def build(ctx): # Exit early if we're just viewing the state. if ctx.options.dump_state: # print out the entire state ctx.db.dump_database() return 0 # Exit early if we're just deleting a function. if ctx.options.delete_function: if not ctx.db.delete_function(ctx.options.delete_function): raise fbuild.Error('function %r not cached' % ctx.options.delete_function) return 0 # Exit early if we're just deleting a file. if ctx.options.delete_file: if not ctx.db.delete_file(ctx.options.delete_file): raise fbuild.Error('file %r not cached' % ctx.options.delete_file) return 0 # We'll use the arguments as our targets. targets = ctx.options.targets # Installation stuff. if 'install' in targets: if targets[-1] != 'install': raise fbuild.Error('install must be last target') if not set(targets) - {'configure', 'install'}: targets.insert(targets.index('install') - 1, 'build') # Step through each target and execute it. for target_name in targets: if target_name == 'install': try: pre_install = getattr(fbuildroot, 'pre_install') except AttributeError: pass else: pre_install(ctx) install_files(ctx) try: post_install = getattr(fbuildroot, 'post_install') except AttributeError: pass else: post_install(ctx) else: target = fbuild.target.find(target_name) target.function(ctx) return 0
def install(self, path, category, addroot=''): try: self.to_install[category].append((Path(path).abspath(), addroot)) except AttributeError: pass except KeyError: raise fbuild.Error('invalid install category: {}'.format(category))
def find(target_name): """Look up and return a target.""" try: return _targets[target_name] except KeyError: raise fbuild.Error('invalid target %r' % target_name)
def __init__(self, ctx, *, engine, explain=False): def handle_rpc(method, *args, **kwargs): return method(*args, **kwargs) self._ctx = ctx self._explain = explain self._connected = False if engine == 'pickle': self._backend = fbuild.db.pickle_backend.PickleBackend(self._ctx) elif engine == 'cache': self._backend = fbuild.db.cache_backend.CacheBackend(self._ctx) elif engine == 'sqlite': self._backend = fbuild.db.sqlite_backend.SqliteBackend(self._ctx) else: raise fbuild.Error('unknown backend: %s' % engine) self._rpc = fbuild.rpc.RPC(handle_rpc) self._rpc.daemon = True self.start()
def main(argv=None): # Register a couple functions as targets. for name in ('configure', 'build'): try: fbuild.target.register(name=name)(getattr(fbuildroot, name)) except AttributeError: pass # Get the prune handlers. try: prune_get_all = fbuildroot.prune_get_all except: def prune_get_all(ctx, root=None): files = set() if root is None: root = ctx.buildroot for dirpath, dirnames, filenames in root.walk(): files.update(map(dirpath.__truediv__, filenames)) return files try: prune_get_bad = fbuildroot.prune_get_bad except: def prune_get_bad(ctx, files): return files # -------------------------------------------------------------------------- ctx = parse_args(sys.argv if argv is None else argv) # -------------------------------------------------------------------------- # Replace the ctrl-c signal handler with one that will shut down the # scheduler before moving on. old_handler = signal.getsignal(signal.SIGINT) def handle_interrupt(signum, frame): ctx.scheduler.shutdown() old_handler(signum, frame) signal.signal(signal.SIGINT, handle_interrupt) # -------------------------------------------------------------------------- # If we don't wrap this in a try...finally block to shutdown the scheduler # after all else finishes, fbuild will hang indefinitely try: # If the fbuildroot doesn't exist, error out. We do this now so that # there's a chance to ask fbuild for help first. if isinstance(fbuildroot, Exception): if not os.path.exists('fbuildroot.py'): raise fbuild.Error('Cannot find fbuildroot.py') else: raise fbuildroot # Exit early if we want to clean the buildroot. if ctx.options.clean_buildroot: # Only try to clean the buildroot if it actually exists. if ctx.options.buildroot.exists(): ctx.options.buildroot.rmtree() return # Prep the context for running. ctx.create_buildroot() ctx.load_configuration() # ... and then run the build. try: result = build(ctx) if ctx.options.prune: ctx.prune(prune_get_all, prune_get_bad) except fbuild.Error as e: ctx.logger.log(e, color='red') sys.exit(1) except KeyboardInterrupt: # It appears that we can't reliably shutdown the scheduler's threads # when SIGINT is emitted, because python may raise KeyboardInterrupt # between the finally and the mutex.release call. So, we can find # ourselves exiting functions with the lock still held. This could # then cause deadlocks if that lock was ever acquired again. Oiy. print('Interrupted, saving state...') raise finally: ctx.save_configuration() ctx.db.shutdown() finally: ctx.scheduler.shutdown() return result
def autoconf_config_header(ctx, dst, src:fbuild.db.SRC, patterns, *, buildroot=None) -> fbuild.db.DST: """L{autoconf_config_header} replaces the I{patterns} in the file named I{src} and saves the changes into file named I{dst}. It uses autoconf AC_CONFIG_HEADERS @word@ and #define patterns to find the insertion points.""" buildroot = buildroot or ctx.buildroot src = fbuild.path.Path(src) dst = fbuild.path.Path.addroot(dst, buildroot) dst.parent.makedirs() ctx.logger.log(' * creating ' + dst, color='yellow') missing_definitions = [] def replace(match): if match.group('sub'): # Handle the @foo@ substitution value = patterns[match.group('sub')] if isinstance(value, str): return value elif isinstance(value, collections.Iterable): return ' '.join(str(v) for v in value) return str(value) else: # Handle the #undef replacement key = match.group('def') try: value = patterns[key] except KeyError: # We couldn't find a value for this # key, so log it and continue on. missing_definitions.append(key) value = None if isinstance(value, bool): value = int(value) elif \ not isinstance(value, str) and \ isinstance(value, collections.Iterable): value = ' '.join(str(v) for v in value) if value: return '#define %s %s' % (key, value) else: return '/* #undef %s */' % (key) with open(src, 'r') as src_file: code = src_file.read() code = re.sub('(^#undef +(?P<def>\w+)$)|(?:@(?P<sub>\w+)@)', replace, code, flags=re.M) if missing_definitions: raise fbuild.Error('missing definitions: %s' % ' '.join(missing_definitions)) with open(dst, 'w') as dst_file: dst_file.write(code) return dst
def main(argv=None): # Register a couple functions as targets. for name in ('configure', 'build'): try: fbuild.target.register(name=name)(getattr(fbuildroot, name)) except AttributeError: pass # -------------------------------------------------------------------------- # Hacky way of enabling warnings before parsing options. if '--no-warnings' not in sys.argv: warnings.filterwarnings('always', category=fbuild.Deprecation) # -------------------------------------------------------------------------- ctx = parse_args(sys.argv if argv is None else argv) # -------------------------------------------------------------------------- # Replace the ctrl-c signal handler with one that will shut down the # scheduler before moving on. old_handler = signal.getsignal(signal.SIGINT) def handle_interrupt(signum, frame): ctx.scheduler.shutdown() old_handler(signum, frame) signal.signal(signal.SIGINT, handle_interrupt) # -------------------------------------------------------------------------- # If we don't wrap this in a try...finally block to shutdown the scheduler # after all else finishes, fbuild will hang indefinitely. try: # If the fbuildroot doesn't exist, error out. We do this now so that # there's a chance to ask fbuild for help first. if isinstance(fbuildroot, Exception): if not os.path.exists('fbuildroot.py'): raise fbuild.Error('Cannot find fbuildroot.py') else: raise fbuildroot # Exit early if we want to clean the buildroot. if ctx.options.clean_buildroot: # Only try to clean the buildroot if it actually exists. if ctx.options.buildroot.exists(): ctx.options.buildroot.rmtree() return # Prep the context for running. ctx.create_buildroot() ctx.load_configuration() # ... and then run the build. try: result = build(ctx) except fbuild.Error as e: ctx.logger.log(e, color='red') sys.exit(1) except KeyboardInterrupt: # It appears that we can't reliably shutdown the scheduler's threads # when SIGINT is emitted, because python may raise KeyboardInterrupt # between the finally and the mutex.release call. So, we can find # ourselves exiting functions with the lock still held. This could # then cause deadlocks if that lock was ever acquired again. Oiy. print('Interrupted, saving state...') raise else: # Only delete the temporary directory if the build succeeded. ctx.clear_temp_dir() finally: ctx.save_configuration() ctx.db.shutdown() finally: ctx.scheduler.shutdown() return result