Mercurial > gub
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 ()