summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Wouters2014-07-03 04:08:59 (EDT)
committerLaurent Wouters2014-07-03 04:22:57 (EDT)
commit4c13fda692505f22f1f5a7d83c4161aea067fc2f (patch)
tree3174f8bdc677397efb6cf5e294108c26e508d825
parenta4420c351de7d7565218f6975b19eaac90fb2075 (diff)
downloadorg.eclipse.papyrus-4c13fda692505f22f1f5a7d83c4161aea067fc2f.zip
org.eclipse.papyrus-4c13fda692505f22f1f5a7d83c4161aea067fc2f.tar.gz
org.eclipse.papyrus-4c13fda692505f22f1f5a7d83c4161aea067fc2f.tar.bz2
[releng] Cleaning-up release engineering toolkit scriptsrefs/changes/79/29379/2
* Refactored for Python idiomatic syntaxes * Added Python inline documentation Change-Id: I193eb4fc271cb97813fe558c3d03b7dfe9785b8c Signed-off-by: Laurent Wouters <laurent.wouters@cea.fr>
-rwxr-xr-xreleng/toolkit/cleaner.py243
-rwxr-xr-xreleng/toolkit/console.py76
-rwxr-xr-xreleng/toolkit/eclipse.py272
-rwxr-xr-xreleng/toolkit/tycho-generator.py451
-rwxr-xr-xreleng/toolkit/tycho-updater.py266
-rwxr-xr-xreleng/toolkit/xmlutils.py35
6 files changed, 766 insertions, 577 deletions
diff --git a/releng/toolkit/cleaner.py b/releng/toolkit/cleaner.py
index 0b6be0a..e2768d1 100755
--- a/releng/toolkit/cleaner.py
+++ b/releng/toolkit/cleaner.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2013 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,112 +9,139 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
-
-import os # File handling
-import os.path # File path handling
-import re # Regular expressions
-import shutil # File handling
-import sys # System
-import subprocess # Process handling
-import xml.dom.minidom # Minimal XML
-
-import console # Console pretty printing
-import eclipse # Eclipse API
-import xmlutils # XML utilities
-
-
-# Print how to use this script
-def printUsage():
- print("Usage:")
- print(" python cleaner.py [-h | --help] [--color] <targets>")
- print(" <targets> is the list of files and directories to clean")
- print("Options:")
- print(" -h, --help: print this screen")
- print(" --color: activate console color")
-
-
-# Cleanup the given bundle
-def cleanup(bundle):
- cleanupClasspath(bundle)
- cleanupBuildProperties(bundle)
-
-# Cleanup the bundle's class path
-def cleanupClasspath(bundle):
- subs = os.listdir(bundle.location)
- if not ".classpath" in subs:
- return
- doc = xml.dom.minidom.parse(os.path.join(bundle.location, ".classpath"))
- dirty = False
- for entry in doc.getElementsByTagName("classpathentry"):
- data = entry.getAttribute("excluding")
- folder = entry.getAttribute("path")
- if data is not None and len(data)>0:
- files = data.split("|")
- for file in files:
- if file is not None and len(file)>0:
- dirty = True
- full = os.path.join(bundle.location, os.path.join(folder, os.path.join(file)))
- print("Found " + full)
- if full.endswith("/"):
- subprocess.call(["git", "rm", "-r", full])
- else:
- subprocess.call(["git", "rm", full])
- entry.parentNode.removeChild(entry)
- if dirty:
- xmlutils.output(doc, os.path.join(bundle.location, ".classpath"))
- console.log("Bundle " + bundle.name + " => Fixed .classpath to remove excluded sources")
-
-# Cleanup the bundle's build properties
-def cleanupBuildProperties(bundle):
- subs = os.listdir(bundle.location)
- if not "build.properties" in subs:
- return
- properties = open(os.path.join(bundle.location, "build.properties"), "r")
- found = False
- for line in properties:
- if line.find("src.includes") != -1:
- found = True
- break
- properties.close()
- if not found:
- if not "about.html" in subs:
- shutil.copy("about.html", os.path.join(bundle.location, "about.html"))
- properties = open(os.path.join(bundle.location, "build.properties"), "a")
- properties.write("src.includes = about.html\n")
- properties.close()
- console.log("Bundle " + bundle.name + " => Fixed build.properties to add src.includes")
-
-# Execute the cleanup
-def execute(targets):
- # Build the repo
- repo = eclipse.Repository()
- for target in targets:
- repo.load(target)
- # Do the cleanup
- for name in repo.plugins:
- cleanup(repo.plugins[name])
- for name in repo.features:
- cleanup(repo.features[name])
+# ###############################################################################
+
+"""
+This script cleans up a repository of Eclipse features and plugins
+in order to improve their Tycho compatibility
+"""
+
+import os # File handling
+import os.path # File path handling
+import shutil # File handling
+import sys # System
+import subprocess # Process handling
+import xml.dom.minidom # Minimal XML
+
+import console # Console pretty printing
+import eclipse # Eclipse API
+import xmlutils # XML utilities
+
+
+def print_usage():
+ """
+ Print how to use this script
+ :return: None
+ """
+ print("Usage:")
+ print(" python cleaner.py [-h | --help] [--color] <targets>")
+ print(" <targets> is the list of files and directories to clean")
+ print("Options:")
+ print(" -h, --help: print this screen")
+ print(" --color: activate console color")
+
+
+def cleanup_bundle(bundle):
+ """
+ Cleanup the specified Eclipse bundle
+ :param bundle: An Eclipse bundle
+ :return: None
+ """
+ __cleanup_classpath(bundle)
+ __cleanup_build_properties(bundle)
+
+
+def __cleanup_classpath(bundle):
+ """
+ Cleanup the classpath of the specified Eclipse bundle
+ :param bundle: An Eclipse bundle
+ :return: None
+ """
+ subs = os.listdir(bundle.location)
+ if not ".classpath" in subs:
+ return
+ doc = xml.dom.minidom.parse(os.path.join(bundle.location, ".classpath"))
+ dirty = False
+ for entry in doc.getElementsByTagName("classpathentry"):
+ data = entry.getAttribute("excluding")
+ folder = entry.getAttribute("path")
+ if data is not None and len(data) > 0:
+ files = data.split("|")
+ for file in files:
+ if file is not None and len(file) > 0:
+ dirty = True
+ full = os.path.join(bundle.location, os.path.join(folder, os.path.join(file)))
+ print("Found " + full)
+ if full.endswith("/"):
+ subprocess.call(["git", "rm", "-r", full])
+ else:
+ subprocess.call(["git", "rm", full])
+ entry.parentNode.removeChild(entry)
+ if dirty:
+ xmlutils.output(doc, os.path.join(bundle.location, ".classpath"))
+ console.log("Bundle " + bundle.name + " => Fixed .classpath to remove excluded sources")
+
+
+def __cleanup_build_properties(bundle):
+ """
+ Cleanup the build properties of the specified Eclipse bunle
+ :param bundle: An Eclipse bundle
+ :return: None
+ """
+ subs = os.listdir(bundle.location)
+ if not "build.properties" in subs:
+ return
+ properties = open(os.path.join(bundle.location, "build.properties"), "r")
+ found = False
+ for line in properties:
+ if line.find("src.includes") != -1:
+ found = True
+ break
+ properties.close()
+ if not found:
+ if not "about.html" in subs:
+ shutil.copy("about.html", os.path.join(bundle.location, "about.html"))
+ properties = open(os.path.join(bundle.location, "build.properties"), "a")
+ properties.write("src.includes = about.html\n")
+ properties.close()
+ console.log("Bundle " + bundle.name + " => Fixed build.properties to add src.includes")
+
+
+def cleanup(directories):
+ """
+ Cleanup the Eclipse bundles in the specified directories
+ :param directories: A collection of directories
+ :return: None
+ """
+ # Build the repo
+ repo = eclipse.Repository()
+ for directory in directories:
+ repo.load(directory)
+ # Do the cleanup
+ for name in repo.plugins:
+ cleanup_bundle(repo.plugins[name])
+ for name in repo.features:
+ cleanup_bundle(repo.features[name])
+
# Main script
-if __name__=="__main__":
- # Checks the arguments
- nb = len(sys.argv)
- if nb <= 1:
- printUsage()
- sys.exit(1)
-
- targets = []
- # Parse the arguments
- for arg in sys.argv[1:]:
- if arg == "-h" or arg == "--help":
- printUsage()
- sys.exit(0)
- elif arg == console.CLI_COLOR:
- console.USE_COLOR = True
- else:
- targets.append(arg)
- # Execute
- code = execute(targets)
- sys.exit(code) \ No newline at end of file
+if __name__ == "__main__":
+ # Checks the arguments
+ nb = len(sys.argv)
+ if nb <= 1:
+ print_usage()
+ sys.exit(1)
+
+ targets = []
+ # Parse the arguments
+ for arg in sys.argv[1:]:
+ if arg == "-h" or arg == "--help":
+ print_usage()
+ sys.exit(0)
+ elif arg == console.CLI_COLOR:
+ console.USE_COLOR = True
+ else:
+ targets.append(arg)
+ # Execute
+ cleanup(targets)
+ sys.exit(0) \ No newline at end of file
diff --git a/releng/toolkit/console.py b/releng/toolkit/console.py
index 9739fa3..7789840 100755
--- a/releng/toolkit/console.py
+++ b/releng/toolkit/console.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2014 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,43 +9,65 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
+# ###############################################################################
+
+"""
+API for console logging with log levels and colors
+"""
+
# Log levels
-LEVELS={
- "DEBUG":0,
- "INFO":0,
- "WARNING":93,
- "ERROR":91
+LEVELS = {
+ "DEBUG": 0,
+ "INFO": 0,
+ "WARNING": 93,
+ "ERROR": 91
}
# Color codes for the console colors
-COLORS={
- "ENDC":0, # RESET COLOR
- "GREY70":97,
- "RED":91,
- "YELLOW":93,
- "BLUE":94,
- "PURPLE":95,
- "GREEN":92,
+COLORS = {
+ "ENDC": 0, # RESET COLOR
+ "GREY70": 97,
+ "RED": 91,
+ "YELLOW": 93,
+ "BLUE": 94,
+ "PURPLE": 95,
+ "GREEN": 92,
}
# Activate/Deactivate the use of console colors
-USE_COLOR=False
+USE_COLOR = False
# Command line option to activate colors
-CLI_COLOR="--color"
+CLI_COLOR = "--color"
+
-# Logs the given message at the given level
def log(message, level="INFO"):
- print(__getFormatted(message, level))
+ """
+ Logs the given message at the given level
+ :param message: The message to log
+ :param level: The log level
+ :return: None
+ """
+ print(__get_formatted(message, level))
+
+
+def __get_formatted(message, level):
+ """
+ Gets the formatted string for the given message and level
+ :param message: The message to format
+ :param level: The log level
+ :return: The formatted message string
+ """
+ if USE_COLOR and LEVELS[level] > 0:
+ return __termcode(LEVELS[level]) + "[" + level + "] " + message + __termcode(0)
+ else:
+ return "[" + level + "] " + message
-# Gets the formatted string for the given message and level
-def __getFormatted(message, level):
- if USE_COLOR and LEVELS[level] > 0:
- return __termcode(LEVELS[level]) + "[" + level + "] " + message + __termcode(0)
- else:
- return "[" + level + "] " + message
-# Gets the string for the given console color
def __termcode(num):
- return "\033[%sm"%num \ No newline at end of file
+ """
+ Gets the string for the given console color
+ :param num: A console color
+ :return: The terminal string for the specified color
+ """
+ return "\033[%sm" % num \ No newline at end of file
diff --git a/releng/toolkit/eclipse.py b/releng/toolkit/eclipse.py
index 0e5180d..fba29a9 100755
--- a/releng/toolkit/eclipse.py
+++ b/releng/toolkit/eclipse.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2014 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,126 +9,174 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
+# ###############################################################################
-# This script provides an API to load and manipulate
-# Eclipse plugins and features in a code repository
+"""
+This script provides an API to load and manipulate
+Eclipse plugins and features in a code repository
+"""
+
+import os # File handling
+import os.path # File path handling
+import re # Regular expressions
+import xml.dom.minidom # Minimal XML
-import os # File handling
-import os.path # File path handling
-import re # Regular expressions
-import xml.dom.minidom # Minimal XML
-# Represents an Eclipse bundle
class Bundle:
- # Constructor
- def __init__(self, location):
- # The name as the last element of the path (folder name)
- self.name = os.path.basename(location)
- # The folder
- self.location = location
+ """
+ Represents an Eclipse bundle
+ """
+
+ def __init__(self, location):
+ """
+ Initializes this bundle
+ :param location: The bundle's location
+ :return: The bundle
+ """
+ # The name as the last element of the path (folder name)
+ self.name = os.path.basename(location)
+ # The folder
+ self.location = location
-# Represents an Eclipse plugin
class Plugin(Bundle):
- def __init__(self, location):
- Bundle.__init__(self, location)
- # Initializes the list of dependencies
- self.dependencies=[]
- # Initializes the manifest data
- self.properties={}
- # Load the data from manifest
- manifest = open(os.path.join(os.path.join(location, "META-INF"), "MANIFEST.MF"), "r")
- onDep = False
- for line in manifest:
- if line.startswith("Require-Bundle:") or onDep:
- m = re.search("[a-zA-Z_][a-zA-Z_0-9]+(\\.[a-zA-Z_][a-zA-Z_0-9]+)+", line)
- dep = m.group(0)
- self.dependencies.append(dep)
- onDep = line.endswith(",")
- elif line.startswith("Bundle-"):
- m = re.match("Bundle-(\\w+): (.*)", line)
- self.properties[m.group(1)] = m.group(2)
- manifest.close()
-
-
-# Represents an Eclipse feature
+ """
+ Represents an Eclipse plugin
+ """
+
+ def __init__(self, location):
+ """
+ Initializes this plugin
+ :param location: The plugin's location
+ :return: The plugin
+ """
+ Bundle.__init__(self, location)
+ # Initializes the list of dependencies
+ self.dependencies = []
+ # Initializes the manifest data
+ self.properties = {}
+ # Load the data from manifest
+ manifest = open(os.path.join(os.path.join(location, "META-INF"), "MANIFEST.MF"), "r")
+ on_dependency = False
+ for line in manifest:
+ if line.startswith("Require-Bundle:") or on_dependency:
+ m = re.search("[a-zA-Z_][a-zA-Z_0-9]+(\\.[a-zA-Z_][a-zA-Z_0-9]+)+", line)
+ dep = m.group(0)
+ self.dependencies.append(dep)
+ on_dependency = line.endswith(",")
+ elif line.startswith("Bundle-"):
+ m = re.match("Bundle-(\\w+): (.*)", line)
+ self.properties[m.group(1)] = m.group(2)
+ manifest.close()
+
+
class Feature(Bundle):
- def __init__(self, location):
- Bundle. __init__(self, location)
- # Initializes the list of the included features
- self.included=[]
- # Initializes the list of the plugins
- self.plugins=[]
- # Load the content
- doc = xml.dom.minidom.parse(os.path.join(location, "feature.xml"))
- for node in doc.getElementsByTagName("plugin"):
- id = node.getAttribute("id")
- self.plugins.append(id)
- for node in doc.getElementsByTagName("includes"):
- id = node.getAttribute("id")
- self.included.append(id)
-
-
-# Represents a repository of Eclipse plugins and features
+ """
+ Represents an Eclipse feature
+ """
+
+ def __init__(self, location):
+ """
+ Represents an Eclipse feature
+ :param location: The feature's location
+ :return: The feature
+ """
+ Bundle.__init__(self, location)
+ # Initializes the list of the included features
+ self.included = []
+ # Initializes the list of the plugins
+ self.plugins = []
+ # Load the content
+ doc = xml.dom.minidom.parse(os.path.join(location, "feature.xml"))
+ for node in doc.getElementsByTagName("plugin"):
+ identifier = node.getAttribute("id")
+ self.plugins.append(identifier)
+ for node in doc.getElementsByTagName("includes"):
+ identifier = node.getAttribute("id")
+ self.included.append(identifier)
+
+
class Repository:
- def __init__(self):
- # Initializes a dictionary of plugins indexed by name
- self.plugins={}
- # Initializes a dictionary of features indexed by name
- self.features={}
-
- # Recursively load plugins and features in the given directory
- def load(self, dir):
- subs = os.listdir(dir)
- if "META-INF" in subs:
- # this is a plugin
- plugin = Plugin(dir)
- self.plugins[plugin.name] = plugin
- return
- if "feature.xml" in subs:
- # this is a feature
- feature = Feature(dir)
- self.features[feature.name] = feature
- return
- for name in subs:
- sub = os.path.join(dir, name)
- if os.path.isdir(sub):
- self.load(sub)
-
- # Checks the consistency of the repository to check whether
- # all required features and plugins are present
- # The given pattern is used to determine whether a feature or
- # plugin is required ; matching means required
- # This method returns the list of the missing features and plugins
- def check(self, includePattern, excludePattern):
- result=[]
- for name in self.features:
- if match(name, excludePattern):
- continue
- feature = self.features[name]
- for included in feature.included:
- if match(included, excludePattern):
- continue
- if not included in self.features and match(included, includePattern):
- result.append(included)
- for plugin in feature.plugins:
- if match(plugin, excludePattern):
- continue
- if not plugin in self.plugins and match(plugin, includePattern):
- result.append(plugin)
- for name in self.plugins:
- if match(name, excludePattern):
- continue
- plugin = self.plugins[name]
- for dep in plugin.dependencies:
- if match(dep, excludePattern):
- continue
- if not dep in self.plugins and match(dep, includePattern):
- result.append(dep)
- return result
+ """
+ Represents a repository of Eclipse plugins and features
+ """
+
+ def __init__(self):
+ """
+ Initializes this repository
+ :return: The repository
+ """
+ # Initializes a dictionary of plugins indexed by name
+ self.plugins = {}
+ # Initializes a dictionary of features indexed by name
+ self.features = {}
+
+ def load(self, directory):
+ """
+ Recursively load plugins and features in the given directory
+ :param directory: The directory to load from
+ :return: None
+ """
+ subs = os.listdir(directory)
+ if "META-INF" in subs:
+ # this is a plugin
+ plugin = Plugin(directory)
+ self.plugins[plugin.name] = plugin
+ return
+ if "feature.xml" in subs:
+ # this is a feature
+ feature = Feature(directory)
+ self.features[feature.name] = feature
+ return
+ for name in subs:
+ sub = os.path.join(directory, name)
+ if os.path.isdir(sub):
+ self.load(sub)
+
+ def check(self, include_pattern, exclude_pattern):
+ """
+ Checks the consistency of the repository to check whether
+ all required features and plugins are present
+ The given pattern is used to determine whether a feature or
+ plugin is required ; matching means required
+ This method returns the list of the missing features and plugins
+ :param include_pattern: A pattern matching the bundles to include
+ :param exclude_pattern: A pattern matching the bundles to exclude
+ :return: The missing bundles
+ """
+ result = []
+ for name in self.features:
+ if match(name, exclude_pattern):
+ continue
+ feature = self.features[name]
+ for included in feature.included:
+ if match(included, exclude_pattern):
+ continue
+ if not included in self.features and match(included, include_pattern):
+ result.append(included)
+ for plugin in feature.plugins:
+ if match(plugin, exclude_pattern):
+ continue
+ if not plugin in self.plugins and match(plugin, include_pattern):
+ result.append(plugin)
+ for name in self.plugins:
+ if match(name, exclude_pattern):
+ continue
+ plugin = self.plugins[name]
+ for dep in plugin.dependencies:
+ if match(dep, exclude_pattern):
+ continue
+ if not dep in self.plugins and match(dep, include_pattern):
+ result.append(dep)
+ return result
def match(value, pattern):
- m = re.match(pattern, value)
- return (m is not None) \ No newline at end of file
+ """
+ Determines whether the specified value matches the given pattern
+ :param value: A value
+ :param pattern: A pattern
+ :return: True if the value matches the pattern
+ """
+ m = re.match(pattern, value)
+ return m is not None \ No newline at end of file
diff --git a/releng/toolkit/tycho-generator.py b/releng/toolkit/tycho-generator.py
index dbf24ff..fd2b7d2 100755
--- a/releng/toolkit/tycho-generator.py
+++ b/releng/toolkit/tycho-generator.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2014 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,34 +9,44 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
+# ###############################################################################
-import os # File handling
-import os.path # File path handling
-import re # Regular expressions
-import sys # System
-import xml.dom.minidom # Minimal XML
+"""
+This script provides an API to generate the Tycho
+configuration files (pom.xml) for an Eclipse code repository
+"""
-import console # Console pretty printing
-import eclipse # Eclipse API
-import xmlutils # XML utilities
+import os # File handling
+import os.path # File path handling
+import sys # System
+import xml.dom.minidom # Minimal XML
+
+import console # Console pretty printing
+import eclipse # Eclipse API
+import xmlutils # XML utilities
-# Represents a build target
class Target:
- def __init__(self, name, pom, site, feature):
- # The target's name
- self.name = name
- # The path to the top pom.xml file
- self.pom = pom
- # The path to the repository (update site) project
- self.site = site
- # The target's top feature
- self.feature = feature
+ """
+ Represents a build target
+ """
+ def __init__(self, name, pom, site, feature):
+ """
+ Initializes this build target
+ :param name: The target's name
+ :param pom: Path to the target top pom.xml
+ :param site: Path to the target's site
+ :param feature: Identifier of the target's top Eclipse feature
+ :return: The build target
+ """
+ self.name = name
+ self.pom = pom
+ self.site = site
+ self.feature = feature
# General constants
-MAVEN_MODEL_VERSION="4.0.0"
+MAVEN_MODEL_VERSION = "4.0.0"
# Product constants
PRODUCT_VERSION = "1.0.0"
@@ -46,189 +56,240 @@ PRODUCT_CATEGORY_DESC = PRODUCT_CATEGORY_LABEL
PRODUCT_GROUP = "org.eclipse.papyrus"
# Generator targets configuration
-TARGETS = [ Target( "main",
- "releng/top-pom-main.xml",
- "releng/main",
- "org.eclipse.papyrus.sdk.feature"),
- Target( "extras",
- "releng/top-pom-extras.xml",
- "releng/extras",
- "org.eclipse.papyrus.extra.feature"),
- Target( "dev",
- "releng/top-pom-dev.xml",
- "releng/dev",
- "org.eclipse.papyrus.dev.feature") ]
+TARGETS = [Target("main",
+ "releng/top-pom-main.xml",
+ "releng/main",
+ "org.eclipse.papyrus.sdk.feature"),
+ Target("extras",
+ "releng/top-pom-extras.xml",
+ "releng/extras",
+ "org.eclipse.papyrus.extra.feature"),
+ Target("dev",
+ "releng/top-pom-dev.xml",
+ "releng/dev",
+ "org.eclipse.papyrus.dev.feature")]
+
# Generator inputs configuration
INPUTS = [
- "plugins",
- "extraplugins",
- "features/papyrus-main-features",
- "features/papyrus-extra-features",
- "features/papyrus-dev-features"
+ "plugins",
+ "extraplugins",
+ "features/papyrus-main-features",
+ "features/papyrus-extra-features",
+ "features/papyrus-dev-features"
]
+
# Pattern to recognize required plugin to include in the build
PATTERN_INCLUDE = "org\\.eclipse\\.papyrus\\..*"
# Pattern to recognize required plugin to exclude from the build
PATTERN_EXCLUDE = "(.*\\.source.feature)|(.*\\.tests)"
-# Print how to use this script
-def printUsage():
- print("Usage:")
- print(" python tycho-generator.py [-h | --help] [--color]")
- print("Options:")
- print(" -h, --help: print this screen")
- print(" --color: activate console color")
-
-
-# Generate the Tycho data and files
-def generate(inputs, targets, includePattern, excludePattern):
- # Build repo
- console.log("== Preparing the repository ...")
- repo = getRepo(inputs, includePattern, excludePattern)
- if repo is None:
- return 1
- # Setup the bundles' target data
- for target in targets:
- addTarget(repo, target.feature, target)
- # Generate all bundles POM
- console.log("== Generating POM for features ...")
- for name in iter(sorted(repo.features)):
- if not generateBundlePOM(repo.features[name], "eclipse-feature"):
- return 2
- console.log("== Generating POM for plugins ...")
- for name in iter(sorted(repo.plugins)):
- if not generateBundlePOM(repo.plugins[name], "eclipse-plugin"):
- return 2
- # Update the targets' top pom.xml
- console.log("== Updating the module references in top POMs ...")
- for target in targets:
- updateModules(repo, target)
- return 0
-
-
-# Gets an initialized repository of features and plugins
-# includePattern is used to identify required plugins and features
-# excludePattern is used to ignore MISSING plugins and features
-def getRepo(inputs, includePattern, excludePattern):
- # Build the repo
- repo = eclipse.Repository()
- for input in inputs:
- repo.load(input)
- # Check for missing bundles
- missing = repo.check(includePattern, excludePattern)
- for m in missing:
- console.log("Missing bundle " + m, "ERROR")
- if len(missing) > 0:
- return None
- # Initializes the targets
- for name in repo.plugins:
- repo.plugins[name].targets = []
- for name in repo.features:
- repo.features[name].targets = []
- return repo
-
-
-# Recursively add a target to a feature, its included features and its plugins
-def addTarget(repo, featureName, target):
- # If the feature is missing
- if not featureName in repo.features:
- return
- feature = repo.features[featureName]
- # Add the target is required
- if not target in feature.targets:
- feature.targets.append(target)
- # Traverse all sub-features
- for included in feature.included:
- addTarget(repo, included, target)
- # Traverse all plugins
- for name in feature.plugins:
- if name in repo.plugins:
- plugin = repo.plugins[name]
- if not target in plugin.targets:
- plugin.targets.append(target)
-
-
-# Generate the pom.xml file for the given bundle and given packaging
-def generateBundlePOM(bundle, packaging):
- if len(bundle.targets) == 0:
- console.log("Bundle " + bundle.name + " has no target => skipped", "WARNING")
- return True
- if len(bundle.targets) >= 2:
- console.log("Bundle " + bundle.name + " has more than one target:", "ERROR")
- for target in bundle.targets:
- console.log("\t" + target, "ERROR")
- return False
- if os.path.isfile(os.path.join(bundle.location, "pom.xml")):
- console.log("Bundle " + bundle.name + " already has pom.xml => skipped")
- return True
- relative = os.path.relpath(".", bundle.location)
- relative = os.path.join(relative, bundle.targets[0].pom)
- impl = xml.dom.minidom.getDOMImplementation()
- doc = impl.createDocument(None, "project", None)
- project = doc.documentElement
- appendText(doc, project, "modelVersion", MAVEN_MODEL_VERSION)
- parent = doc.createElement("parent")
- project.appendChild(parent)
- appendTychoRef(doc, parent, PRODUCT_GROUP)
- appendText(doc, parent, "relativePath", relative)
- appendTychoRef(doc, project, bundle.name)
- appendText(doc, project, "packaging", packaging)
- xmlutils.output(doc, os.path.join(bundle.location, "pom.xml"))
- console.log("Bundle " + bundle.name + " POM generated for target " + bundle.targets[0].name)
- return True
-
-
-# Append an element node with the given tag and content
-def appendText(doc, parent, tag, content):
- child = doc.createElement(tag)
- parent.appendChild(child)
- child.appendChild(doc.createTextNode(content))
-
-
-# Append Tycho-specific data
-def appendTychoRef(doc, parent, id):
- appendText(doc, parent, "artifactId", id)
- appendText(doc, parent, "groupId", PRODUCT_GROUP)
- appendText(doc, parent, "version", PRODUCT_VERSION + "-SNAPSHOT")
-
-
-# Updates the modules for the given target
-def updateModules(repo, target):
- doc = xml.dom.minidom.parse(target.pom)
- modules = doc.getElementsByTagName("modules")[0]
- for module in modules.getElementsByTagName("module"):
- modules.removeChild(module)
- for name in iter(sorted(repo.features)):
- feature = repo.features[name]
- if target in feature.targets:
- modules.appendChild(getBundleModuleNode(feature, doc, target))
- for name in iter(sorted(repo.plugins)):
- plugin = repo.plugins[name]
- if target in plugin.targets:
- modules.appendChild(getBundleModuleNode(plugin, doc, target))
- repoNode = doc.createElement("module")
- repoNode.appendChild(doc.createTextNode(target.name))
- modules.appendChild(repoNode)
- xmlutils.output(doc, target.pom)
- console.log("Updated top POM for target " + target.name)
-
-# Get the path to this bundle relatively to the given target's top POM
-def getBundleModuleNode(bundle, doc, target):
- child = doc.createElement("module")
- child.appendChild(doc.createTextNode(os.path.join("..", bundle.location)))
- return child
+def print_usage():
+ """
+ Print how to use this script
+ :return: None
+ """
+ print("Usage:")
+ print(" python tycho-generator.py [-h | --help] [--color]")
+ print("Options:")
+ print(" -h, --help: print this screen")
+ print(" --color: activate console color")
+
+
+def generate(inputs, targets, include_pattern, exclude_pattern):
+ """
+ Generate the Tycho data and files
+ :param inputs: Array of input directories to load Eclipse plugins and features from
+ :param targets: Array of build targets
+ :param include_pattern: Pattern matching Eclipse bundle to include into a build target
+ :param exclude_pattern: Pattern matching Eclipse bundle to exclude from any build target
+ :return: The error code, or 0 if all went well
+ """
+ # Build repo
+ console.log("== Preparing the repository ...")
+ repo = __build_repository(inputs, include_pattern, exclude_pattern)
+ if repo is None:
+ return 1
+ # Setup the bundles' target data
+ for target in targets:
+ __add_target(repo, target.feature, target)
+ # Generate all bundles POM
+ console.log("== Generating POM for features ...")
+ for name in iter(sorted(repo.features)):
+ if not __generate_bundle_pom(repo.features[name], "eclipse-feature"):
+ return 2
+ console.log("== Generating POM for plugins ...")
+ for name in iter(sorted(repo.plugins)):
+ if not __generate_bundle_pom(repo.plugins[name], "eclipse-plugin"):
+ return 2
+ # Update the targets' top pom.xml
+ console.log("== Updating the module references in top POMs ...")
+ for target in targets:
+ __update_modules(repo, target)
+ return 0
+
+
+def __build_repository(inputs, include_pattern, exclude_pattern):
+ """
+ Gets an initialized repository of features and plugins
+ :param inputs: Array of input directories to load Eclipse plugins and features from
+ :param include_pattern: Pattern matching Eclipse bundle to include into a build target
+ :param exclude_pattern: Pattern matching Eclipse bundle to exclude from any build target
+ :return: The corresponding repository of Eclipse plugins and features
+ """
+ # Build the repo
+ repository = eclipse.Repository()
+ for directory_input in inputs:
+ repository.load(directory_input)
+ # Check for missing bundles
+ missing = repository.check(include_pattern, exclude_pattern)
+ for m in missing:
+ console.log("Missing bundle " + m, "ERROR")
+ if len(missing) > 0:
+ return None
+ # Initializes the targets
+ for name in repository.plugins:
+ repository.plugins[name].targets = []
+ for name in repository.features:
+ repository.features[name].targets = []
+ return repository
+
+
+def __add_target(repository, feature_identifier, target):
+ """
+ Recursively add a build target to a feature, its included features and its plugins
+ :param repository: The Eclipse repository to work on
+ :param feature_identifier: The identifier of the Eclipse feature to add a build target for
+ :param target: The build target to add
+ :return: None
+ """
+ # If the feature is missing
+ if not feature_identifier in repository.features:
+ return
+ feature = repository.features[feature_identifier]
+ # Add the target is required
+ if not target in feature.targets:
+ feature.targets.append(target)
+ # Traverse all sub-features
+ for included in feature.included:
+ __add_target(repository, included, target)
+ # Traverse all plugins
+ for name in feature.plugins:
+ if name in repository.plugins:
+ plugin = repository.plugins[name]
+ if not target in plugin.targets:
+ plugin.targets.append(target)
+
+
+def __generate_bundle_pom(bundle, packaging):
+ """
+ Generate the pom.xml file for the given bundle and given packaging
+ :param bundle: The bundle to generate the pom for
+ :param packaging: The type of packaging (feature or plugin)
+ :return: True if the operation succeeded, False otherwise
+ """
+ if len(bundle.targets) == 0:
+ console.log("Bundle " + bundle.name + " has no target => skipped", "WARNING")
+ return True
+ if len(bundle.targets) >= 2:
+ console.log("Bundle " + bundle.name + " has more than one target:", "ERROR")
+ for target in bundle.targets:
+ console.log("\t" + target, "ERROR")
+ return False
+ if os.path.isfile(os.path.join(bundle.location, "pom.xml")):
+ console.log("Bundle " + bundle.name + " already has pom.xml => skipped")
+ return True
+ relative = os.path.relpath(".", bundle.location)
+ relative = os.path.join(relative, bundle.targets[0].pom)
+ impl = xml.dom.minidom.getDOMImplementation()
+ doc = impl.createDocument(None, "project", None)
+ project = doc.documentElement
+ __xml_append_text(doc, project, "modelVersion", MAVEN_MODEL_VERSION)
+ parent = doc.createElement("parent")
+ project.appendChild(parent)
+ __xml_append_tycho_ref(doc, parent, PRODUCT_GROUP)
+ __xml_append_text(doc, parent, "relativePath", relative)
+ __xml_append_tycho_ref(doc, project, bundle.name)
+ __xml_append_text(doc, project, "packaging", packaging)
+ xmlutils.output(doc, os.path.join(bundle.location, "pom.xml"))
+ console.log("Bundle " + bundle.name + " POM generated for target " + bundle.targets[0].name)
+ return True
+
+
+def __xml_append_text(doc, parent, tag, content):
+ """
+ Append an element node with the given tag and content
+ :param doc: The parent document
+ :param parent: The parent XML element node
+ :param tag: The element tag to create
+ :param content: The content of the element to create
+ :return: None
+ """
+ child = doc.createElement(tag)
+ parent.appendChild(child)
+ child.appendChild(doc.createTextNode(content))
+
+
+def __xml_append_tycho_ref(doc, parent, tycho_identifier):
+ """
+ Append a reference to a Tycho module
+ :param doc: The parent document
+ :param parent: The parent XML element node
+ :param tycho_identifier: The Tycho module identifier
+ :return:
+ """
+ __xml_append_text(doc, parent, "artifactId", tycho_identifier)
+ __xml_append_text(doc, parent, "groupId", PRODUCT_GROUP)
+ __xml_append_text(doc, parent, "version", PRODUCT_VERSION + "-SNAPSHOT")
+
+
+def __update_modules(repository, target):
+ """
+ Updates the modules for the given target
+ :param repository: The Eclipse repository to work on
+ :param target: The build target to update
+ :return: None
+ """
+ doc = xml.dom.minidom.parse(target.pom)
+ modules = doc.getElementsByTagName("modules")[0]
+ for module in modules.getElementsByTagName("module"):
+ modules.removeChild(module)
+ for name in iter(sorted(repository.features)):
+ feature = repository.features[name]
+ if target in feature.targets:
+ modules.appendChild(__get_module_node(feature, doc))
+ for name in iter(sorted(repository.plugins)):
+ plugin = repository.plugins[name]
+ if target in plugin.targets:
+ modules.appendChild(__get_module_node(plugin, doc))
+ repo_node = doc.createElement("module")
+ repo_node.appendChild(doc.createTextNode(target.name))
+ modules.appendChild(repo_node)
+ xmlutils.output(doc, target.pom)
+ console.log("Updated top POM for target " + target.name)
+
+
+def __get_module_node(bundle, doc):
+ """
+ Get the path to the specified bundle relatively to the given target's top POM
+ :param bundle: An Eclipse bundle
+ :param doc: The parent XML document
+ :return: The XML node containing the relative path
+ """
+ child = doc.createElement("module")
+ child.appendChild(doc.createTextNode(os.path.join("..", bundle.location)))
+ return child
# Main script
-if __name__=="__main__":
- # Checks the arguments
- for arg in sys.argv[1:]:
- if arg == "-h" or arg == "--help":
- printUsage()
- sys.exit(0)
- elif arg == console.CLI_COLOR:
- console.USE_COLOR = True
- # Execute the generation
- code = generate(INPUTS, TARGETS, PATTERN_INCLUDE, PATTERN_EXCLUDE)
- sys.exit(code) \ No newline at end of file
+if __name__ == "__main__":
+ # Checks the arguments
+ for arg in sys.argv[1:]:
+ if arg == "-h" or arg == "--help":
+ print_usage()
+ sys.exit(0)
+ elif arg == console.CLI_COLOR:
+ console.USE_COLOR = True
+ # Execute the generation
+ code = generate(INPUTS, TARGETS, PATTERN_INCLUDE, PATTERN_EXCLUDE)
+ sys.exit(code) \ No newline at end of file
diff --git a/releng/toolkit/tycho-updater.py b/releng/toolkit/tycho-updater.py
index 70ca723..4749e7d 100755
--- a/releng/toolkit/tycho-updater.py
+++ b/releng/toolkit/tycho-updater.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2014 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,132 +9,156 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
+# ###############################################################################
-# This script provides an API to update the URI
-# of P2 update sites in Tycho pom.xml using the
-# Eclipse SIMREL repository
+"""
+This script provides an API to update the URI
+of P2 update sites in Tycho pom.xml using the
+Eclipse SIMREL repository
+"""
-import os.path # File path handling
-import re # Regular expressions
-import shutil # Shell utilities
-import subprocess # OS Process management
-import sys # System
-import xml.dom.minidom # Minimal XML
+import os.path # File path handling
+import re # Regular expressions
+import shutil # Shell utilities
+import subprocess # OS Process management
+import sys # System
+import xml.dom.minidom # Minimal XML
-import console # Console pretty printing
-import xmlutils # XML utilities
+import console # Console pretty printing
+import xmlutils # XML utilities
# URI of the git SIMREL repository
-SIMREL_GIT="http://git.eclipse.org/gitroot/simrel/org.eclipse.simrel.build.git"
+SIMREL_GIT = "http://git.eclipse.org/gitroot/simrel/org.eclipse.simrel.build.git"
# Path of the local SIMREL repository
-SIMREL_PATH="simrel"
-
-
-# Print how to use this script
-def printUsage():
- print("Usage:")
- print(" python tycho-updater.py [-h | --help] [--color] [--simrel <local>] <targets>")
- print(" <targets> is the list of file to update")
- print("Options:")
- print(" -h, --help: print this screen")
- print(" --color: activate console color")
- print(" --simrel <local>: use the SIMREL repo at the given <local> path")
-
-# Get the update site URL for the given identifier
-# An identifier is a simple name with an optional '[index]' suffix where index is the integer index of the update site to use
-def getURLFor(simrel, id):
- m = re.match("(?P<id>(\\w|-)+)(\\[(?P<index>\\d+)\\])?", id)
- if m is None:
- return None
- file = simrel + "/" + m.group("id") + ".b3aggrcon"
- index = m.group("index")
- if index is None:
- index = 0
- else:
- index = int(index)
- if os.path.isfile(file):
- content = xml.dom.minidom.parse(simrel + "/" + m.group("id") + ".b3aggrcon")
- location = content.getElementsByTagName("repositories")[index].getAttribute("location")
- return location
- return None
-
-# Update the given Tycho pom.xml file with new update sites
+SIMREL_PATH = "simrel"
+
+
+def print_usage():
+ """
+ Print how to use this script
+ :return: None
+ """
+ print("Usage:")
+ print(" python tycho-updater.py [-h | --help] [--color] [--simrel <local>] <targets>")
+ print(" <targets> is the list of file to update")
+ print("Options:")
+ print(" -h, --help: print this screen")
+ print(" --color: activate console color")
+ print(" --simrel <local>: use the SIMREL repo at the given <local> path")
+
+
+def __get_url_for(simrel, identifier):
+ """
+ Get the update site URL for the given identifier
+ An identifier is a simple name with an optional '[index]' suffix
+ where index is the integer index of the update site to use
+ :param simrel: Path to the local simrel repository
+ :param identifier: Identifier of the dependency
+ :return: The URL for the dependency
+ """
+ m = re.match("(?P<id>(\\w|-)+)(\\[(?P<index>\\d+)\\])?", identifier)
+ if m is None:
+ return None
+ file = simrel + "/" + m.group("id") + ".b3aggrcon"
+ index = m.group("index")
+ if index is None:
+ index = 0
+ else:
+ index = int(index)
+ if os.path.isfile(file):
+ content = xml.dom.minidom.parse(simrel + "/" + m.group("id") + ".b3aggrcon")
+ location = content.getElementsByTagName("repositories")[index].getAttribute("location")
+ return location
+ return None
+
+
def update(simrel, target):
- console.log("Reading " + target)
- pom = xml.dom.minidom.parse(target)
-
- console.log("Updating " + target)
- for node in pom.getElementsByTagName("repository"):
- id = node.getElementsByTagName("id")[0].childNodes[0].data
- url = node.getElementsByTagName("url")[0].childNodes[0].data
- data = getURLFor(simrel, id)
- if data == None:
- console.log(id + " => no matching repository found", "WARNING")
- else:
- if data == url:
- console.log(id + " => no change")
- else:
- node.getElementsByTagName("url")[0].childNodes[0].data = data
- console.log(id + " => updated to " + data)
-
- console.log("Writing back " + target)
- xmlutils.output(pom, target)
-
-
-
-# Main script
-if __name__=="__main__":
- # Checks the arguments
- nb = len(sys.argv)
- if nb <= 1:
- printUsage()
- sys.exit(1)
-
- # Initializes the local data
- local = False
- simrel = SIMREL_PATH
- targets = []
-
- # Parse the arguments
- expectLocal = False
- for arg in sys.argv[1:]:
- if arg == "-h" or arg == "--help":
- printUsage()
- sys.exit(0)
- elif arg == console.CLI_COLOR:
- console.USE_COLOR = True
- elif arg == "--simrel":
- expectLocal = True
- elif expectLocal:
- local = True
- simrel = arg
- expectLocal = False
- else:
- targets.append(arg)
-
- # Checks the data
- if expectLocal:
- console.log("Expected path the local SIMREL repo", "ERROR")
- printUsage()
- sys.exit(1)
- if len(targets) == 0:
- console.log("No target given", "ERROR")
- printUsage()
- sys.exit(1)
-
- # Clone the SIMREL repo if needed
- if local:
- console.log("Using local simrel at " + simrel)
- else:
- console.log("Cloning the simrel repository from Eclipse")
- subprocess.call(["git", "clone", SIMREL_GIT, simrel])
- # Do the updates
- for target in targets:
- update(simrel, target)
- # Cleanup if required
- if not local:
- console.log("Cleaning up ...")
- shutil.rmtree(simrel) \ No newline at end of file
+ """
+ Update the given Tycho pom.xml file with new update sites
+ :param simrel: Path to the local simrel repository
+ :param target: Path to the target pom.xml to update
+ :return: None
+ """
+ console.log("Reading " + target)
+ pom = xml.dom.minidom.parse(target)
+
+ console.log("Updating " + target)
+ for node in pom.getElementsByTagName("repository"):
+ identifier = node.getElementsByTagName("id")[0].childNodes[0].data
+ url = node.getElementsByTagName("url")[0].childNodes[0].data
+ data = __get_url_for(simrel, identifier)
+ if data is None:
+ console.log(identifier + " => no matching repository found", "WARNING")
+ else:
+ if data == url:
+ console.log(identifier + " => no change")
+ else:
+ node.getElementsByTagName("url")[0].childNodes[0].data = data
+ console.log(identifier + " => updated to " + data)
+
+ console.log("Writing back " + target)
+ xmlutils.output(pom, target)
+
+
+def execute(arguments):
+ """
+ Executes the update process
+ :return: None
+ """
+ # Checks the arguments
+ nb = len(arguments)
+ if nb <= 1:
+ print_usage()
+ sys.exit(1)
+
+ # Initializes the local data
+ local = False
+ simrel = SIMREL_PATH
+ targets = []
+
+ # Parse the arguments
+ expect_local = False
+ for arg in arguments[1:]:
+ if arg == "-h" or arg == "--help":
+ print_usage()
+ sys.exit(0)
+ elif arg == console.CLI_COLOR:
+ console.USE_COLOR = True
+ elif arg == "--simrel":
+ expect_local = True
+ elif expect_local:
+ local = True
+ simrel = arg
+ expect_local = False
+ else:
+ targets.append(arg)
+
+ # Checks the data
+ if expect_local:
+ console.log("Expected path the local SIMREL repo", "ERROR")
+ print_usage()
+ sys.exit(1)
+ if len(targets) == 0:
+ console.log("No target given", "ERROR")
+ print_usage()
+ sys.exit(1)
+
+ # Clone the SIMREL repo if needed
+ if local:
+ console.log("Using local simrel at " + simrel)
+ else:
+ console.log("Cloning the simrel repository from Eclipse")
+ subprocess.call(["git", "clone", SIMREL_GIT, simrel])
+ # Do the updates
+ for target in targets:
+ update(simrel, target)
+ # Cleanup if required
+ if not local:
+ console.log("Cleaning up ...")
+ shutil.rmtree(simrel)
+
+
+if __name__ == "__main__":
+ execute(sys.argv) \ No newline at end of file
diff --git a/releng/toolkit/xmlutils.py b/releng/toolkit/xmlutils.py
index cb206f4..90b6258 100755
--- a/releng/toolkit/xmlutils.py
+++ b/releng/toolkit/xmlutils.py
@@ -1,4 +1,4 @@
-################################################################################
+# ###############################################################################
# Copyright (c) 2014 CEA LIST.
#
# All rights reserved. This program and the accompanying materials
@@ -9,24 +9,31 @@
# Contributors:
# Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation
#
-################################################################################
-
-# System imports
-import xml.dom.minidom # Minimal XML
+# ###############################################################################
+"""
+API for the serialization of pretty-printed XML files
+"""
# encoding of the XML files
-XML_ENCODING="UTF-8"
+XML_ENCODING = "UTF-8"
# identation string
-XML_IDENT="\t"
+XML_IDENT = "\t"
# new line string
-XML_NEWLINE="\n"
+XML_NEWLINE = "\n"
-# Outputs the XML document in the given file with pretty printing
def output(document, file):
- document.normalize()
- content = XML_NEWLINE.join([line for line in document.toprettyxml(XML_IDENT, XML_NEWLINE, XML_ENCODING).split(XML_NEWLINE) if line.strip()])
- output = open(file, "w")
- output.write(content)
- output.close() \ No newline at end of file
+ """
+ Outputs the XML document in the given file with pretty printing
+ :param document: The XML document to serialize
+ :param file: The file to output to
+ :return: None
+ """
+ document.normalize()
+ content = XML_NEWLINE.join(
+ [line for line in document.toprettyxml(XML_IDENT, XML_NEWLINE, XML_ENCODING).split(XML_NEWLINE) if
+ line.strip()])
+ result = open(file, "w")
+ result.write(content)
+ result.close() \ No newline at end of file