changeset 8131:83ec1df0a30f

added support for distributions to mx added GRAAL distribution to create graal.jar in top level directory
author Doug Simon <doug.simon@oracle.com>
date Wed, 06 Mar 2013 16:59:10 +0100
parents 22bbd34705ed
children 394f685c1502
files mx/projects mxtool/mx.py
diffstat 2 files changed, 113 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/mx/projects	Wed Mar 06 13:24:11 2013 +0100
+++ b/mx/projects	Wed Mar 06 16:59:10 2013 +0100
@@ -22,6 +22,9 @@
 library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 
+distribution@GRAAL@path=graal.jar
+distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc
+
 # graal.api.runtime
 project@com.oracle.graal.api.runtime@subDir=graal
 project@com.oracle.graal.api.runtime@sourceDirs=src
--- a/mxtool/mx.py	Wed Mar 06 13:24:11 2013 +0100
+++ b/mxtool/mx.py	Wed Mar 06 16:59:10 2013 +0100
@@ -143,12 +143,28 @@
 
 _projects = dict()
 _libs = dict()
+_dists = dict()
 _suites = dict()
 _mainSuite = None
 _opts = None
 _java = None
 
 """
+A distribution is a jar or zip file containing the output from one or more Java projects.
+"""
+class Distribution:
+    def __init__(self, suite, name, path, deps):
+        self.suite = suite
+        self.name = name
+        self.path = path.replace('/', os.sep)
+        if not isabs(self.path):
+            self.path = join(suite.dir, self.path)
+        self.deps = deps
+        
+    def __str__(self):
+        return self.name
+    
+"""
 A dependency is a library or project specified in a suite.
 """
 class Dependency:
@@ -416,6 +432,7 @@
         self.dir = d
         self.projects = []
         self.libs = []
+        self.dists = []
         self.includes = []
         self.commands = None
         self.primary = primary
@@ -427,6 +444,7 @@
     def _load_projects(self, mxDir):
         libsMap = dict()
         projsMap = dict()
+        distsMap = dict()
         projectsFile = join(mxDir, 'projects')
         if not exists(projectsFile):
             return
@@ -447,8 +465,10 @@
                         m = projsMap
                     elif kind == 'library':
                         m = libsMap
+                    elif kind == 'distribution':
+                        m = distsMap
                     else:
-                        abort('Property name does not start with "project@" or "library@": ' + key)
+                        abort('Property name does not start with "project@", "library@" or "distribution@": ' + key)
 
                     attrs = m.get(name)
                     if attrs is None:
@@ -494,6 +514,13 @@
             l.__dict__.update(attrs)
             self.libs.append(l)
 
+        for name, attrs in distsMap.iteritems():
+            path = attrs.pop('path')
+            deps = pop_list(attrs, 'dependencies')
+            d = Distribution(self, name, path, deps)
+            d.__dict__.update(attrs)
+            self.dists.append(d)
+
     def _load_commands(self, mxDir):
         commands = join(mxDir, 'commands.py')
         if exists(commands):
@@ -549,6 +576,11 @@
             if existing is not None:
                 abort('cannot redefine library  ' + l.name)
             _libs[l.name] = l
+        for d in self.dists:
+            existing = _dists.get(l.name)
+            if existing is not None:
+                abort('cannot redefine distribution  ' + d.name)
+            _dists[d.name] = d
 
 class XMLElement(xml.dom.minidom.Element):
     def writexml(self, writer, indent="", addindent="", newl=""):
@@ -653,6 +685,16 @@
     """
     return _projects.values()
 
+def distribution(name, fatalIfMissing=True):
+    """
+    Get the distribution for a given name. This will abort if the named distribution does
+    not exist and 'fatalIfMissing' is true.
+    """
+    d = _dists.get(name)
+    if d is None and fatalIfMissing:
+        abort('distribution named ' + name + ' not found')
+    return d
+
 def project(name, fatalIfMissing=True):
     """
     Get the project for a given name. This will abort if the named project does
@@ -1477,6 +1519,9 @@
         finally:
             for n in toBeDeleted:
                 os.remove(n)
+                
+    for dist in _dists.values():
+        archive(['@' + dist.name])
 
     if suppliedParser:
         return args
@@ -1578,7 +1623,7 @@
     projects = set()
     
     for p in sorted_deps():
-        if _needsEclipseJarBuild(p):
+        if _isAnnotationProcessorDependency(p):
             projects.add(p)
             
     if len(projects) <= 0:
@@ -1586,37 +1631,38 @@
     
     pnames = [p.name for p in projects]
     build(['--projects', ",".join(pnames)])
-    jarprojects(pnames)
-
-def jarprojects(args):
-    """create jar files for the output of one or more projects"""
-    parser = ArgumentParser(prog='mx jar');
-    parser.add_argument('-d', '--dest', help='single jar file to create')
-    parser.add_argument('projects', nargs=REMAINDER, metavar='projects...')
+    archive(pnames)
+
+def archive(args):
+    """create jar files for projects and distributions"""
+    parser = ArgumentParser(prog='mx archive');
+    parser.add_argument('names', nargs=REMAINDER, metavar='[<project>|@<distribution>]...')
     args = parser.parse_args(args)
     
