Omaha #3836 - initial commit of the groovy-based developer deployment.
Please refer to the: build/deploy.edex/ReadMe.txt amend: remove files that are not used by the developer deployment Change-Id: I7caaf61e88d315ea0d065d46036d3ba9530c29ec Former-commit-id:5b7f86d9d4
[formerly d881ba5d55c41647e5b3c4dfecd7ea89ad7ec2eb] Former-commit-id:c963a90ce0
This commit is contained in:
parent
c4d27803cc
commit
dc5cae7ea1
20 changed files with 1732 additions and 0 deletions
11
build/build.core/.project
Normal file
11
build/build.core/.project
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>build.core</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
108
build/build.core/Feature.groovy
Normal file
108
build/build.core/Feature.groovy
Normal file
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* POJO-based representation of the contents of an Eclipse feature file.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
class Feature
|
||||
{
|
||||
private String feature
|
||||
private String featureDirectory
|
||||
/*
|
||||
* The first iteration of the build will assume that when includes
|
||||
* are present, there will not be any plugins or dependencies
|
||||
* because we will be working with the product feature
|
||||
*/
|
||||
private List includesList
|
||||
private List dependenciesList
|
||||
private List pluginsList
|
||||
|
||||
public Feature(String feature, String featureDirectory)
|
||||
{
|
||||
this.feature = feature
|
||||
this.featureDirectory = featureDirectory
|
||||
this.includesList = []
|
||||
this.dependenciesList = []
|
||||
this.pluginsList = []
|
||||
}
|
||||
|
||||
public String getFeature()
|
||||
{
|
||||
return this.feature
|
||||
}
|
||||
|
||||
public String getFeatureDirectory()
|
||||
{
|
||||
return this.featureDirectory
|
||||
}
|
||||
|
||||
public void addInclude(String includedFeature)
|
||||
{
|
||||
this.includesList.add(includedFeature)
|
||||
}
|
||||
|
||||
public List getIncludes()
|
||||
{
|
||||
return this.includesList
|
||||
}
|
||||
|
||||
public boolean hasIncludes()
|
||||
{
|
||||
return this.includesList.size() > 0
|
||||
}
|
||||
|
||||
public void addDependency(String dependency)
|
||||
{
|
||||
this.dependenciesList.add(dependency)
|
||||
}
|
||||
|
||||
public List getDependencies()
|
||||
{
|
||||
return this.dependenciesList
|
||||
}
|
||||
|
||||
public boolean hasDependencies()
|
||||
{
|
||||
return this.dependenciesList.size() > 0
|
||||
}
|
||||
|
||||
public void addPlugin(String plugin)
|
||||
{
|
||||
this.pluginsList.add(plugin)
|
||||
}
|
||||
|
||||
public List getPlugins()
|
||||
{
|
||||
return this.pluginsList
|
||||
}
|
||||
}
|
52
build/build.core/FeatureParser.groovy
Normal file
52
build/build.core/FeatureParser.groovy
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Parses an Eclipse feature file (feature.xml) and returns a POJO representation
|
||||
* of the contents of the feature file.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class FeatureParser
|
||||
{
|
||||
public static Feature parseFeature(String featureFile, String featureDirectory)
|
||||
{
|
||||
Feature feature = new Feature(featureFile, featureDirectory)
|
||||
|
||||
def featureXML = new XmlSlurper().parse(new File(featureFile))
|
||||
featureXML.includes.each {feature.addInclude(it.attributes().id)}
|
||||
featureXML.requires.import.each {feature.addDependency(it.attributes().feature)}
|
||||
featureXML.plugin.each {feature.addPlugin(it.attributes().id)}
|
||||
|
||||
return feature
|
||||
}
|
||||
}
|
11
build/deploy.edex/.project
Normal file
11
build/deploy.edex/.project
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>deploy.edex</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Abstraction of a customized plugin deployer that provides access
|
||||
* to a pre-configured groovy Ant Builder.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
abstract class AbstractAntBasedPluginCustomDeployer
|
||||
implements IPluginCustomDeployer
|
||||
{
|
||||
protected AntBuilder ant
|
||||
|
||||
protected AbstractAntBasedPluginCustomDeployer()
|
||||
{
|
||||
this.ant = new AntBuilder()
|
||||
// disable ant logging - based on:
|
||||
// http://stackoverflow.com/questions/15143221/enable-verbose-output-from-groovys-antbuilder
|
||||
this.ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
}
|
||||
}
|
72
build/deploy.edex/AbstractExternalPluginFilesDeployer.groovy
Normal file
72
build/deploy.edex/AbstractExternalPluginFilesDeployer.groovy
Normal file
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Abstraction of a customized plugin deployer that deploys
|
||||
* plugin-specific files and directories that exist outside
|
||||
* of the Java src directory. Files are deployed from
|
||||
* the specified externalDirectory in the plugin (if it exists) to the
|
||||
* specified destinationDirectoryTree located beneath the root edex directory.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
abstract class AbstractExternalPluginFilesDeployer
|
||||
extends AbstractAntBasedPluginCustomDeployer {
|
||||
private String externalDirectory
|
||||
private String destinationDirectoryTree
|
||||
|
||||
protected AbstractExternalPluginFilesDeployer(String externalDirectory, String destinationDirectoryTree) {
|
||||
super()
|
||||
this.externalDirectory = externalDirectory
|
||||
this.destinationDirectoryTree = destinationDirectoryTree
|
||||
}
|
||||
|
||||
// Add plugin name if we want to add logging to this capability
|
||||
protected void deployExternalFilesystem(String edexRootDirectory, String pluginFullPath)
|
||||
{
|
||||
String fullPluginExternalPath = pluginFullPath + File.separator + this.externalDirectory
|
||||
// ensure that this plugin has an external directory
|
||||
if (new File(fullPluginExternalPath).exists() == false)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
String fullDestinationPath = edexRootDirectory + File.separator +
|
||||
this.destinationDirectoryTree + File.separator + this.externalDirectory
|
||||
// ensure that the destination directory exists
|
||||
new File(fullDestinationPath).mkdirs()
|
||||
|
||||
// copy the files
|
||||
ant.copy( todir : fullDestinationPath, overwrite : true )
|
||||
{ fileset( dir : fullPluginExternalPath ) }
|
||||
}
|
||||
}
|
61
build/deploy.edex/CustomDeploymentRunner.groovy
Normal file
61
build/deploy.edex/CustomDeploymentRunner.groovy
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Searches for and runs custom plugin-specific groovy scripts named plugin-deploy.groovy
|
||||
* located directly within the plugin directory. The requirement is that the custom
|
||||
* plugin deployments must only deploy files to a location relative to the EDEX root directory.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class CustomDeploymentRunner
|
||||
implements IPluginCustomDeployer {
|
||||
private static final String PLUGIN_GROOVY_SCRIPT = "plugin-deploy.groovy"
|
||||
private static final String BINDING_EDEX_ROOT = "__EDEX_ROOT__"
|
||||
private static final String BINDING_PLUGIN = "__PLUGIN__"
|
||||
private static final String BINDING_PLUGIN_PATH = "__PLUGIN_PATH__"
|
||||
|
||||
public void deploy(String edexRootDirectory, String plugin, String pluginFullPath) {
|
||||
File groovyScript = new File(pluginFullPath + File.separator + PLUGIN_GROOVY_SCRIPT)
|
||||
if (groovyScript.exists() == false) {
|
||||
return
|
||||
}
|
||||
|
||||
Binding binding = new Binding()
|
||||
binding.setVariable(BINDING_EDEX_ROOT, edexRootDirectory)
|
||||
binding.setVariable(BINDING_PLUGIN, plugin)
|
||||
binding.setVariable(BINDING_PLUGIN_PATH, pluginFullPath)
|
||||
|
||||
def groovyShell = new GroovyShell(binding)
|
||||
groovyShell.run(groovyScript)
|
||||
}
|
||||
}
|
120
build/deploy.edex/DeployESB.groovy
Normal file
120
build/deploy.edex/DeployESB.groovy
Normal file
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import groovy.util.logging.*
|
||||
|
||||
/**
|
||||
* Deploys the EDEX esb scripts, libraries, and other files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
@Log
|
||||
class DeployESB
|
||||
{
|
||||
private static final String SETUP_ENV = "setup.env"
|
||||
|
||||
private DeployESB()
|
||||
{
|
||||
}
|
||||
|
||||
public static void deploy(String edexRootDirectory, String esbDirectory, String overrideArchitecture)
|
||||
{
|
||||
if (new File(esbDirectory).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"The specified esb directory does not exist - " + esbDirectory)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
new File(edexRootDirectory).mkdirs()
|
||||
|
||||
// deploy the ESB directory structure.
|
||||
AntBuilder ant = new AntBuilder()
|
||||
ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
|
||||
log.info "Deploying ESB ..."
|
||||
ant.copy( todir : edexRootDirectory,
|
||||
overwrite : true )
|
||||
{
|
||||
fileset( dir : esbDirectory )
|
||||
}
|
||||
|
||||
// remove setup.env
|
||||
new File(edexRootDirectory + File.separator + "bin" + File.separator + SETUP_ENV).delete()
|
||||
// remove lib_illusion
|
||||
new File(edexRootDirectory + File.separator + "lib" + File.separator + "lib_illusion").deleteDir()
|
||||
|
||||
// copy the correct lib_illusion based on architecture
|
||||
// determine architecture?
|
||||
|
||||
// since this is only a temporary consideration since we will eventually be switching to a 64-bit
|
||||
// EDEX, we will just look at the OS architecture since the JDK does not provide a simple way
|
||||
// to retrieve the required information about the JVM process, itself. The -Darchitecture argument
|
||||
// can be used to override the dynamically determined architecture
|
||||
String architecture = overrideArchitecture
|
||||
if (architecture == "")
|
||||
{
|
||||
architecture =
|
||||
(System.getProperty("os.arch") == "amd64") ? "x86_64" : "x86"
|
||||
}
|
||||
String esbLibIllusionPath = esbDirectory + File.separator + "lib" + File.separator +
|
||||
"lib_illusion" + File.separator + architecture
|
||||
if (new File(esbLibIllusionPath).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find the illusion lib associated with architecture - " + architecture)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
String libIllusionDestination = edexRootDirectory + File.separator +
|
||||
"lib" + File.separator + "lib_illusion"
|
||||
new File(libIllusionDestination).mkdirs()
|
||||
ant.copy( todir : libIllusionDestination, overwrite : true )
|
||||
{
|
||||
fileset( dir : esbLibIllusionPath )
|
||||
}
|
||||
}
|
||||
|
||||
public static void deployEdexConfiguration(String edexRootDirectory, String esbDirectory)
|
||||
{
|
||||
final String setupEnvSrc = esbDirectory + File.separator + "bin" + File.separator + SETUP_ENV
|
||||
final String destinationDirectory = edexRootDirectory + File.separator + "bin"
|
||||
|
||||
AntBuilder ant = new AntBuilder()
|
||||
ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
|
||||
ant.copy( todir : destinationDirectory,
|
||||
overwrite : true )
|
||||
{
|
||||
fileset( file : setupEnvSrc )
|
||||
}
|
||||
}
|
||||
}
|
53
build/deploy.edex/DeployEdexLocalization.groovy
Normal file
53
build/deploy.edex/DeployEdexLocalization.groovy
Normal file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Deploys plugin-provided localization files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class DeployEdexLocalization
|
||||
extends AbstractExternalPluginFilesDeployer
|
||||
{
|
||||
private static final String destinationDirectory = "utility"
|
||||
private static final String destinationDirectoryTree = "data"
|
||||
|
||||
public DeployEdexLocalization()
|
||||
{
|
||||
super(destinationDirectory, destinationDirectoryTree)
|
||||
}
|
||||
|
||||
public void deploy(String edexRootDirectory, String plugin, String pluginFullPath)
|
||||
{
|
||||
super.deployExternalFilesystem(edexRootDirectory, pluginFullPath)
|
||||
}
|
||||
}
|
53
build/deploy.edex/DeployEdexResources.groovy
Normal file
53
build/deploy.edex/DeployEdexResources.groovy
Normal file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Deploys plugin-provided resource (properties) files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class DeployEdexResources
|
||||
extends AbstractExternalPluginFilesDeployer
|
||||
{
|
||||
private static final String destinationDirectory = "resources"
|
||||
private static final String destinationDirectoryTree = "conf"
|
||||
|
||||
public DeployEdexResources()
|
||||
{
|
||||
super(destinationDirectory, destinationDirectoryTree)
|
||||
}
|
||||
|
||||
public void deploy(String edexRootDirectory, String plugin, String pluginFullPath)
|
||||
{
|
||||
super.deployExternalFilesystem(edexRootDirectory, pluginFullPath)
|
||||
}
|
||||
}
|
73
build/deploy.edex/DeployEdexSiteLocalization.groovy
Normal file
73
build/deploy.edex/DeployEdexSiteLocalization.groovy
Normal file
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import groovy.util.logging.*
|
||||
import ProjectInformation
|
||||
|
||||
/**
|
||||
* Deploys the sample EDEX localization files when requested.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Log
|
||||
class DeployEdexSiteLocalization
|
||||
{
|
||||
private static final String EDEX_LOCALIZATION_DIRECTORY = "data" + File.separator +
|
||||
"utility"
|
||||
|
||||
private DeployEdexSiteLocalization()
|
||||
{
|
||||
}
|
||||
|
||||
public static void deploy(String edexRootDirectory, ProjectInformation projectInformation, String site)
|
||||
{
|
||||
if (projectInformation == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.WARNING,
|
||||
"Unable to find the localization project associated with site " + site +
|
||||
"; skipping localization deployment")
|
||||
return
|
||||
}
|
||||
|
||||
String localizationDestination = edexRootDirectory + File.separator + EDEX_LOCALIZATION_DIRECTORY
|
||||
new File(localizationDestination).mkdirs()
|
||||
|
||||
AntBuilder ant = new AntBuilder()
|
||||
ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
|
||||
log.info "Deploying localization for site ... " + site
|
||||
ant.copy( todir : localizationDestination, overwrite : true )
|
||||
{
|
||||
fileset( dir : projectInformation.projectFullLocation + File.separator + "utility" )
|
||||
}
|
||||
}
|
||||
}
|
55
build/deploy.edex/DeployModes.groovy
Normal file
55
build/deploy.edex/DeployModes.groovy
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Deploys plugin-provided EDEX mode files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class DeployModes
|
||||
extends AbstractExternalPluginFilesDeployer
|
||||
{
|
||||
private static final String destinationDirectory = 'modes'
|
||||
private static final String destinationDirectoryTree = 'conf'
|
||||
|
||||
public DeployModes()
|
||||
{
|
||||
super(destinationDirectory, destinationDirectoryTree)
|
||||
}
|
||||
|
||||
public void deploy(String edexRootDirectory, String plugin, String pluginFullPath)
|
||||
{
|
||||
super.deployExternalFilesystem(edexRootDirectory, pluginFullPath)
|
||||
}
|
||||
}
|
118
build/deploy.edex/DeployPythonPackages.groovy
Normal file
118
build/deploy.edex/DeployPythonPackages.groovy
Normal file
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import groovy.util.logging.*
|
||||
import java.util.regex.Pattern
|
||||
import java.util.regex.Matcher
|
||||
import ProjectInformation
|
||||
|
||||
/**
|
||||
* Deploys the Raytheon-maintained Python Packages when requested.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Log
|
||||
class DeployPythonPackages {
|
||||
private static final String PYTHON_VERSION_PATTERN_STRING = "python([0-9].+)"
|
||||
private static final Pattern pythonVersionPattern =
|
||||
Pattern.compile(PYTHON_VERSION_PATTERN_STRING)
|
||||
|
||||
private DeployPythonPackages() {
|
||||
}
|
||||
|
||||
public static deploy(String pythonRootDirectory, ProjectInformation projectInformation,
|
||||
String[] pythonPackagesToDeploy) {
|
||||
if (projectInformation == null) {
|
||||
log.log(java.util.logging.Level.WARNING,
|
||||
"Unable to find pythonPackages in the workspace; skipping python deployment")
|
||||
return
|
||||
}
|
||||
if (pythonPackagesToDeploy.length == 0) {
|
||||
log.info "No python packages have been specified for deployment; skipping python deployment."
|
||||
return
|
||||
}
|
||||
|
||||
// determine what the python version directory is
|
||||
// loop through all directories in the python lib directory; attempt to find
|
||||
// the one that matches our pattern
|
||||
final String pythonLibDirectory = pythonRootDirectory + File.separator + "lib"
|
||||
String pythonVersion = null
|
||||
for (String libFile : new File(pythonLibDirectory).list())
|
||||
{
|
||||
Matcher matcher = pythonVersionPattern.matcher(libFile)
|
||||
if (matcher.matches())
|
||||
{
|
||||
pythonVersion = matcher.group(1)
|
||||
}
|
||||
}
|
||||
|
||||
if (pythonVersion == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find the python version directory in " + pythonLibDirectory)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
AntBuilder ant = new AntBuilder()
|
||||
ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
|
||||
log.info "Deploying pythonPackages ..."
|
||||
final String pythonSitePackagesDirectory = pythonLibDirectory + File.separator +
|
||||
"python" + pythonVersion + File.separator + "site-packages"
|
||||
for (String pythonPackage : pythonPackagesToDeploy)
|
||||
{
|
||||
String pythonPackageDirectory = projectInformation.projectFullLocation + File.separator + pythonPackage
|
||||
if (pythonPackage == "pypies")
|
||||
{
|
||||
// special case for pypies
|
||||
pythonPackageDirectory += File.separator + "pypies"
|
||||
}
|
||||
if (new File(pythonPackageDirectory).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.WARNING,
|
||||
"Unable to find the " + pythonPackage + " python package in the workspace")
|
||||
continue
|
||||
}
|
||||
|
||||
String pythonPackageDestination = pythonSitePackagesDirectory + File.separator +
|
||||
pythonPackage
|
||||
log.info "Deploying pythonPackage ... " + pythonPackage
|
||||
|
||||
// Remove the existing deployment
|
||||
new File(pythonPackageDestination).deleteDir()
|
||||
// Create an empty destination directory
|
||||
new File(pythonPackageDestination).mkdirs()
|
||||
ant.copy( todir : pythonPackageDestination )
|
||||
{ fileset( dir : pythonPackageDirectory ) }
|
||||
}
|
||||
}
|
||||
}
|
119
build/deploy.edex/DeployWeb.groovy
Normal file
119
build/deploy.edex/DeployWeb.groovy
Normal file
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import groovy.util.logging.*
|
||||
|
||||
import IPluginCustomDeployer
|
||||
|
||||
/**
|
||||
* Deploys plugin-provided web applications as war files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Log
|
||||
class DeployWeb
|
||||
extends AbstractAntBasedPluginCustomDeployer
|
||||
{
|
||||
private final String WEB_XML_PATH = "web" + File.separator + "WEB-INF" + File.separator + "web.xml"
|
||||
|
||||
public DeployWeb()
|
||||
{
|
||||
super()
|
||||
}
|
||||
|
||||
public void deploy(String edexRootDirectory, String plugin, String pluginFullPath)
|
||||
{
|
||||
final String edexWebappsDirectory = edexRootDirectory + File.separator + "webapps"
|
||||
|
||||
// determine if the plugin encapsulates a web application
|
||||
final String expectedWebXMLPath = pluginFullPath + File.separator + WEB_XML_PATH
|
||||
if (new File(expectedWebXMLPath).exists() == false)
|
||||
{
|
||||
// no web application
|
||||
return
|
||||
}
|
||||
|
||||
String webAppRootKey = this.getWebAppRootKey(expectedWebXMLPath)
|
||||
if (webAppRootKey == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.WARNING,
|
||||
"webAppRootKey not specified in web.xml for plugin - " + plugin + "; skipping web app deployment")
|
||||
return
|
||||
}
|
||||
log.info "Deploying Web Application associated with plugin ... " + plugin
|
||||
|
||||
final String warFile = edexWebappsDirectory + File.separator + webAppRootKey + ".war"
|
||||
final String unwarDirectory = edexWebappsDirectory + File.separator + webAppRootKey
|
||||
this.cleanup(edexWebappsDirectory, warFile, unwarDirectory)
|
||||
|
||||
// produce the war file
|
||||
this.ant.war( destfile : warFile,
|
||||
webxml : expectedWebXMLPath )
|
||||
{
|
||||
fileset( dir : pluginFullPath + File.separator + "web",
|
||||
excludes : "WEB-INF" + File.separator )
|
||||
classes( dir : pluginFullPath + File.separator + "web" + File.separator +
|
||||
"WEB-INF" + File.separator + "classes" )
|
||||
webinf ( file : pluginFullPath + File.separator + "web" + File.separator +
|
||||
"WEB-INF" + File.separator + "dwr.xml" )
|
||||
}
|
||||
|
||||
// finally, unwar the war file
|
||||
this.ant.unzip( src : warFile,
|
||||
dest : unwarDirectory )
|
||||
new File(warFile).delete()
|
||||
}
|
||||
|
||||
private String getWebAppRootKey(String webXMLFile)
|
||||
{
|
||||
String webAppRootKey = null
|
||||
def webXML = new XmlSlurper().parse(new File(webXMLFile))
|
||||
|
||||
webXML.'context-param'.each
|
||||
{
|
||||
String paramName = it.'param-name'.toString()
|
||||
if (paramName == "webAppRootKey")
|
||||
{
|
||||
webAppRootKey = it.'param-value'.toString()
|
||||
}
|
||||
}
|
||||
|
||||
return webAppRootKey
|
||||
}
|
||||
|
||||
private void cleanup(String edexWebappsDirectory, String warFile, String webAppDirectory)
|
||||
{
|
||||
// cleanup any previous deployments
|
||||
new File(warFile).delete()
|
||||
new File(webAppDirectory).deleteDir()
|
||||
}
|
||||
}
|
42
build/deploy.edex/IPluginCustomDeployer.groovy
Normal file
42
build/deploy.edex/IPluginCustomDeployer.groovy
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Defines a customized plugin deployer. Customized Plugin deployers are
|
||||
* used to deploy additional plugin-specific files that exist outside
|
||||
* of a standard Java build.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
interface IPluginCustomDeployer {
|
||||
void deploy(String edexRootDirectory, String plugin, String pluginFullPath)
|
||||
}
|
54
build/deploy.edex/ProjectInformation.groovy
Normal file
54
build/deploy.edex/ProjectInformation.groovy
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
/**
|
||||
* POJO representation of projects discovered in the Eclipse workspace.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
class ProjectInformation
|
||||
{
|
||||
// the name of the project as it is known to Eclipse
|
||||
public String project
|
||||
// the name of the project directory
|
||||
// in most cases (not all) this will be the same as the project name
|
||||
public String projectDirectory
|
||||
// the full path to the plugin
|
||||
public String projectFullLocation
|
||||
|
||||
public ProjectInformation()
|
||||
{
|
||||
this.project = null
|
||||
this.projectDirectory = null
|
||||
this.projectFullLocation = null
|
||||
}
|
||||
}
|
15
build/deploy.edex/ReadMe.txt
Normal file
15
build/deploy.edex/ReadMe.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Run deploy-install.xml to execute the new groovy-based deployment mechanism.
|
||||
The mechanism will need to remain ant-wrapped until the Groovy plugins are added
|
||||
to the uframe Eclipse distribution.
|
||||
|
||||
One argument is required to run the script: -Dworkspace_loc=${workspace_loc}
|
||||
|
||||
Note: ENTER THE ARGUMENT EXACTLY AS IT IS WRITTEN ABOVE. ${workspace_loc} is
|
||||
an Eclipse variable that references the actual location of the workspace.
|
||||
|
||||
deploy-install will deploy any EDEX features it finds in the workspace excluding:
|
||||
com.raytheon.edex.wa.feature and com.raytheon.edex.feature.uframe
|
||||
|
||||
Currently, an EDEX feature is defined as a feature project that includes edex in
|
||||
the name. Feature deployment options will most likely be more customizable when
|
||||
the pure groovy version of this deployment can be used.
|
563
build/deploy.edex/RunDeployInstall.groovy
Normal file
563
build/deploy.edex/RunDeployInstall.groovy
Normal file
|
@ -0,0 +1,563 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
|
||||
import groovy.util.logging.*
|
||||
import ProjectInformation
|
||||
import Feature
|
||||
import FeatureParser
|
||||
import java.util.Properties
|
||||
import java.util.List
|
||||
import java.util.ArrayList
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
import DeployESB
|
||||
import DeployPythonPackages
|
||||
import DeployEdexSiteLocalization
|
||||
import IPluginCustomDeployer
|
||||
|
||||
/**
|
||||
* Initial version of the deploy-install driver. Temporarily
|
||||
* wrapped by and executed by an ant script until the Groovy
|
||||
* plugins become a standard part of the uframe Eclipse distribution.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 4, 2014 3836 bkowal Initial Commit
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bkowal
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Log
|
||||
class DeployInstall
|
||||
{
|
||||
private static final String edexFeatureRegex = '^.*\\.edex\\..*\\.feature$'
|
||||
|
||||
private static final Pattern EDEX_FEATURE_PATTERN =
|
||||
Pattern.compile(edexFeatureRegex)
|
||||
|
||||
// temporarily have to declare and add this feature to the list of deployed features
|
||||
// manually. there are improvements that can be made in 15.1.
|
||||
private static final String COMMON_BASE_FEATURE = "com.raytheon.uf.common.base.feature"
|
||||
|
||||
// temporary. maintain backwards compatibility until baseline cleanup
|
||||
private final List<String> blacklistedEdexFeatures
|
||||
|
||||
private projectInformationMap = [:]
|
||||
private List<String> edexFeaturesToDeploy
|
||||
private String edexRootDirectory
|
||||
private String[] localizationSitesToDeploy = []
|
||||
private boolean deployPythonPackages
|
||||
private String pythonRootDirectory
|
||||
private String[] pythonPackagesToDeploy = []
|
||||
private String architecture
|
||||
private List<IPluginCustomDeployer> customPluginDeployers
|
||||
|
||||
// a list of features that have been deployed to ensure that a feature is not deployed
|
||||
// more than once.
|
||||
private List featuresDeployed = []
|
||||
// a list of the plugins that we will be deploying.
|
||||
private List pluginsToDeploy = []
|
||||
// used to track which feature a plugin was discovered in; will be used to
|
||||
// verify that a plugin is not listed in more than one feature.
|
||||
private pluginToFeatureMap = [:]
|
||||
|
||||
public DeployInstall(final String workspaceDirectory,
|
||||
final String localizationSites, final boolean deployPythonPackages,
|
||||
final String edexRootDirectory, final String pythonRootDirectory, final String pythonPackages,
|
||||
final String architecture)
|
||||
{
|
||||
blacklistedEdexFeatures = new ArrayList<String>()
|
||||
// never deploy these features
|
||||
blacklistedEdexFeatures.add("com.raytheon.edex.wa.feature")
|
||||
blacklistedEdexFeatures.add("com.raytheon.edex.feature.uframe")
|
||||
|
||||
this.init(workspaceDirectory.trim())
|
||||
if (localizationSites.trim() != "")
|
||||
{
|
||||
this.localizationSitesToDeploy = localizationSites.trim().split(":")
|
||||
}
|
||||
this.deployPythonPackages = deployPythonPackages
|
||||
this.edexRootDirectory = edexRootDirectory.trim()
|
||||
this.pythonRootDirectory = pythonRootDirectory.trim()
|
||||
if (pythonPackages.trim() != "")
|
||||
{
|
||||
this.pythonPackagesToDeploy = pythonPackages.trim().split(":")
|
||||
}
|
||||
this.architecture = architecture.trim()
|
||||
}
|
||||
|
||||
public void deploy()
|
||||
{
|
||||
// recursively build the list of plugins that will be deployed.
|
||||
for (String featureToDeploy : edexFeaturesToDeploy)
|
||||
{
|
||||
this.buildPluginList(featureToDeploy)
|
||||
}
|
||||
log.info "Found " + this.pluginsToDeploy.size() + " Plugins To Deploy."
|
||||
this.cleanup()
|
||||
this.deployPlugins()
|
||||
|
||||
// complete the esb deployment
|
||||
|
||||
// we need to determine the location of the build.edex project
|
||||
ProjectInformation projectInformation = this.projectInformationMap["build.edex"]
|
||||
if (projectInformation == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find project - build.edex")
|
||||
System.exit(-1)
|
||||
}
|
||||
final String esbDirectory = projectInformation.projectFullLocation + File.separator + "esb"
|
||||
|
||||
DeployESB.deploy(this.edexRootDirectory, esbDirectory, this.architecture)
|
||||
DeployESB.deployEdexConfiguration(this.edexRootDirectory, esbDirectory)
|
||||
if (this.deployPythonPackages)
|
||||
{
|
||||
DeployPythonPackages.deploy(this.pythonRootDirectory,
|
||||
this.projectInformationMap["pythonPackages"], this.pythonPackagesToDeploy)
|
||||
}
|
||||
if (this.localizationSitesToDeploy.length > 0)
|
||||
{
|
||||
for (String localizationSite : this.localizationSitesToDeploy)
|
||||
{
|
||||
String localizationProject = "localization." + localizationSite
|
||||
DeployEdexSiteLocalization.deploy(this.edexRootDirectory,
|
||||
this.projectInformationMap[localizationProject], localizationSite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the existing deployment
|
||||
private void cleanup()
|
||||
{
|
||||
// remove the contents of the edex lib directory (execluding native)
|
||||
log.info "Cleaning EDEX lib directory ..."
|
||||
final String EDEX_LIB_DIRECTORY = this.edexRootDirectory + File.separator + "lib"
|
||||
for (File file : new File(EDEX_LIB_DIRECTORY).listFiles())
|
||||
{
|
||||
if (file.getName() == "native")
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
file.deleteDir()
|
||||
}
|
||||
|
||||
// remove the shell scripts and the yajsw sub-directory from the edex bin directory
|
||||
log.info "Cleaning EDEX bin directory ..."
|
||||
final String EDEX_BIN_DIRECTORY = this.edexRootDirectory + File.separator + "bin"
|
||||
for (File file : new File(EDEX_BIN_DIRECTORY).listFiles())
|
||||
{
|
||||
if (file.getName() == "yajsw")
|
||||
{
|
||||
file.deleteDir()
|
||||
}
|
||||
|
||||
// we really should be checking the file extension here instead of just doing a
|
||||
// basic String comparison
|
||||
if (file.getName().endsWith(".sh") || file.getName() == "setup.env")
|
||||
{
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
|
||||
// remove the contents of the edex conf directory
|
||||
log.info "Cleaning EDEX conf directory ..."
|
||||
final String EDEX_CONF_DIRECTORY = this.edexRootDirectory + File.separator + "conf"
|
||||
for (File file : new File(EDEX_CONF_DIRECTORY).listFiles())
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
file.deleteDir()
|
||||
}
|
||||
else
|
||||
{
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deployPlugins()
|
||||
{
|
||||
// we will need ant to complete this
|
||||
AntBuilder ant = new AntBuilder()
|
||||
ant.project.getBuildListeners().firstElement().setMessageOutputLevel(0)
|
||||
|
||||
log.info "Deploying plugins ..."
|
||||
for (String plugin : this.pluginsToDeploy)
|
||||
{
|
||||
this.deployPlugin(plugin, ant)
|
||||
}
|
||||
}
|
||||
|
||||
// FOSS plugins are plugins that include jar files.
|
||||
private boolean isFOSSPlugin(ProjectInformation projectInformation)
|
||||
{
|
||||
final String jarSuffix = ".jar"
|
||||
// loop through the files in the plugin directory; true if a single
|
||||
// jar file is found.
|
||||
for (String pluginFile : new File(projectInformation.projectFullLocation).listFiles())
|
||||
{
|
||||
if (pluginFile.endsWith(".jar"))
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private void deployPlugin(String plugin, AntBuilder ant)
|
||||
{
|
||||
// first, attempt to find the plugin in the plugin map
|
||||
ProjectInformation projectInformation = this.projectInformationMap[plugin]
|
||||
if (projectInformation == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find plugin - " + plugin)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
// next, attempt to access the build.properties file for the plugin
|
||||
final String PLUGIN_BUILD_PROPERTIES = projectInformation.projectFullLocation + File.separator +
|
||||
"build.properties"
|
||||
if (new File(PLUGIN_BUILD_PROPERTIES).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find the build.properties file for plugin - " + plugin)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
log.info "Deploying plugin ... " + plugin
|
||||
|
||||
// read the plugin build.properties file
|
||||
BufferedReader br =
|
||||
new BufferedReader(new FileReader(PLUGIN_BUILD_PROPERTIES))
|
||||
Properties properties = new Properties()
|
||||
properties.load(br)
|
||||
|
||||
final String output = properties.getProperty("output..")
|
||||
final String binIncludes = properties.getProperty("bin.includes")
|
||||
|
||||
if (output == null)
|
||||
{
|
||||
// we will not be producing a jar file and are most likely deploying a FOSS plugin
|
||||
this.deployFOSSPlugin(projectInformation, binIncludes, ant)
|
||||
return
|
||||
}
|
||||
|
||||
// jar the plugin
|
||||
final String pluginJarName = plugin + ".jar"
|
||||
final String edexLibPlugins = this.edexRootDirectory + File.separator + "lib" + File.separator +
|
||||
"plugins"
|
||||
new File(edexLibPlugins).mkdirs()
|
||||
final String fullJarPath = edexLibPlugins + File.separator + pluginJarName
|
||||
|
||||
ant.jar( destfile : fullJarPath,
|
||||
manifest : projectInformation.projectFullLocation + File.separator + "META-INF" +
|
||||
File.separator + "MANIFEST.MF" )
|
||||
{
|
||||
fileset( dir : projectInformation.projectFullLocation + File.separator + output )
|
||||
}
|
||||
|
||||
// is the plugin FOSS?
|
||||
if (this.isFOSSPlugin(projectInformation))
|
||||
{
|
||||
this.deployFOSSPlugin(projectInformation, binIncludes, ant)
|
||||
return
|
||||
}
|
||||
|
||||
// finish the plugin based on build.properties
|
||||
for (String binInclude : binIncludes.split(","))
|
||||
{
|
||||
binInclude = binInclude.trim()
|
||||
if (binInclude == ".")
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// ensure that the artifact exists
|
||||
final String artifact = projectInformation.projectFullLocation + File.separator + binInclude
|
||||
if (new File(artifact).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
artifact + " specified in build.properties for plugin " + projectInformation.project + " was not found")
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
// add the artifact to the jar
|
||||
if (new File(artifact).isDirectory())
|
||||
{
|
||||
ant.jar( destfile : fullJarPath,
|
||||
update : true )
|
||||
{
|
||||
fileset( dir : projectInformation.projectFullLocation,
|
||||
includes : binInclude )
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ant.jar( destfile : fullJarPath,
|
||||
update : true )
|
||||
{
|
||||
fileset( file : artifact )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run "custom" deployment steps
|
||||
for (IPluginCustomDeployer pluginCustomDeployer : this.customPluginDeployers)
|
||||
{
|
||||
pluginCustomDeployer.deploy(this.edexRootDirectory, projectInformation.project,
|
||||
projectInformation.projectFullLocation)
|
||||
}
|
||||
}
|
||||
|
||||
private void deployFOSSPlugin(ProjectInformation projectInformation, String binIncludes, AntBuilder ant)
|
||||
{
|
||||
final String edexLibDependencies = this.edexRootDirectory + File.separator + "lib" + File.separator +
|
||||
"dependencies" + File.separator + projectInformation.project
|
||||
// create the destination directory
|
||||
new File(edexLibDependencies).mkdirs()
|
||||
|
||||
for (String binInclude : binIncludes.split(","))
|
||||
{
|
||||
binInclude = binInclude.trim()
|
||||
if (binInclude == ".")
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// ensure that the artifact exists
|
||||
final String artifact = projectInformation.projectFullLocation + File.separator + binInclude
|
||||
if (new File(artifact).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
artifact + " specified in build.properties for plugin " + projectInformation.project + " was not found")
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
if (new File(artifact).isDirectory())
|
||||
{
|
||||
ant.copy( todir : edexLibDependencies )
|
||||
{
|
||||
fileset( dir : artifact )
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ant.copy( todir : edexLibDependencies, file : artifact )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildPluginList(String featureName)
|
||||
{
|
||||
if (this.featuresDeployed.contains(featureName))
|
||||
{
|
||||
log.log(java.util.logging.Level.WARNING,
|
||||
"Feature " + featureName + " has been included more than once; skipping the duplicate.")
|
||||
return
|
||||
}
|
||||
log.info "Analyzing feature ... " + featureName
|
||||
|
||||
// first, attempt to find the feature in the project map
|
||||
ProjectInformation projectInformation = this.projectInformationMap[featureName]
|
||||
// verify that the feature exists
|
||||
if (projectInformation == null)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find the specified feature - " + featureName)
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
final String featureFullPath = projectInformation.projectFullLocation + File.separator + "feature.xml"
|
||||
// verify that the feature exists
|
||||
if (new File(featureFullPath).exists() == false)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Unable to find the specified feature - " + featureName + "; '" + featureFullPath + "' does not exist")
|
||||
System.exit(-1)
|
||||
}
|
||||
|
||||
Feature feature = FeatureParser.parseFeature(featureFullPath, featureName)
|
||||
// first, process any features that the feature includes
|
||||
for (String featureInclude : feature.getIncludes())
|
||||
{
|
||||
this.buildPluginList(featureInclude)
|
||||
}
|
||||
|
||||
// should we also check dependencies?
|
||||
|
||||
// complete an initial analysis of the plugins that we will be deploying
|
||||
for (String plugin : feature.getPlugins())
|
||||
{
|
||||
final String featureWithPlugin = this.pluginToFeatureMap[plugin]
|
||||
if (featureWithPlugin == null)
|
||||
{
|
||||
// we have not seen this plugin yet
|
||||
this.pluginToFeatureMap[plugin] = featureName
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have seen this plugin before, verify that the plugin
|
||||
// is not in more than one feature
|
||||
if (featureWithPlugin != featureName)
|
||||
{
|
||||
log.log(java.util.logging.Level.SEVERE,
|
||||
"Plugin is listed in more than one feature - " + featureWithPlugin + " AND " + featureName)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pluginsToDeploy.contains(plugin) == false)
|
||||
{
|
||||
this.pluginsToDeploy.add(plugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init(final String workspaceDirectory)
|
||||
{
|
||||
this.edexFeaturesToDeploy = new ArrayList<String>()
|
||||
final String metadataProjectsDirectory = workspaceDirectory + File.separator +
|
||||
".metadata" + File.separator + ".plugins" + File.separator + "org.eclipse.core.resources" +
|
||||
File.separator + ".projects"
|
||||
|
||||
for (String project : new File(metadataProjectsDirectory).list())
|
||||
{
|
||||
// determine if the project is an EDEX feature.
|
||||
Matcher matcher = EDEX_FEATURE_PATTERN.matcher(project)
|
||||
if (matcher.matches() || project == COMMON_BASE_FEATURE)
|
||||
{
|
||||
// this is an EDEX feature.
|
||||
if (blacklistedEdexFeatures.contains(project) == false)
|
||||
{
|
||||
this.edexFeaturesToDeploy.add(project)
|
||||
log.log(java.util.logging.Level.INFO, 'Found EDEX Feature: ' + project)
|
||||
}
|
||||
}
|
||||
|
||||
final String expectedLocationFile = metadataProjectsDirectory +
|
||||
File.separator + project + File.separator + ".location"
|
||||
if (new File(expectedLocationFile).exists())
|
||||
{
|
||||
this.catalogProject(expectedLocationFile)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* previously this was dynamically loaded via spring. However, spring
|
||||
* was removed from groovy.
|
||||
*/
|
||||
this.customPluginDeployers = new ArrayList<IPluginCustomDeployer>()
|
||||
this.customPluginDeployers.add(new DeployWeb())
|
||||
this.customPluginDeployers.add(new DeployEdexLocalization())
|
||||
this.customPluginDeployers.add(new DeployEdexResources())
|
||||
this.customPluginDeployers.add(new CustomDeploymentRunner())
|
||||
this.customPluginDeployers.add(new DeployModes())
|
||||
}
|
||||
|
||||
private void catalogProject(String locationFile)
|
||||
{
|
||||
byte[] contents = new File(locationFile).getBytes()
|
||||
final String FILE_ = "file:"
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder()
|
||||
boolean buildLocationString = false
|
||||
|
||||
for (int i = 0; i < contents.length; i++)
|
||||
{
|
||||
if (contents[i] < 0 || contents[i] > 127)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (buildLocationString)
|
||||
{
|
||||
if (contents[i] == 0)
|
||||
{
|
||||
// the end of the file path (ideally).
|
||||
break
|
||||
}
|
||||
char c = (char) contents[i]
|
||||
stringBuilder.append(c)
|
||||
}
|
||||
else
|
||||
{
|
||||
// first: we want to find the letter 'f'
|
||||
char c = (char) contents[i]
|
||||
if ( c == 'f')
|
||||
{
|
||||
stringBuilder.append(c)
|
||||
// we have found 'f'; determine if we have found "file:"
|
||||
int counter = 0
|
||||
while (counter < 4)
|
||||
{
|
||||
++i
|
||||
c = (char) contents[i]
|
||||
stringBuilder.append(c)
|
||||
++counter
|
||||
}
|
||||
|
||||
if (FILE_ == stringBuilder.toString())
|
||||
{
|
||||
buildLocationString = true
|
||||
}
|
||||
|
||||
stringBuilder = new StringBuilder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String projectLocationString = stringBuilder.toString()
|
||||
// get the .project file
|
||||
File projectMetadataFile =
|
||||
new File(projectLocationString + File.separator + ".project")
|
||||
// ensure that the project metadata file actually exists
|
||||
if (projectMetadataFile.exists() == false)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
// read the file
|
||||
def projectMetadataXML = new XmlSlurper().parse(projectMetadataFile)
|
||||
// extract the plugin name (as Eclipse sees it)
|
||||
final String projectName = projectMetadataXML.name
|
||||
|
||||
ProjectInformation projectInformation = new ProjectInformation()
|
||||
projectInformation.project = projectName
|
||||
projectInformation.projectDirectory = new File(projectLocationString).getName()
|
||||
projectInformation.projectFullLocation = projectLocationString
|
||||
|
||||
this.projectInformationMap[projectName] = projectInformation
|
||||
}
|
||||
}
|
||||
|
||||
DeployInstall deployInstall =
|
||||
new DeployInstall(args[0], args[1], Boolean.parseBoolean(args[2]),
|
||||
args[3], args[4], args[5], args[6])
|
||||
deployInstall.deploy()
|
79
build/deploy.edex/deploy-install.xml
Normal file
79
build/deploy.edex/deploy-install.xml
Normal file
|
@ -0,0 +1,79 @@
|
|||
<project default="main" basedir=".">
|
||||
<property name="localization.sites" value="" />
|
||||
<property name="deploy.python" value="true" />
|
||||
<!--
|
||||
The python packages to deploy - provided that
|
||||
deploy.python is true
|
||||
-->
|
||||
<property name="python.packages"
|
||||
value="pypies:ufpy:dynamicserialize" />
|
||||
<!-- EDEX root directory - defaults to /awips2/edex -->
|
||||
<property name="edex.root" value="/awips2/edex" />
|
||||
<!-- Python root directory - defaults to /awips2/python -->
|
||||
<property name="python.root" value="/awips2/python" />
|
||||
<!--
|
||||
if groovy.path is not manually set, groovy must be
|
||||
on the PATH.
|
||||
-->
|
||||
<property name="groovy.path" value="" />
|
||||
<property name="architecture" value="x86_64" />
|
||||
|
||||
<condition property="requiredPropertiesSet">
|
||||
<and>
|
||||
<isset property="workspace_loc" />
|
||||
</and>
|
||||
</condition>
|
||||
|
||||
<available property="groovyPathSet"
|
||||
file="${groovy.path}/groovy" type="file" />
|
||||
|
||||
<target name="main">
|
||||
<antcall target="usage" />
|
||||
<antcall target="deploy-using-specific-groovy" />
|
||||
<antcall target="deploy-using-environment-groovy" />
|
||||
</target>
|
||||
|
||||
<target name="usage" unless="${requiredPropertiesSet}">
|
||||
<echo message="Usage: the following parameters are available when running deploy-install.xml." />
|
||||
<echo message="REQUIRED PARAMETERS:" />
|
||||
<echo message=" -Dworkspace_loc the location of the Eclipse workspace; use the 'workspace_loc' variable provided by Eclipse" />
|
||||
<echo message="OPTIONAL PARAMETERS:" />
|
||||
<echo message=" -Dlocalization.sites a colon delimited list of sites to deploy localization for" />
|
||||
<echo message=" -Dedex.root the root of the EDEX installation; defaults to /awips2/edex" />
|
||||
<echo message=" -Ddeploy.python a boolean value {true, false} indicating if python should be deployed" />
|
||||
<echo message=" -Dpython.root the root of the python installation; defaults to /awips2/python" />
|
||||
<echo message=" -Dpython.packages a colon delimited list of python packages to deploy; defaults to pypies:ufpy:dynamicserialize" />
|
||||
<echo message=" -Darchitecture used to override the deployment architecture; use one of: {x86_64, x86}." />
|
||||
|
||||
<fail message="All required parameters have not been specified. Refer to the usage message above." />
|
||||
</target>
|
||||
|
||||
<target name="deploy-using-specific-groovy" if="${groovyPathSet}">
|
||||
<deploy
|
||||
groovy.executable="${groovy.path}/groovy" />
|
||||
</target>
|
||||
|
||||
<target name="deploy-using-environment-groovy" unless="${groovyPathSet}">
|
||||
<deploy
|
||||
groovy.executable="groovy" />
|
||||
</target>
|
||||
|
||||
<macrodef name="deploy">
|
||||
<attribute name="groovy.executable" />
|
||||
|
||||
<sequential>
|
||||
<exec executable="@{groovy.executable}">
|
||||
<arg value="-cp" />
|
||||
<arg value="${basedir}${path.separator}${basedir}/../build.core" />
|
||||
<arg value="${basedir}/RunDeployInstall.groovy" />
|
||||
<arg value="${workspace_loc}" />
|
||||
<arg value="${localization.sites}" />
|
||||
<arg value="${deploy.python}" />
|
||||
<arg value="${edex.root}" />
|
||||
<arg value="${python.root}" />
|
||||
<arg value="${python.packages}" />
|
||||
<arg value="${architecture}" />
|
||||
</exec>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</project>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="customPluginDeployersList" class="java.util.ArrayList">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref bean="customLocalizationDeploy" />
|
||||
<ref bean="customResourcesDeploy" />
|
||||
<ref bean="customWebDeploy" />
|
||||
<ref bean="customDeploymentRunner" />
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="customWebDeploy" class="DeployWeb" />
|
||||
<bean id="customLocalizationDeploy" class="DeployEdexLocalization" />
|
||||
<bean id="customResourcesDeploy" class="DeployEdexResources" />
|
||||
<bean id="customDeploymentRunner" class="CustomDeploymentRunner" />
|
||||
</beans>
|
Loading…
Add table
Reference in a new issue