add support for inline module source and build objects
authorMathieu Lacage <mathieu.lacage@inria.fr>
Mon, 28 Mar 2011 09:27:10 +0200
changeset 8 22723c848b28
parent 7 be7ceee49db9
child 9 23b2b96ba147
add support for inline module source and build objects
TODO
bake/Configuration.py
bake/Module.py
bake/ModuleBuild.py
bake/ModuleSource.py
examples/ns3/bakeconf.xml
examples/numesis/bakeconf.xml
--- a/TODO	Sat Mar 26 14:24:21 2011 +0100
+++ b/TODO	Mon Mar 28 09:27:10 2011 +0200
@@ -3,6 +3,7 @@
 * check build tool versions !
 * pass around -j X
 * compressed 'bake' binary
+* implement 'inline' source/build module
 
 * missing commands:
   - diff in ModuleSource
--- a/bake/Configuration.py	Sat Mar 26 14:24:21 2011 +0100
+++ b/bake/Configuration.py	Mon Mar 28 09:27:10 2011 +0200
@@ -1,6 +1,6 @@
 from Module import Module,ModuleDependency
-from ModuleSource import ModuleSource
-from ModuleBuild import ModuleBuild
+from ModuleSource import ModuleSource,InlineModuleSource
+from ModuleBuild import ModuleBuild,InlineModuleBuild
 import xml.etree.ElementTree as ET
 from Exceptions import MetadataError
 import os
@@ -57,7 +57,7 @@
         # now, read the attributes from file.
         for attribute_node in top_level_node.findall('attribute'):
             attr_name = attribute_node.get('name')
-            attr_value = attribute_node.get('value')
+            attr_value = attribute_node.get('value', None)
             if attribute_base.attribute(attr_name) is None:
                 sys.stderr.write('Error: attribute "%s" is not supported by %s node of type "%s"\n' % 
                                  (attr_name, type_string, top_level_node.get('type')))
@@ -71,6 +71,32 @@
                                                 'value' : attribute.value})
                 top_level_node.append(node)
 
+    def _create_obj_from_node(self, node, classBase):
+        if node.get('type') == 'inline':
+            code_node = node.find('code')
+            if node is None:
+                sys.stderr.write('Error: no code tag in in inline module\n')
+                sys.exit(1)
+            classname = node.get('classname')
+            import codeop
+            exec code_node.text in globals(), locals()
+            obj = eval(classname + '()')
+            obj.__hidden_source_code = code_node.text
+        else:
+            obj = classBase.create(node.get('type'))
+        return obj
+
+    def _create_node_from_obj(self, obj, node_string):
+        if obj.__class__.name() == 'inline':
+            node = ET.Element(node_string, {'type' : 'inline',
+                                            'classname' : obj.__class__.__name__})
+            code = ET.Element('code')
+            code.text = obj.__hidden_source_code
+            node.append(code)
+        else:
+            node = ET.Element(node_string, {'type' : obj.__class__.name()})
+        return node
+        
 
     def _read_metadata(self, et):
         # function designed to be called on two kinds of xml files.
@@ -80,12 +106,12 @@
             version = module_node.get('version', None)
 
             source_node = module_node.find('source')
-            source = ModuleSource.create(source_node.get('type'))
+            source = self._create_obj_from_node(source_node, ModuleSource)
             self._check_mandatory_attributes(source, source_node, 'source', name)
             self._read_attributes(source, source_node, 'source', name)
 
             build_node = module_node.find('build')
-            build = ModuleBuild.create(build_node.get('type'))
+            build = self._create_obj_from_node(build_node, ModuleBuild)
             self._check_mandatory_attributes(build, build_node, 'build', name)
             self._read_attributes(source, source_node, 'build', name)
 
@@ -107,11 +133,11 @@
                 module_attrs['version'] = module.version()
             module_node = ET.Element('module', module_attrs)
 
-            source_node = ET.Element('source', {'type' : module.get_source().__class__.name()})
+            source_node = self._create_node_from_obj(module.get_source(), 'source')
             self._write_attributes(module.get_source(), source_node)
             module_node.append(source_node)
 
-            build_node = ET.Element('build', {'type' : module.get_build().__class__.name()})
+            build_node = self._create_node_from_obj(module.get_build(), 'build')
             self._write_attributes(module.get_build(), build_node)
             module_node.append(build_node)
             
--- a/bake/Module.py	Sat Mar 26 14:24:21 2011 +0100
+++ b/bake/Module.py	Mon Mar 28 09:27:10 2011 +0200
@@ -38,7 +38,7 @@
         if os.path.isdir(dirname):
             return True
         try:
