Created
July 22, 2013 18:43
-
-
Save eddieantonio/6056410 to your computer and use it in GitHub Desktop.
A useless Python script I used to collect JARs and WARs from a directory of Maven projects.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Build all Maven files and dump all of the jars into a directory. | |
""" | |
import os | |
import sys | |
import re | |
import glob | |
import shutil | |
import xml.etree.ElementTree as ET | |
from contextlib import contextmanager | |
RELEASE_DIR = os.path.join(os.getcwd(), 'release') | |
# ANSI colours | |
BLACK = 0 | |
RED = 1 | |
GREEN = 2 | |
YELLOW = 3 | |
BLUE = 4 | |
MAGENTA = 5 | |
CYAN = 6 | |
WHITE = 7 | |
RESET = '\033[0m' | |
@contextmanager | |
def ansi_color(foreground=None, background=None, bold=False, stream=sys.stdout): | |
""" | |
Surrounds write to `stream` with the given ANSI colour. | |
Maybe I'm going crazy with context managers... | |
""" | |
codes = [] | |
if foreground: | |
codes.append(foreground | int('30', base=8)) | |
if background: | |
codes.append(background | int('40', base=8)) | |
if bold: | |
codes.append(1) | |
# Create the inner... part | |
inner = ';'.join('%o' % num for num in codes) | |
escape = '\033[%sm' % inner | |
stream.write(escape) | |
yield | |
stream.write(RESET) | |
stream.flush() | |
def find_maven_projects(top_level='.'): | |
""" | |
Generates a tuple of (path, pom) for each Maven project found in the given | |
top level. Defaults to the current working directory. | |
`pom` is parsed into an ElementTree object. | |
""" | |
# Get subdirectories. Pretend I have pattern matching. | |
_, subdirectories, _ = next(os.walk(top_level)) | |
for directory in subdirectories: | |
# Skip if no pom is found | |
if 'pom.xml' not in os.listdir(directory): | |
continue | |
# Else, parse it and yield it. | |
pom_filename = os.path.join(directory, 'pom.xml') | |
pom = ET.parse(pom_filename) | |
yield directory, pom | |
def war_handler(project_dir, settings, pom): | |
""" | |
Handles WAR packaging. | |
""" | |
# TODO | |
raise NotImplementedError('gotta figure this one out :/') | |
def jar_handler(project_dir, settings, pom): | |
""" | |
Handles JAR packaging. | |
""" | |
# Glob for the fully-qualified path of the project dir. | |
jar_glob = os.path.join(os.getcwd(), project_dir, 'target', '*.jar') | |
jars = glob.iglob(jar_glob) | |
for jar_path in jars: | |
# Get the base name of the jar, and the new path. | |
jar_name = os.path.basename(jar_path) | |
new_path = os.path.join(RELEASE_DIR, jar_name) | |
# Now copy it over. | |
shutil.copy(jar_path, new_path) | |
def unknown_handler(project_dir, settings, pom): | |
""" | |
Handles unknown packaging. | |
""" | |
print("Cannot package '%s'!" % project_dir) | |
packaging_handlers = { | |
'war': war_handler, | |
'jar': jar_handler | |
} | |
def get_namespace(element): | |
""" | |
Gets the XML namespace of a given object. Returns None if no namespace is | |
defined. | |
""" | |
# Extract the name from the root tag. | |
root_name = element.tag | |
match = re.match(r'^{([^}]+)}', root_name) | |
# Get the XML namespace, or else get None. | |
return match.group(1) if match else None | |
def fix_namespaces(tree): | |
""" | |
Inserts the proper namespace prefix for the sequence 'n:' in an XPath | |
query. | |
Returns the partially applied function that does the namespace fixing for | |
a given string. | |
>>> pom = ET.fromstring('<project xmlns="http://maven.apache.org/POM/4.0.0"></project>') | |
>>> fix_namespaces(pom)('./n:packaging') | |
'./{http://maven.apache.org/POM/4.0.0}packaging' | |
""" | |
namespace = get_namespace(tree) | |
# Render and compile the replacement and the regex. | |
replacement = '{%s}' % namespace if namespace is not None else '' | |
path_pattern = re.compile(r'\bn:') | |
def fixer(path): | |
return path_pattern.sub(replacement, path) | |
return fixer | |
def get_packaging_handler(pom): | |
""" | |
Returns a function for the given pom ElementTree that, when called will | |
place the function into the correct directory. | |
""" | |
# Get the packaging directive. | |
query = fix_namespaces(pom.getroot())(r'./n:packaging') | |
packaging = pom.find(query) | |
# Assume 'jar' if there is no packaging directive. | |
packaging_name = packaging.text if packaging is not None else 'jar' | |
# Return the proper handler, or else use the unknown handler. | |
return packaging_handlers.get(packaging_name, unknown_handler) | |
@contextmanager | |
def cd(next_dir): | |
""" | |
Changes the current working directory to `next_dir` for the given context. | |
The current working directory is reverted when the context is left. | |
>>> with cd('/tmp'), open('hello', 'w') as outfile: | |
... outfile.write('hi!') | |
>>> with open('/tmp/hello') as infile: | |
... print(infile.read()) | |
hi! | |
""" | |
original_dir = os.getcwd() | |
os.chdir(next_dir) | |
yield | |
os.chdir(original_dir) | |
def main(top_level='.'): | |
# Get a list of all maven projects. | |
projects = find_maven_projects(top_level) | |
for name, pom in projects: | |
with ansi_color(RED, bold=True): | |
print("Project: %s" % name) | |
# Run Maven in the project directory. | |
with cd(name): | |
os.system('mvn package') | |
# Now, get a handler based on the packagin | |
handle = get_packaging_handler(pom) | |
# And now handle it! | |
handle(name, {}, pom) | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment