changeset 3426:632f2ab3cdaf

Move Builder out of gub to builder.py
author Jan Nieuwenhuizen <janneke@gnu.org>
date Fri, 04 May 2007 09:57:19 +0200
parents 6ec2f3d0bb59
children b6d7c063a4f9
files bin/gub gub/builder.py
diffstat 2 files changed, 260 insertions(+), 220 deletions(-) [+]
line wrap: on
line diff
--- a/bin/gub	Fri May 04 09:39:34 2007 +0200
+++ b/bin/gub	Fri May 04 09:57:19 2007 +0200
@@ -20,9 +20,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 """
 
-import os
-import re
-import string
 import sys
 sys.path.insert (0, '.')
 #
@@ -38,9 +35,8 @@
     import optparse
     p = optparse.OptionParser ()
 
-    p.usage='''gub [OPTION]... [PACKAGE]...
+    p.usage='''gub [OPTION]... [PACKAGE]...'''
 
-'''
     p.description='Grand Unified Builder.'
 
     p.add_option ('-B', '--branch', action='append',
@@ -126,223 +122,12 @@
 
     return p
 
-# FIXME: put all these functions that take manager, settings, specs, deps
-# into a 'builder' class?
 
-def pkg_checksum_valid (manager, spec, pkg):
-    name = pkg.name ()
-    pkg_dict = manager.package_dict (name)
-
-    valid = (spec.spec_checksum == pkg_dict['spec_checksum']
-             and spec.source_checksum () == pkg_dict['source_checksum'])
-
-    hdr = pkg.expand ('%(split_hdr)s')
-    valid = valid and os.path.exists (hdr)
-    if valid:
-        import pickle
-        hdr_dict = pickle.load (open (hdr))
-        hdr_sum = hdr_dict['spec_checksum']
-        valid = valid and hdr_sum == spec.spec_checksum
-        valid = valid and spec.source_checksum () == hdr_dict['source_checksum']
-
-    ## let's be lenient for cross pkgs.
-    ## spec.cross_checksum == manager.package_dict(name)['cross_checksum'])
-    return valid
-    
-
-def spec_checksums_valid (manager, spec):
-    valid = True
-    for pkg in spec.get_packages ():
-        valid = valid and pkg_checksum_valid (manager, spec, pkg)
-    return valid
-
-def run_one_builder (options, spec):
-    import inspect
-    available = dict (inspect.getmembers (spec, callable))
-    if options.stage:
-        (available[options.stage]) ()
-        return
-    
-    stages = ['download', 'untar', 'patch',
-              'configure', 'compile', 'install',
-              'src_package', 'package', 'clean']
-
-    if options.offline:
-        stages.remove ('download')
-
-    if not options.build_source:
-        stages.remove ('src_package')
-
-    if options.fresh:
-        try:
-            spec_obj.os_interface.action ('Removing status filex')
-            os.unlink (spec_obj.get_stamp_file ())
-        except OSError:
-            pass
-
-    tainted = False
-    for stage in stages:
-        if (not available.has_key (stage)):
-            continue
-
-        if spec.is_done (stage, stages.index (stage)):
-            tainted = True
-            continue
-
-        spec.os_interface.stage (' *** Stage: %s (%s)\n'
-                                 % (stage, spec.name ()))
-
-        if stage == 'package' and tainted and not options.force_package:
-            msg = spec.expand ('''Compile was continued from previous run.
-Will not package.
-Use
-
-rm %(stamp_file)s
-
-to force rebuild, or
-
---force-package
-
-to skip this check.
-''')
-            spec.os_interface.error (msg)
-            raise 'abort'
-
-
-        if (stage == 'clean'
-            and options.keep_build):
-            os.unlink (spec.get_stamp_file ())
-            continue
-
-        try:
-            (available[stage]) ()
-        except misc.SystemFailed:
-
-            ## failed patch will leave system in unpredictable state.
-            if stage == 'patch':
-                spec.system ('rm %(stamp_file)s')
-
-            raise
-
-        if stage != 'clean':
-            spec.set_done (stage, stages.index (stage))
-
-def spec_conflict_resolution (manager, spec, pkg):
-    pkg_name = pkg.name ()
-    install_candidate = pkg
-    subname = ''
-    if spec.name () != pkg_name:
-        subname = pkg_name.split ('-')[-1]
-    if spec.get_conflict_dict ().has_key (subname):
-        for c in spec.get_conflict_dict ()[subname]:
-            if manager.is_installed (c):
-                print '%(c)s conflicts with %(pkg_name)s' % locals ()
-                conflict_source = manager.source_name (c)
-                # FIXME: implicit provides: foo-* provides foo-core,
-                # should implement explicit provides
-                if conflict_source + '-core' == pkg_name:
-                    print ('  non-core %(conflict_source)s already installed'
-                           % locals ())
-                    print ('    skipping request to install %(pkg_name)s'
-                           % locals ())
-                    install_candidate = None
-                    continue
-                manager.uninstall_package (c)
-    return install_candidate
-
-def pkg_install (manager, spec, pkg):
-    if not manager.is_installed (pkg.name ()):
-        install_candidate = spec_conflict_resolution (manager, spec, pkg)
-        if install_candidate:
-            manager.unregister_package_dict (install_candidate.name ())
-            manager.register_package_dict (install_candidate.dict ())
-            manager.install_package (install_candidate.name ())
-            
-def spec_install (manager, spec):
-    for pkg in spec.get_packages ():
-        pkg_install (manager, spec, pkg)
-
-def spec_build (settings, manager, specs, spec_name):
-    spec = specs[spec_name]
-    all_installed = True
-    for p in spec.get_packages ():
-        all_installed = all_installed and manager.is_installed (p.name ())
-    if all_installed:
-        return
-
-    # ugh, dupe
-    checksum_ok = (settings.options.lax_checksums
-                   or spec_checksums_valid (manager, specs[spec_name]))
-
-    is_installable = misc.forall (manager.is_installable (p.name ())
-                                  for p in spec.get_packages ())
-
-    if (settings.options.stage
-        or not is_installable
-        or not checksum_ok):
-        settings.os_interface.stage ('building package: %s\n' % spec_name)
-        run_one_builder (settings.options, spec)
-
-    # FIXME, spec_install should be stage?
-    if settings.options.stage: # and options.stage != spec_install:
-        return
-
-    # FIXME, spec_install should be stage?
-    spec_install (manager, spec)
-
-def uninstall_outdated_specs (settings, manager, specs, deps):
-    def reverse (lst):
-        list.reverse (lst)
-        return lst
-    for spec_name in reverse (deps[:]):
-        spec = specs[spec_name]
-        # ugh, dupe
-        checksum_ok = (settings.options.lax_checksums
-                       or spec_checksums_valid (manager, specs[spec_name]))
-        for pkg in spec.get_packages ():
-            if (manager.is_installed (pkg.name ())
-                and (not manager.is_installable (pkg.name ())
-                     or not checksum_ok)):
-                manager.uninstall_package (pkg.name ())
-
-def build_source_packages (settings, specs, names):
-    try:
-        manager = gup.get_target_manager (settings)
-
-        ## Todo: have a readonly lock for local platform
-    except locker.LockedError:
-        print 'another build in progress. Skipping.'
-        if settings.options.skip_if_locked:
-            sys.exit (0)
-        raise
-
-    deps = filter (specs.has_key, names)
-
-    PATH = os.environ['PATH']
-    ## cross_prefix is also necessary for building cross packages, such as GCC
-    os.environ['PATH'] = settings.expand ('%(cross_prefix)s/bin:' + PATH,
-                                          locals ())
-
-    ## UGH -> double work, see cross.change_target_packages () ?
-    sdk_pkgs = [p for p in specs.values ()
-                if isinstance (p, gubb.SdkBuildSpec)]
-    cross_pkgs = [p for p in specs.values ()
-                  if isinstance (p, cross.CrossToolSpec)]
-
-    extra_build_deps = [p.name () for p in sdk_pkgs + cross_pkgs]
-    gup.add_packages_to_manager (manager, settings, specs)
-
-    # FIXME: what happens here, move to descriptive function?
-    if not settings.options.stage:
-        uninstall_outdated_specs (settings, manager, specs, deps)
-
-    for spec_name in deps:
-        spec_build (settings, manager, specs, spec_name)
-        
+#FIXME: move to Builder?
 def inspect (settings, files):
     (names, specs) = gup.get_source_packages (settings, files)
     pm = gup.get_target_manager (settings)
-    gup.add_packages_to_manager (pm, settings, specs)
+    gup.add_packages_to_self.manager (pm, settings, specs)
     deps = filter (specs.has_key, names)
 
     for f in files:
@@ -351,7 +136,8 @@
             open (settings.options.inspect_output, 'w').write (v)
         else:
             print v
-        
+
+#FIXME: move to Builder?
 def build (settings, files):
     (names, specs) = gup.get_source_packages (settings, files)
     def get_all_deps (name):
@@ -365,6 +151,7 @@
     deps = gup.topologically_sorted (files, {}, get_all_deps, None)
     settings.os_interface.info ('deps:' + `deps` + '\n')
 
+    import os
     PATH = os.environ['PATH']
     os.environ['PATH'] = settings.expand ('%(local_prefix)s/bin:' + PATH)
 
@@ -382,7 +169,18 @@
     if settings.options.stage:
         names = files
 
-    build_source_packages (settings, specs, names)
+    try:
+        manager = gup.get_target_manager (settings)
+        ## Todo: have a readonly lock for local platform
+    except locker.LockedError:
+        settings.os_interface.error ('another build in progress.  Skipping.')
+        if settings.options.skip_if_locked:
+            sys.exit (0)
+        raise
+
+    from gub import builder
+    b = builder.Builder (manager, settings, specs)
+    b.build_source_packages (names)
 
 def main ():
     cli_parser = get_cli_parser ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gub/builder.py	Fri May 04 09:57:19 2007 +0200
@@ -0,0 +1,242 @@
+"""
+    Copyright (c) 2005--2007
+    Jan Nieuwenhuizen <janneke@gnu.org>
+    Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import sys
+sys.path.insert (0, '.')
+#
+from gub import cross
+## fixme: double use of gub name.
+from gub import gubb
+from gub import misc
+from gub import gup
+
+#FIXME: split spec_* into SpecBuiler?
+class Builder ():
+    def __init__ (self, manager, settings, specs):
+        self.manager = manager
+        self.settings = settings
+        self.specs = specs
+    
+        PATH = os.environ['PATH']
+        ## cross_prefix is also necessary for building cross packages, such as GCC
+        os.environ['PATH'] = self.settings.expand ('%(cross_prefix)s/bin:' + PATH,
+                                              locals ())
+
+        ## UGH -> double work, see cross.change_target_packages () ?
+        sdk_pkgs = [p for p in self.specs.values ()
+                    if isinstance (p, gubb.SdkBuildSpec)]
+        cross_pkgs = [p for p in self.specs.values ()
+                      if isinstance (p, cross.CrossToolSpec)]
+
+        extra_build_deps = [p.name () for p in sdk_pkgs + cross_pkgs]
+        gup.add_packages_to_manager (self.manager, self.settings, self.specs)
+
+    def pkg_checksum_valid (self, spec, pkg):
+        name = pkg.name ()
+        pkg_dict = self.manager.package_dict (name)
+
+        valid = (spec.spec_checksum == pkg_dict['spec_checksum']
+                 and spec.source_checksum () == pkg_dict['source_checksum'])
+
+        hdr = pkg.expand ('%(split_hdr)s')
+        valid = valid and os.path.exists (hdr)
+        if valid:
+            import pickle
+            hdr_dict = pickle.load (open (hdr))
+            hdr_sum = hdr_dict['spec_checksum']
+            valid = valid and hdr_sum == spec.spec_checksum
+            valid = valid and spec.source_checksum () == hdr_dict['source_checksum']
+
+        ## let's be lenient for cross pkgs.
+        ## spec.cross_checksum == self.manager.package_dict(name)['cross_checksum'])
+        return valid
+
+    def spec_checksums_valid (self, spec):
+        valid = True
+        for pkg in spec.get_packages ():
+            valid = valid and self.pkg_checksum_valid (spec, pkg)
+        return valid
+
+    def run_one_builder (self, spec):
+        import inspect
+        available = dict (inspect.getmembers (spec, callable))
+        if self.settings.options.stage:
+            (available[options.stage]) ()
+            return
+
+        stages = ['download', 'untar', 'patch',
+                  'configure', 'compile', 'install',
+                  'src_package', 'package', 'clean']
+
+        if self.settings.options.offline:
+            stages.remove ('download')
+
+        if not self.settings.options.build_source:
+            stages.remove ('src_package')
+
+        if self.settings.options.fresh:
+            try:
+                spec_obj.os_interface.action ('Removing status filex')
+                os.unlink (spec_obj.get_stamp_file ())
+            except OSError:
+                pass
+
+        tainted = False
+        for stage in stages:
+            if (not available.has_key (stage)):
+                continue
+
+            if spec.is_done (stage, stages.index (stage)):
+                tainted = True
+                continue
+
+            spec.os_interface.stage (' *** Stage: %s (%s)\n'
+                                     % (stage, spec.name ()))
+
+            if stage == 'package' and tainted and not options.force_package:
+                msg = spec.expand ('''Compile was continued from previous run.
+Will not package.
+Use
+
+rm %(stamp_file)s
+
+to force rebuild, or
+
+--force-package
+
+to skip this check.
+''')
+                spec.os_interface.error (msg)
+                raise 'abort'
+
+
+            if (stage == 'clean'
+                and self.settings.options.keep_build):
+                os.unlink (spec.get_stamp_file ())
+                continue
+
+            try:
+                (available[stage]) ()
+            except misc.SystemFailed:
+
+                ## failed patch will leave system in unpredictable state.
+                if stage == 'patch':
+                    spec.system ('rm %(stamp_file)s')
+
+                raise
+
+            if stage != 'clean':
+                spec.set_done (stage, stages.index (stage))
+
+    def spec_conflict_resolution (self, spec, pkg):
+        pkg_name = pkg.name ()
+        install_candidate = pkg
+        subname = ''
+        if spec.name () != pkg_name:
+            subname = pkg_name.split ('-')[-1]
+        if spec.get_conflict_dict ().has_key (subname):
+            for c in spec.get_conflict_dict ()[subname]:
+                if self.manager.is_installed (c):
+                    print '%(c)s conflicts with %(pkg_name)s' % locals ()
+                    conflict_source = self.manager.source_name (c)
+                    # FIXME: implicit provides: foo-* provides foo-core,
+                    # should implement explicit provides
+                    if conflict_source + '-core' == pkg_name:
+                        print ('  non-core %(conflict_source)s already installed'
+                               % locals ())
+                        print ('    skipping request to install %(pkg_name)s'
+                               % locals ())
+                        install_candidate = None
+                        continue
+                    self.manager.uninstall_package (c)
+        return install_candidate
+
+    def pkg_install (self, spec, pkg):
+        if not self.manager.is_installed (pkg.name ()):
+            install_candidate = self.spec_conflict_resolution (spec, pkg)
+            if install_candidate:
+                self.manager.unregister_package_dict (install_candidate.name ())
+                self.manager.register_package_dict (install_candidate.dict ())
+                self.manager.install_package (install_candidate.name ())
+
+    def spec_install (self, spec):
+        for pkg in spec.get_packages ():
+            self.pkg_install (spec, pkg)
+
+    def spec_build (self, spec_name):
+        spec = self.specs[spec_name]
+        all_installed = True
+        for p in spec.get_packages ():
+            all_installed = (all_installed
+                             and self.manager.is_installed (p.name ()))
+        if all_installed:
+            return
+        # ugh, dupe
+        checksum_ok = (self.settings.options.lax_checksums
+                       or self.spec_checksums_valid (self.specs[spec_name]))
+        is_installable = misc.forall (self.manager.is_installable (p.name ())
+                                      for p in spec.get_packages ())
+        if (self.settings.options.stage
+            or not is_installable
+            or not checksum_ok):
+            self.settings.os_interface.stage ('building package: %s\n'
+                                              % spec_name)
+            self.run_one_builder (spec)
+
+        # FIXME, spec_install should be stage?
+        if self.settings.options.stage: # and options.stage != spec_install:
+            return
+
+        # FIXME, spec_install should be stage?
+        self.spec_install (spec)
+
+    def uninstall_outdated_spec (self, spec_name):
+            spec = self.specs[spec_name]
+            # ugh, dupe
+            checksum_ok = (self.settings.options.lax_checksums
+                           or self.spec_checksums_valid (self.specs[spec_name]))
+            for pkg in spec.get_packages ():
+                if (self.manager.is_installed (pkg.name ())
+                    and (not self.manager.is_installable (pkg.name ())
+                         or not checksum_ok)):
+                    self.manager.uninstall_package (pkg.name ())
+
+    def uninstall_outdated_specs (self, deps):
+        def reverse (lst):
+            list.reverse (lst)
+            return lst
+        for spec_name in reverse (deps[:]):
+            self.uninstall_outdated_spec (spec_name)
+
+    def build_source_packages (self, names):
+        deps = filter (self.specs.has_key, names)
+
+        if not self.settings.options.stage:
+            self.uninstall_outdated_specs (deps)
+
+        for spec_name in deps:
+            self.spec_build (spec_name)
+
+def main ():
+    boe
+
+if __name__ == '__main__':
+    main ()