-    if not args.projects:
-        args.projects = [p.name for p in projects()]
-
-    if args.dest is not None:
-        zf = zipfile.ZipFile(args.dest, 'w')
-    
-    for pname in args.projects:
-        p = project(pname, fatalIfMissing=True)
-        if args.dest is None:
+    for name in args.names:
+        if name.startswith('@'):
+            dname = name[1:]
+            d = distribution(dname)
+            zf = zipfile.ZipFile(d.path, 'w')
+            for p in sorted_deps(d.deps):
+                outputDir = p.output_dir()
+                for root, _, files in os.walk(outputDir):
+                    for f in files:
+                        relpath = root[len(outputDir) + 1:]
+                        arcname = join(relpath, f).replace(os.sep, '/')
+                        zf.write(join(root, f), arcname)
+            zf.close()
+        else:
+            p = project(name)
+            outputDir = p.output_dir()
             jar = join(p.dir, p.name + '.jar')
             zf = zipfile.ZipFile(jar, 'w')
-        outputDir = p.output_dir()
-        for root, _, files in os.walk(outputDir):
-            for f in files:
-                relpath = root[len(outputDir) + 1:]
-                arcname = join(relpath, f).replace(os.sep, '/')
-                zf.write(join(root, f), arcname)
-        if args.dest is None:
+            for root, _, files in os.walk(outputDir):
+                for f in files:
+                    relpath = root[len(outputDir) + 1:]
+                    arcname = join(relpath, f).replace(os.sep, '/')
+                    zf.write(join(root, f), arcname)
             zf.close()
-            
-    if args.dest is not None:
-        zf.close()
 
 def canonicalizeprojects(args):
     """process all project files to canonicalize the dependencies
@@ -1996,6 +2042,12 @@
     if buildProcessorJars:
         processorjars()
 
+    projToDist = dict()
+    for dist in _dists.values():
+        distDeps = sorted_deps(dist.deps)
+        for p in distDeps:
+            projToDist[p.name] = (dist, [dep.name for dep in distDeps])
+
     for p in projects():
         if p.native:
             continue
@@ -2110,24 +2162,14 @@
                 out.element('arguments', data='')
                 out.close('buildCommand')
 
-        if (_needsEclipseJarBuild(p)):
-            targetValues = _genEclipseJarBuild(p);
-            for value in targetValues:
-                out.open('buildCommand')
-                out.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder')
-                out.element('triggers', data='auto,full,incremental,')
-                out.open('arguments')
-                out.open('dictionary')
-                out.element('key', data = 'LaunchConfigHandle')
-                out.element('value', data = value)
-                out.close('dictionary')
-                out.open('dictionary')
-                out.element('key', data = 'incclean')
-                out.element('value', data = 'true')
-                out.close('dictionary')
-                out.close('arguments')
-                out.close('buildCommand')       
-                    
+        if _isAnnotationProcessorDependency(p):
+            _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False)
+            _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh = True, async = True)
+                       
+        if projToDist.has_key(p.name):
+            dist, distDeps = projToDist[p.name]
+            _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist.launch', 'archive @' + dist.name, refresh=False, async=True)
+        
         out.close('buildSpec')
         out.open('natures')
         out.element('nature', data='org.eclipse.jdt.core.javanature')
@@ -2182,8 +2224,11 @@
     make_eclipse_attach('localhost', '8000', deps=projects())
 
 
-def _needsEclipseJarBuild(p):
-    processors = set([])
+def _isAnnotationProcessorDependency(p):
+    """
+    Determines if a given project is part of an annotation processor.
+    """
+    processors = set()
     
     for otherProject in projects():
         if hasattr(otherProject, 'annotationProcessors') and len(otherProject.annotationProcessors) > 0:
@@ -2200,13 +2245,7 @@
     
     return False
 
-def _genEclipseJarBuild(p):
-    builders = []
-    builders.append(_genEclipseLaunch(p, 'Jar.launch', ''.join(['jarprojects ', p.name]), refresh = False, async = False))
-    builders.append(_genEclipseLaunch(p, 'Refresh.launch', '', refresh = True, async = True))
-    return builders
-
-def _genEclipseLaunch(p, name, mxCommand, refresh=True, async=False):
+def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False):
     launchOut = XMLDoc();
     launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
     if refresh:
@@ -2236,9 +2275,21 @@
         os.makedirs(externalToolDir)
     update_file(join(externalToolDir, name), launchOut.xml(indent='\t', newl='\n'))
     
-    return ''.join(["<project>/.externalToolBuilders/", name])
-
-
+    dotProjectDoc.open('buildCommand')
+    dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder')
+    dotProjectDoc.element('triggers', data='auto,full,incremental,')
+    dotProjectDoc.open('arguments')
+    dotProjectDoc.open('dictionary')
+    dotProjectDoc.element('key', data = 'LaunchConfigHandle')
+    dotProjectDoc.element('value', data = '<project>/.externalToolBuilders/' + name)
+    dotProjectDoc.close('dictionary')
+    dotProjectDoc.open('dictionary')
+    dotProjectDoc.element('key', data = 'incclean')
+    dotProjectDoc.element('value', data = 'true')
+    dotProjectDoc.close('dictionary')
+    dotProjectDoc.close('arguments')
+    dotProjectDoc.close('buildCommand')
+    
 def netbeansinit(args, suite=None):
     """(re)generate NetBeans project configurations"""
 
@@ -2956,7 +3007,7 @@
     'help': [help_, '[command]'],
     'ideclean': [ideclean, ''],
     'ideinit': [ideinit, ''],
-    'jarprojects': [jarprojects, '[options]'],
+    'archive': [archive, '[options]'],
     'projectgraph': [projectgraph, ''],
     'javap': [javap, ''],
     'javadoc': [javadoc, '[options]'],