changeset 3353:1cd50c9b33ea

Refactor gub building into smaller functions. Add bit smarter conflict resolution.
author Jan Nieuwenhuizen <janneke@gnu.org>
date Sun, 29 Apr 2007 10:25:48 +0200
parents 1dd83f9be9a4
children 82b667bc3d7a
files bin/gub lib/gub.py lib/gup.py
diffstat 3 files changed, 137 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/bin/gub	Sat Apr 28 11:17:48 2007 +0200
+++ b/bin/gub	Sun Apr 29 10:25:48 2007 +0200
@@ -122,34 +122,38 @@
 
     return p
 
-def checksums_valid (manager, specname, specs):
-    import pickle
-    spec = specs[specname]
+# 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 = True
-    for package in spec.get_packages ():
-        name = package.name()
-        package_dict = manager.package_dict (name)
-
-        valid = (spec.spec_checksum == package_dict['spec_checksum']
-                 and spec.source_checksum () == package_dict['source_checksum'])
+    valid = (spec.spec_checksum == pkg_dict['spec_checksum']
+             and spec.source_checksum () == pkg_dict['source_checksum'])
 
-        hdr = package.expand ('%(split_hdr)s')
-        valid = valid and os.path.exists (hdr)
-        if valid:
-            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']
+    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 packages.
+    ## 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_obj):
+def run_one_builder (options, spec):
     import inspect
-    available = dict (inspect.getmembers (spec_obj, callable))
+    available = dict (inspect.getmembers (spec, callable))
     if options.stage:
         (available[options.stage]) ()
         return
@@ -169,15 +173,15 @@
         if (not available.has_key (stage)):
             continue
 
-        if spec_obj.is_done (stage, stages.index (stage)):
+        if spec.is_done (stage, stages.index (stage)):
             tainted = True
             continue
 
-        spec_obj.os_interface.log_command (' *** Stage: %s (%s)\n'
-                                           % (stage, spec_obj.name ()))
+        spec.os_interface.log_command (' *** Stage: %s (%s)\n'
+                                           % (stage, spec.name ()))
 
         if stage == 'package' and tainted and not options.force_package:
-            msg = spec_obj.expand ('''Compile was continued from previous run.
+            msg = spec.expand ('''Compile was continued from previous run.
 Will not package.
 Use
 
@@ -189,13 +193,13 @@
 
 to skip this check.
 ''')
-            spec_obj.os_interface.log_command (msg)
+            spec.os_interface.log_command (msg)
             raise 'abort'
 
 
         if (stage == 'clean'
             and options.keep_build):
-            os.unlink (spec_obj.get_stamp_file ())
+            os.unlink (spec.get_stamp_file ())
             continue
 
         try:
@@ -204,15 +208,104 @@
 
             ## failed patch will leave system in unpredictable state.
             if stage == 'patch':
-                spec_obj.system ('rm %(stamp_file)s')
+                spec.system ('rm %(stamp_file)s')
 
             raise
 
         if stage != 'clean':
-            spec_obj.set_done (stage, stages.index (stage))
+            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
 
-# What a mess, what happens here?
-def run_builder (options, settings, manager, names, specs):
+    # 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.log_command ('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,
@@ -226,62 +319,14 @@
 
     extra_build_deps = [p.name () for p in sdk_pkgs + cross_pkgs]
     gup.add_packages_to_manager (manager, settings, specs)
-    if not options.stage:
-        reved = names[:]
-        reved.reverse ()
-        for spec_name in reved:
-            spec = specs[spec_name]
-            checksum_ok = (options.lax_checksums
-                           or checksums_valid (manager, spec_name,
-                                               specs))
-            for p in spec.get_packages ():
-                if (manager.is_installed (p.name ()) and
-                    (not manager.is_installable (p.name ())
-                     or not checksum_ok)):
-                    manager.uninstall_package (p.name ())
-
-    for spec_name in names:
-        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:
-            continue
-
-        # ugh, dupe
-        checksum_ok = (options.lax_checksums
-                       or checksums_valid (manager, spec_name, specs))
 
-        is_installable = misc.forall (manager.is_installable (p.name ())
-                                      for p in spec.get_packages ())
-
-        if (options.stage
-            or not is_installable
-            or not checksum_ok):
-            settings.os_interface.log_command ('building package: %s\n'
-                                               % spec_name)
-            run_one_builder (options, spec)
-
-        # FIXME, pkg_install should be stage?
-        if options.stage: # and options.stage != pkg_install:
-            continue
+    # FIXME: what happens here, move to descriptive function?
+    if not settings.options.stage:
+        uninstall_outdated_specs (settings, manager, specs, deps)
 
-        # FIXME, pkg_install should be stage?
-        for p in spec.get_packages ():
-            name = p.name ()
-            if not manager.is_installed (name):
-                subname = ''
-                if spec.name () != p.name ():
-                    subname = 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 %(name)s' % locals ()
-                            manager.uninstall_package (c)
-                manager.unregister_package_dict (p.name ())
-                manager.register_package_dict (p.dict ())
-                manager.install_package (p.name ())
-
+    for spec_name in deps:
+        spec_build (settings, manager, specs, spec_name)
+        
 def get_settings (options):
     # FIXME, move (all these get_setting*) to constructors
     settings = settings_mod.get_settings (options.platform)
@@ -315,6 +360,7 @@
             deps = [gup.get_base_package_name (d) for d in deps]
         return deps
 
+    # FIXME: why do we only use deps for download, not for build?
     deps = gup.topologically_sorted (files, {}, get_all_deps, None)
     if settings.options.verbose:
         print 'deps:' + `deps`
@@ -332,18 +378,7 @@
             specs[i].download ()
         sys.exit (0)
 
-    try:
-        pm = 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)
-    run_builder (settings.options, settings, pm, deps, specs)
+    build_source_packages (settings, specs, names)
 
 def main ():
     cli_parser = get_cli_parser ()
--- a/lib/gub.py	Sat Apr 28 11:17:48 2007 +0200
+++ b/lib/gub.py	Sun Apr 29 10:25:48 2007 +0200
@@ -31,6 +31,9 @@
         self._dict['split_hdr'] = ('%(gub_uploads)s/%(split_name)s%(vc_branch_suffix)s.%(platform)s.hdr') % self._dict
         self._dict['conflicts_string'] = ';'.join (self._conflicts)
         self._dict['dependencies_string'] = ';'.join (self._dependencies)
+        self._dict['source_name'] = self.name ()
+        if sub_name:
+            self._dict['source_name'] = self.name ()[:-len (sub_name)]
         
     def expand (self, s):
         return s % self._dict
--- a/lib/gup.py	Sat Apr 28 11:17:48 2007 +0200
+++ b/lib/gup.py	Sun Apr 29 10:25:48 2007 +0200
@@ -309,6 +309,9 @@
         FileManager.uninstall_package (self, name)
         del self._package_dict_db[name]
 
+    def source_name (self, name):
+        return self._packages [name]['source_name']
+
     
 def is_string (x):
     return type (x) == type ('')