|
William Benton |
e3a44e3 |
#!/usr/bin/env python
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
# Copyright 2013, 2014 Red Hat, Inc., and William C. Benton
|
|
William Benton |
e3a44e3 |
#
|
|
William Benton |
e3a44e3 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
William Benton |
e3a44e3 |
# you may not use this file except in compliance with the License.
|
|
William Benton |
e3a44e3 |
# You may obtain a copy of the License at
|
|
William Benton |
e3a44e3 |
#
|
|
William Benton |
e3a44e3 |
# http://www.apache.org/licenses/LICENSE-2.0
|
|
William Benton |
e3a44e3 |
#
|
|
William Benton |
e3a44e3 |
# Unless required by applicable law or agreed to in writing, software
|
|
William Benton |
e3a44e3 |
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
William Benton |
e3a44e3 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
William Benton |
e3a44e3 |
# See the License for the specific language governing permissions and
|
|
William Benton |
e3a44e3 |
# limitations under the License.
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
import xml.etree.ElementTree as ET
|
|
William Benton |
e3a44e3 |
import argparse
|
|
William Benton |
e3a44e3 |
import StringIO
|
|
William Benton |
e3a44e3 |
import re
|
|
William Benton |
e3a44e3 |
import subprocess
|
|
William Benton |
e3a44e3 |
import logging
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
from os.path import exists as pathexists
|
|
William Benton |
e3a44e3 |
from os.path import realpath
|
|
William Benton |
e3a44e3 |
from os.path import join as pathjoin
|
|
William Benton |
e3a44e3 |
from os import makedirs
|
|
William Benton |
e3a44e3 |
from os import symlink
|
|
William Benton |
e3a44e3 |
from os import remove as rmfile
|
|
William Benton |
e3a44e3 |
from shutil import copyfile
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
class Artifact(object):
|
|
William Benton |
e3a44e3 |
def __init__(self, a, g, v):
|
|
William Benton |
e3a44e3 |
self.artifact = a
|
|
William Benton |
e3a44e3 |
self.group = g
|
|
William Benton |
e3a44e3 |
self.version = v
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
@classmethod
|
|
William Benton |
e3a44e3 |
def fromCoords(k, coords):
|
|
William Benton |
e3a44e3 |
g,a,v = coords.split(":")
|
|
William Benton |
e3a44e3 |
return k(a, g, v)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
@classmethod
|
|
William Benton |
e3a44e3 |
def fromSubtree(k, t, ns):
|
|
William Benton |
e3a44e3 |
a = t.find("./%sartifactId" % ns).text
|
|
William Benton |
e3a44e3 |
g = t.find("./%sgroupId" % ns).text
|
|
William Benton |
e3a44e3 |
v = t.find("./%sversion" % ns).text
|
|
William Benton |
e3a44e3 |
return k(a, g, v)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def contains(self, substrings):
|
|
William Benton |
e3a44e3 |
for s in substrings:
|
|
William Benton |
e3a44e3 |
if s in self.artifact or s in self.group:
|
|
William Benton |
e3a44e3 |
cn_debug("ignoring %r because it contains %s" % (self, s))
|
|
William Benton |
e3a44e3 |
return True
|
|
William Benton |
e3a44e3 |
if len(substrings) > 0:
|
|
William Benton |
e3a44e3 |
cn_debug("not ignoring %r; looked for %r" % (self, substrings))
|
|
William Benton |
e3a44e3 |
return False
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def __repr__(self):
|
|
William Benton |
e3a44e3 |
return "%s:%s:%s" % (self.group, self.artifact, self.version)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
class DummyPOM(object):
|
|
William Benton |
e3a44e3 |
def __init__(self, groupID=None, artifactID=None, version=None):
|
|
William Benton |
e3a44e3 |
self.groupID = groupID
|
|
William Benton |
e3a44e3 |
self.artifactID = artifactID
|
|
William Benton |
e3a44e3 |
self.version = version
|
|
William Benton |
e3a44e3 |
self.deps = []
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def interestingDep(dt, namespace):
|
|
William Benton |
e3a44e3 |
if len(dt.findall("./%soptional" % namespace)) != 0:
|
|
William Benton |
e3a44e3 |
cn_debug("ignoring optional dep %r" % Artifact.fromSubtree(dt, namespace))
|
|
William Benton |
e3a44e3 |
return False
|
|
William Benton |
e3a44e3 |
if [e for e in dt.findall("./%sscope" % namespace) if e.text == "test"] != []:
|
|
William Benton |
e3a44e3 |
cn_debug("ignoring test dep %r" % Artifact.fromSubtree(dt, namespace))
|
|
William Benton |
e3a44e3 |
return False
|
|
William Benton |
e3a44e3 |
return True
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
class POM(object):
|
|
William Benton |
e3a44e3 |
def __init__(self, filename, suppliedGroupID=None, suppliedArtifactID=None, ignored_deps=[], override=None, extra_deps=[]):
|
|
William Benton |
e3a44e3 |
self.filename = filename
|
|
William Benton |
e3a44e3 |
self.sGroupID = suppliedGroupID
|
|
William Benton |
e3a44e3 |
self.sArtifactID = suppliedArtifactID
|
|
William Benton |
e3a44e3 |
self.logger = logging.getLogger("com.freevariable.climbing-nemesis")
|
|
William Benton |
e3a44e3 |
self.deps = []
|
|
William Benton |
e3a44e3 |
self.ignored_deps = ignored_deps
|
|
William Benton |
e3a44e3 |
self.extra_deps = extra_deps
|
|
William Benton |
e3a44e3 |
cn_debug("POM: extra_deps is %r" % extra_deps)
|
|
William Benton |
e3a44e3 |
self._parsePom()
|
|
William Benton |
e3a44e3 |
self.claimedGroup, self.claimedArtifact = override is not None and override or (self.groupID, self.artifactID)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def _parsePom(self):
|
|
William Benton |
e3a44e3 |
tree = ET.parse(self.filename)
|
|
William Benton |
e3a44e3 |
project = tree.getroot()
|
|
William Benton |
e3a44e3 |
self.logger.info("parsing POM %s", self.filename)
|
|
William Benton |
e3a44e3 |
self.logger.debug("project tag is '%s'", project.tag)
|
|
William Benton |
e3a44e3 |
tagmatch = re.match("[{](.*)[}].*", project.tag)
|
|
William Benton |
e3a44e3 |
namespace = tagmatch and "{%s}" % tagmatch.groups()[0] or ""
|
|
William Benton |
e3a44e3 |
self.logger.debug("looking for '%s'", ("./%sgroupId" % namespace))
|
|
William Benton |
e3a44e3 |
groupIDtag = project.find("./%sgroupId" % namespace)
|
|
William Benton |
e3a44e3 |
if groupIDtag is None:
|
|
William Benton |
e3a44e3 |
groupIDtag = project.find("./%sparent/%sgroupId" % (namespace,namespace))
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
versiontag = project.find("./%sversion" % namespace)
|
|
William Benton |
e3a44e3 |
if versiontag is None:
|
|
William Benton |
e3a44e3 |
versiontag = project.find("./%sparent/%sversion" % (namespace,namespace))
|
|
William Benton |
e3a44e3 |
self.logger.debug("group ID tag is '%s'", groupIDtag)
|
|
William Benton |
e3a44e3 |
self.groupID = groupIDtag.text
|
|
William Benton |
e3a44e3 |
self.artifactID = project.find("./%sartifactId" % namespace).text
|
|
William Benton |
e3a44e3 |
self.version = versiontag.text
|
|
William Benton |
e3a44e3 |
depTrees = project.findall(".//%sdependencies/%sdependency" % (namespace, namespace))
|
|
William Benton |
e3a44e3 |
alldeps = [Artifact.fromSubtree(depTree, namespace) for depTree in depTrees if interestingDep(depTree, namespace)]
|
|
William Benton |
e3a44e3 |
alldeps = [dep for dep in alldeps if not (dep.group == self.groupID and dep.artifact == self.artifactID)]
|
|
William Benton |
e3a44e3 |
self.deps = [dep for dep in alldeps if not dep.contains(self.ignored_deps)] + [Artifact.fromCoords(xtra) for xtra in self.extra_deps]
|
|
William Benton |
e3a44e3 |
jarmatch = re.match(".*JPP-(.*).pom", self.filename)
|
|
William Benton |
e3a44e3 |
self.jarname = (jarmatch and jarmatch.groups()[0] or None)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def cn_debug(*args):
|
|
William Benton |
e3a44e3 |
logging.getLogger("com.freevariable.climbing-nemesis").debug(*args)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def cn_info(*args):
|
|
William Benton |
e3a44e3 |
logging.getLogger("com.freevariable.climbing-nemesis").info(*args)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def resolveArtifact(group, artifact, pomfile=None, kind="jar", ignored_deps=[], override=None, extra_deps=[]):
|
|
William Benton |
e3a44e3 |
# XXX: some error checking would be the responsible thing to do here
|
|
William Benton |
e3a44e3 |
cn_debug("rA: extra_deps is %r" % extra_deps)
|
|
William Benton |
e3a44e3 |
if pomfile is None:
|
|
William Benton |
e3a44e3 |
try:
|
|
William Benton |
e3a44e3 |
if getFedoraRelease() > 19:
|
|
William Benton |
e3a44e3 |
[pom] = subprocess.check_output(["xmvn-resolve", "%s:%s:pom:%s" % (group, artifact, kind)]).split()
|
|
William Benton |
e3a44e3 |
else:
|
|
William Benton |
e3a44e3 |
[pom] = subprocess.check_output(["xmvn-resolve", "%s:%s:%s" % (group, artifact, kind)]).split()
|
|
William Benton |
e3a44e3 |
return POM(pom, ignored_deps=ignored_deps, override=override, extra_deps=extra_deps)
|
|
William Benton |
e3a44e3 |
except:
|
|
William Benton |
e3a44e3 |
return DummyPOM(group, artifact)
|
|
William Benton |
e3a44e3 |
else:
|
|
William Benton |
e3a44e3 |
return POM(pomfile, ignored_deps=ignored_deps, override=override, extra_deps=extra_deps)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def resolveArtifacts(identifiers):
|
|
William Benton |
e3a44e3 |
coords = ["%s:%s:jar" % (group, artifact) for (group, artifact) in identifiers]
|
|
William Benton |
e3a44e3 |
poms = subprocess.check_output(["xmvn-resolve"] + coords).split()
|
|
William Benton |
e3a44e3 |
return [POM(pom) for pom in poms]
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def resolveJar(group, artifact):
|
|
William Benton |
e3a44e3 |
[jar] = subprocess.check_output(["xmvn-resolve", "%s:%s:jar:jar" % (group, artifact)]).split()
|
|
William Benton |
e3a44e3 |
return jar
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def makeIvyXmlTree(org, module, revision, status="release", meta={}, deps=[]):
|
|
William Benton |
e3a44e3 |
ivy_module = ET.Element("ivy-module", {"version":"1.0", "xmlns:e":"http://ant.apache.org/ivy/extra"})
|
|
William Benton |
e3a44e3 |
info = ET.SubElement(ivy_module, "info", dict({"organisation":org, "module":module, "revision":revision, "status":status}.items() + meta.items()))
|
|
William Benton |
e3a44e3 |
info.text = " " # ensure a close tag
|
|
William Benton |
e3a44e3 |
confs = ET.SubElement(ivy_module, "configurations")
|
|
William Benton |
e3a44e3 |
for conf in ["default", "provided", "test"]:
|
|
William Benton |
e3a44e3 |
ET.SubElement(confs, "conf", {"name":conf})
|
|
William Benton |
e3a44e3 |
pubs = ET.SubElement(ivy_module, "publications")
|
|
William Benton |
e3a44e3 |
ET.SubElement(pubs, "artifact", {"name":module, "type":"jar"})
|
|
William Benton |
e3a44e3 |
if len(deps) > 0:
|
|
William Benton |
e3a44e3 |
deptree = ET.SubElement(ivy_module, "dependencies")
|
|
William Benton |
e3a44e3 |
for dep in deps:
|
|
William Benton |
e3a44e3 |
ET.SubElement(deptree, "dependency", {"org":dep.group, "name":dep.artifact, "rev":dep.version})
|
|
William Benton |
e3a44e3 |
return ET.ElementTree(ivy_module)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def writeIvyXml(org, module, revision, status="release", fileobj=None, meta={}, deps=[]):
|
|
William Benton |
e3a44e3 |
# XXX: handle deps!
|
|
William Benton |
e3a44e3 |
if fileobj is None:
|
|
William Benton |
e3a44e3 |
fileobj = StringIO.StringIO()
|
|
William Benton |
e3a44e3 |
tree = makeIvyXmlTree(org, module, revision, status, meta=meta, deps=deps)
|
|
William Benton |
e3a44e3 |
tree.write(fileobj, xml_declaration=True)
|
|
William Benton |
e3a44e3 |
return fileobj
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def ivyXmlAsString(org, module, revision, status, meta={}, deps=[]):
|
|
William Benton |
e3a44e3 |
return writeIvyXml(org, module, revision, status, meta=meta, deps=deps).getvalue()
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def placeArtifact(artifact_file, repo_dirname, org, module, revision, status="release", meta={}, deps=[], supplied_ivy_file=None, scala=None, override=None, override_dir_only=False):
|
|
William Benton |
e3a44e3 |
if scala is not None:
|
|
William Benton |
e3a44e3 |
module = module + "_%s" % scala
|
|
William Benton |
e3a44e3 |
jarmodule = module
|
|
William Benton |
e3a44e3 |
if override is not None:
|
|
William Benton |
e3a44e3 |
org, module = override
|
|
William Benton |
e3a44e3 |
if not override_dir_only:
|
|
William Benton |
e3a44e3 |
jarmodule = module
|
|
William Benton |
e3a44e3 |
repo_dir = realpath(repo_dirname)
|
|
William Benton |
e3a44e3 |
artifact_dir = pathjoin(*[repo_dir] + [org] + [module, revision])
|
|
William Benton |
e3a44e3 |
ivyxml_path = pathjoin(artifact_dir, "ivy.xml")
|
|
William Benton |
e3a44e3 |
artifact_repo_path = pathjoin(artifact_dir, "%s-%s.jar" % (jarmodule, revision))
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
if not pathexists(artifact_dir):
|
|
William Benton |
e3a44e3 |
makedirs(artifact_dir)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
ivyxml_file = open(ivyxml_path, "w")
|
|
William Benton |
e3a44e3 |
if supplied_ivy_file is None:
|
|
William Benton |
e3a44e3 |
writeIvyXml(org, module, revision, status, ivyxml_file, meta=meta, deps=deps)
|
|
William Benton |
e3a44e3 |
else:
|
|
William Benton |
e3a44e3 |
copyfile(supplied_ivy_file, ivyxml_path)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
if pathexists(artifact_repo_path):
|
|
William Benton |
e3a44e3 |
rmfile(artifact_repo_path)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
symlink(artifact_file, artifact_repo_path)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def getFedoraRelease():
|
|
William Benton |
e3a44e3 |
cmd = "rpm -q --qf %{version} fedora-release"
|
|
William Benton |
e3a44e3 |
return int(subprocess.check_output(cmd.split()))
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
def main():
|
|
William Benton |
e3a44e3 |
parser = argparse.ArgumentParser(description="Place a locally-installed artifact in a custom local Ivy repository; get metadata from Maven")
|
|
William Benton |
e3a44e3 |
parser.add_argument("group", metavar="GROUP", type=str, help="name of group")
|
|
William Benton |
e3a44e3 |
parser.add_argument("artifact", metavar="ARTIFACT", type=str, help="name of artifact")
|
|
William Benton |
e3a44e3 |
parser.add_argument("repodir", metavar="REPO", type=str, help="location for local repo")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--version", metavar="VERSION", type=str, help="version to advertise this artifact as, overriding Maven metadata")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--meta", metavar="K=V", type=str, help="extra metadata to store in ivy.xml", action='append')
|
|
William Benton |
e3a44e3 |
parser.add_argument("--jarfile", metavar="JAR", type=str, help="local jar file (use instead of POM metadata")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--pomfile", metavar="POM", type=str, help="local pom file (use instead of xmvn-resolved one")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--log", metavar="LEVEL", type=str, help="logging level")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--ivyfile", metavar="IVY", type=str, help="supplied Ivy file (use instead of POM metadata)")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--scala", metavar="VERSION", type=str, help="encode given scala version in artifact name")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--ignore", metavar="STR", type=str, help="ignore dependencies whose artifact or group contains str", action='append')
|
|
William Benton |
e3a44e3 |
parser.add_argument("--override", metavar="ORG:NAME", type=str, help="override organization and/or artifact name")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--override-dir-only", action='store_true', help="override organization and/or artifact name")
|
|
William Benton |
e3a44e3 |
parser.add_argument("--extra-dep", metavar="ORG:NAME:VERSION", action='append', help="add the given dependencya")
|
|
William Benton |
e3a44e3 |
args = parser.parse_args()
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
if args.log is not None:
|
|
William Benton |
e3a44e3 |
logging.basicConfig(level=getattr(logging, args.log.upper()))
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
override = args.override and args.override.split(":") or None
|
|
William Benton |
e3a44e3 |
cn_debug("cl: args.extra_dep is %r" % args.extra_dep)
|
|
William Benton |
e3a44e3 |
extra_deps = args.extra_dep is not None and args.extra_dep or []
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
pom = resolveArtifact(args.group, args.artifact, args.pomfile, "jar", ignored_deps=(args.ignore or []), override=((not args.override_dir_only) and override or None), extra_deps=extra_deps)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
if args.jarfile is None:
|
|
William Benton |
e3a44e3 |
jarfile = resolveJar(pom.groupID or args.group, pom.artifactID or args.artifact)
|
|
William Benton |
e3a44e3 |
else:
|
|
William Benton |
e3a44e3 |
jarfile = args.jarfile
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
version = (args.version or pom.version)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
meta = dict([kv.split("=") for kv in (args.meta or [])])
|
|
William Benton |
e3a44e3 |
cn_debug("meta is %r" % meta)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
placeArtifact(jarfile, args.repodir, pom.groupID, pom.artifactID, version, meta=meta, deps=pom.deps, supplied_ivy_file=args.ivyfile, scala=args.scala, override=override, override_dir_only=args.override_dir_only)
|
|
William Benton |
e3a44e3 |
|
|
William Benton |
e3a44e3 |
if __name__ == "__main__":
|
|
William Benton |
e3a44e3 |
main()
|