-            self._source.download(logger, dirname)
+            self._source.download(logger, sourcedir, dirname)
             return True
         except:
             import Utils
@@ -57,7 +57,10 @@
 
     def build(self, logger, sourcedir, objdir, installdir):
         src = os.path.join(sourcedir, self._directory())
-        obj = os.path.join(src,objdir)
+        if self._build.attribute('objdir').value == 'srcdir':
+            obj = src
+        else:
+            obj = os.path.join(src, objdir)
         try:
             # delete in case this is a new build configuration
             # and there are old files around
--- a/bake/ModuleBuild.py	Sat Mar 26 14:24:21 2011 +0100
+++ b/bake/ModuleBuild.py	Mon Mar 28 09:27:10 2011 +0200
@@ -5,6 +5,9 @@
 class ModuleBuild(ModuleAttributeBase):
     def __init__(self):
         ModuleAttributeBase.__init__(self)
+        self.add_attribute('objdir', 'srcdir', 
+                           'Does this module support building in objdir != srcdir ? '
+                           'Defaults to objdir == srcdir. ')
     @classmethod
     def create(cls, name):
         for subclass in ModuleBuild.__subclasses__():
@@ -21,12 +24,19 @@
         ModuleBuild.__init__(self)
     @classmethod
     def name(cls):
-        return 'none-build'
+        return 'none'
     def build(self, logger, srcdir, blddir, installdir):
         pass
     def clean(self, logger, srcdir, blddir):
         pass
 
+class InlineModuleBuild(ModuleBuild):
+    def __init__(self):
+        ModuleBuild.__init__(self)
+    @classmethod
+    def name(cls):
+        return 'inline'
+
 class Cmake(ModuleBuild):
     def __init__(self):
         ModuleBuild.__init__(self)
@@ -68,9 +78,6 @@
         self.add_attribute('CFLAGS',   '', 'Flags to use for C compiler')
         self.add_attribute('CXXFLAGS', '', 'Flags to use for C++ compiler')
         self.add_attribute('LDFLAGS',  '', 'Flags to use for Linker')
-        self.add_attribute('blddir',   'srcdir', 
-                           'Does this module support building in blddir != srcdir ? '
-                           'Defaults to blddir == srcdir. ')
         self.add_attribute('maintainer', 'no', 'Maintainer mode ?')
     @classmethod
     def name(cls):
@@ -79,8 +86,6 @@
         if self.attribute('maintainer').value != 'no':
             Utils.run_command(['autoreconf', '--install'], logger,
                         directory = srcdir)
-        if self.attribute('blddir').value == 'srcdir':
-            blddir = srcdir
         Utils.run_command([os.path.join(srcdir, 'configure'),
                            '--prefix=' + installdir, 
                            'CC=' + self.attribute('CC').value,
--- a/bake/ModuleSource.py	Sat Mar 26 14:24:21 2011 +0100
+++ b/bake/ModuleSource.py	Mon Mar 28 09:27:10 2011 +0200
@@ -13,7 +13,7 @@
         return None
     def diff(self, logger, directory):
         raise NotImplemented()
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         raise NotImplemented()
     def update(self, logger, directory):
         raise NotImplemented()
@@ -23,14 +23,21 @@
         ModuleSource.__init__(self)
     @classmethod
     def name(cls):
-        return 'none-source'
+        return 'none'
     def diff(self, logger, directory):
         pass
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         pass
     def update(self, logger, directory):
         pass
 
+class InlineModuleSource(ModuleSource):
+    def __init__(self):
+        ModuleSource.__init__(self)
+    @classmethod
+    def name(cls):
+        return 'inline'
+
 class BazaarModuleSource(ModuleSource):
     def __init__(self):
         ModuleSource.__init__(self)
@@ -42,7 +49,7 @@
         return 'bazaar'
     def diff(self, logger, directory):
         pass
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         rev_arg = []
         if not self.attribute('revision').value is None:
             rev_arg.extend(['-r', self.attribute('revision').value])
@@ -63,7 +70,7 @@
     @classmethod
     def name(cls):
         return 'mercurial'
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         Utils.run_command(['hg', 'clone', '-U', self.attribute('url').value, directory],
                           logger)
         Utils.run_command(['hg', 'update', '-r', self.attribute('revision').value],
@@ -110,14 +117,12 @@
                 return
         raise TaskError('Unknown Archive Type')
 
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         import urllib
         import urlparse
         import os
-        import tempfile
-        tempdir = tempfile.mkdtemp()
         filename = os.path.basename(urlparse.urlparse(self.attribute('url').value).path)
-        tmpfile = os.path.join(tempdir,filename)
+        tmpfile = os.path.join(sourcedir,filename)
         logger.write ('downloading ' + self.attribute('url').value + ' as ' + tmpfile + '\n')
         urllib.urlretrieve(self.attribute('url').value, filename=tmpfile)
         self._decompress(tmpfile, logger, directory)
@@ -138,7 +143,7 @@
     @classmethod
     def name(cls):
         return 'cvs'
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         import tempfile
         tempdir = tempfile.mkdtemp()
         Utils.run_command(['cvs', '-d', self.attribute('root').value, 'login'],
@@ -166,7 +171,7 @@
     @classmethod
     def name(cls):
         return 'git'
-    def download(self, logger, directory):
+    def download(self, logger, sourcedir, directory):
         import tempfile
         import os
         tempdir = tempfile.mkdtemp()
--- a/examples/ns3/bakeconf.xml	Sat Mar 26 14:24:21 2011 +0100
+++ b/examples/ns3/bakeconf.xml	Mon Mar 28 09:27:10 2011 +0200
@@ -6,21 +6,35 @@
      <attribute name="revision" value="revno:777"/>
 <!--     <attribute name="revision" value="tag:0.15.0"/> -->
     </source>
-    <build type="none-build"/>
+    <build type="none"/>
   </module>
 
-  <module name="nsc" version="">
+  <module name="nsc">
     <source type="mercurial">
       <attribute name="url" value="https://secure.wand.net.nz/mercurial/nsc"/>
     </source>
-    <build type="none-build"/>
+<!-- problem: scons has no generic command-line support for builddir and installdir -->
+    <build type="inline"  classname="NscModuleBuild">
+<code>
+class NscModuleBuild(InlineModuleBuild):
+    def __init__(self):
+        InlineModuleBuild.__init__(self)
+    def build(self, logger, srcdir, blddir, installdir):
+        import Utils
+        Utils.run_command(['scons', '--prefix=' + installdir, 'install'], 
+                          logger, directory=srcdir)
+    def clean(self, logger, srcdir, blddir):
+        # XXX
+        pass
+</code>
+    </build>
   </module>
 
   <module name="iproute2" version="2.6.33">
     <source type="archive">
      <attribute name="url" value="http://devresources.linuxfoundation.org/dev/iproute2/download/iproute2-2.6.33.tar.bz2"/>
     </source>
-    <build type="none-build"/>
+    <build type="none"/>
   </module>
 
   <module name="net-next-2.6">
@@ -29,7 +43,7 @@
       <attribute name="url" value="file:///home/mathieu/code/ns-3-linux/net-next-2.6"/>
       <attribute name="revision" value="fed66381d65a35198639f564365e61a7f256bf79"/>
     </source>
-    <build type="none-build"/>
+    <build type="none"/>
   </module>
 
   <module name="ns-3-linux" version="0.1">
@@ -38,7 +52,7 @@
     </source>
     <depends_on name="net-next-2.6"/>
     <depends_on name="iproute2"/>
-    <build type="none-build"/>
+    <build type="none"/>
   </module>
 
   <module name="gdb" version="cvs">
@@ -47,9 +61,9 @@
       <attribute name="module" value="gdb"/>
       <attribute name="checkout_directory" value="src"/>
     </source>
-    <!-- <build type="autotools" blddir="srcdir"/> -->
+    <!-- <build type="autotools" objdir="srcdir"/> -->
     <build type="autotools">
-      <attribute name="blddir" value="any"/>
+      <attribute name="objdir" value="any"/>
     </build>
   </module>
 
@@ -59,7 +73,8 @@
     </source>
     <depends_on name="ns-3-linux" optional="True"/>
     <depends_on name="gdb" optional="True"/>
-    <build type="none-build"/>
+    <depends_on name="nsc" optional="True"/>
+    <build type="none"/>
   </module>
 
 </modules>
--- a/examples/numesis/bakeconf.xml	Sat Mar 26 14:24:21 2011 +0100
+++ b/examples/numesis/bakeconf.xml	Mon Mar 28 09:27:10 2011 +0200
@@ -5,6 +5,8 @@
      <attribute name="revision" value="refs/remotes/origin/master"/>
 <!--     <attribute name="revision" value="b741f29"/> -->
     </source>
-    <build type="cmake" version="2.8"/>
+    <build type="cmake" version="2.8">
+      <attribute name="objdir" value="any"/>
+    </build>
   </module>
 </modules>