def load(name, into=None, get_namespace=True, _stackframe=1): """ Load a Craftr module by name and return it. If *into* is specified, it must be a dictionary that will be filled with all the members of the module. Note that this function returns the namespace object of the module rather than the actual :class:`craftr.core.session.Module` object that wraps the module information unless *get_namespace* is False. The version criteria is read from the current module's manifest. :param name: The name of the module to load. If this name is suffixed with the two characters ``.*`` and the *into* parameter is :const:`None`, the contents of the module will be exported into the globals of the calling frame. :param into: If specified, must be a dictionary. :param get_namespace: :return: The module namespace object (of type :class:`types.ModuleType`) or the actual :class:`craftr.core.session.Module` if *get_namespace* is False. :raise ModuleNotFound: If the module could not be found. :raise RuntimeError: If the module that is attempted to be loaded is not declared in the current module's manifest. """ if name.endswith('.*') and into is None: name = name[:-2] into = _sys._getframe(_stackframe).f_globals if not session: raise RuntimeError('no session context') module = session.module if not module: raise RuntimeError('no current module') if name not in module.manifest.dependencies: raise RuntimeError('"{}" can not load "{}", make sure that it is listed ' 'in the dependencies'.format(module.ident, name)) loaded_module = session.find_module(name, module.manifest.dependencies[name]) if not loaded_module.executed: loaded_module.run() module.dependencies[name] = loaded_module.manifest.version if into is not None: module_builtins = frozenset('loader project_dir options'.split()) all_vars = getattr(loaded_module.namespace, '__all__', None) for key, value in vars(loaded_module.namespace).items(): if all_vars is not None: if key in all_vars: into[key] = value else: if not key.startswith('_') and key not in module_builtins and key not in globals(): into[key] = value if get_namespace: return loaded_module.namespace return loaded_module
def _dump_deptree(self, args, module, indent=0, index=0): if indent == 0 and index == 0: print() print(' ' * indent + '{} (v{})'.format(module.manifest.name, module.manifest.version)) for index, (name, version) in enumerate( module.manifest.dependencies.items()): self._dump_deptree(args, session.find_module(name, version), indent=indent + 1, index=index) return 0
def _dump_options(self, args, module): width = tty.terminal_size()[0] print() title = '{} (v{})'.format(module.manifest.name, module.manifest.version) print(title) if args.details: print('-' * len(title)) print() if module.manifest.description: print('Description:\n') print(textfill(module.manifest.description, indent=2)) print() print('Options:\n') for option in sorted(module.manifest.options.values(), key=attrgetter('name')): line = ' ' + option.name info = option.alias if option.inherit: info += ', inheritable' remain = width - len(line) - len(info) default = repr(option.default) default_inline = False if len(default) < (remain - 4): # 3 spaces and 2 parenthesis default_inline = True info = '({}) '.format(default) + info remain -= len(default) + 3 print(line + ' ' * remain + info) if not default_inline: print(' ({})'.format(default)) if args.details: if option.help: print() print(textfill(option.help, indent=4)) print() if args.recursive: for name, version in module.manifest.dependencies.items(): print() self._dump_options(args, session.find_module(name, version)) return 0
def _find_module(self, parser, args): """ Find the main Craftr module that is to be executed. Returns None in modes that do not require a main module. """ if self.mode not in ('export', 'run', 'help', 'dump-options', 'dump-deptree'): return None # Determine the module to execute, either from the current working # directory or find it by name if one is specified. if not args.module: for fn in MANIFEST_FILENAMES + [ path.join('craftr', x) for x in MANIFEST_FILENAMES ]: if path.isfile(fn): module = session.parse_manifest(fn) break else: logger.error('"{}" does not exist'.format( MANIFEST_FILENAMES[0])) sys.exit(1) else: # TODO: For some reason, prints to stdout are not visible here. # TODO: Prints to stderr however work fine. try: module_name, version = parse_module_spec(args.module) except ValueError as exc: logger.error( '{} (note: you have to escape > and < characters)'.format( exc)) sys.exit(1) try: module = session.find_module(module_name, version) except Module.NotFound as exc: logger.error('module not found: ' + str(exc)) sys.exit(1) return module
def load_module(name, into=None, get_namespace=True, _stackframe=1): """ Load a Craftr module by name and return it. If *into* is specified, it must be a dictionary that will be filled with all the members of the module. Note that this function returns the namespace object of the module rather than the actual :class:`craftr.core.session.Module` object that wraps the module information unless *get_namespace* is False. The version criteria is read from the current module's manifest. :param name: The name of the module to load. If this name is suffixed with the two characters ``.*`` and the *into* parameter is :const:`None`, the contents of the module will be exported into the globals of the calling frame. :param into: If specified, must be a dictionary. :param get_namespace: :return: The module namespace object (of type :class:`types.ModuleType`) or the actual :class:`craftr.core.session.Module` if *get_namespace* is False. :raise ModuleNotFound: If the module could not be found. :raise RuntimeError: If the module that is attempted to be loaded is not declared in the current module's manifest. Examples: .. code:: python cxx = load_module('lang.cxx') load_module('lang.cxx.*') assert cxx.c_compile is c_compile """ if name.endswith('.*') and into is None: name = name[:-2] into = _sys._getframe(_stackframe).f_globals if not session: raise RuntimeError('no session context') module = session.module if not module: raise RuntimeError('no current module') if name not in module.manifest.dependencies: raise RuntimeError('"{}" can not load "{}", make sure that it is listed ' 'in the dependencies'.format(module.ident, name)) loaded_module = session.find_module(name, module.manifest.dependencies[name]) if not loaded_module.executed: loaded_module.run() if into is not None: module_builtins = frozenset('loader project_dir options'.split()) all_vars = getattr(loaded_module.namespace, '__all__', None) for key, value in vars(loaded_module.namespace).items(): if all_vars is not None: if key in all_vars: into[key] = value else: if not key.startswith('_') and key not in module_builtins and key not in globals(): into[key] = value if get_namespace: return loaded_module.namespace return loaded_module
def execute(self, parser, args): session.path.extend(map(path.norm, args.include_path)) if self.is_export: # Determine the module to execute, either from the current working # directory or find it by name if one is specified. if not args.module: for fn in [MANIFEST_FILENAME, path.join('craftr', MANIFEST_FILENAME)]: if path.isfile(fn): module = session.parse_manifest(fn) break else: parser.error('"{}" does not exist'.format(MANIFEST_FILENAME)) else: # TODO: For some reason, prints to stdout are not visible here. # TODO: Prints to stderr however work fine. try: module_name, version = parse_module_spec(args.module) except ValueError as exc: parser.error('{} (note: you have to escape > and < characters)'.format(exc)) try: module = session.find_module(module_name, version) except Module.NotFound as exc: parser.error('module not found: ' + str(exc)) else: module = None ninja_bin, ninja_version = get_ninja_info() # Create and switch to the build directory. session.builddir = path.abs(args.build_dir) path.makedirs(session.builddir) os.chdir(session.builddir) # Read the cache and parse command-line options. cachefile = path.join(session.builddir, '.craftrcache') if not read_cache(cachefile) and not self.is_export: logger.error('Unable to load "{}", can not build'.format(cachefile)) return 1 # Prepare options, loaders and execute. if self.is_export: session.cache['build'] = {} try: write_cache(cachefile) module.run() except (Module.InvalidOption, Module.LoaderInitializationError) as exc: for error in exc.format_errors(): logger.error(error) return 1 except craftr.defaults.ModuleError as exc: logger.error(exc) return 1 # Write the cache back. session.cache['build']['targets'] = list(session.graph.targets.keys()) session.cache['build']['main'] = module.ident session.cache['build']['options'] = args.options write_cache(cachefile) # Write the Ninja manifest. with open("build.ninja", 'w') as fp: platform = core.build.get_platform_helper() context = core.build.ExportContext(ninja_version) writer = core.build.NinjaWriter(fp) session.graph.export(writer, context, platform) else: parse_cmdline_options(session.cache['build']['options']) main = session.cache['build']['main'] available_targets = frozenset(session.cache['build']['targets']) # Check the targets and if they exist. targets = [] for target in args.targets: if '.' not in target: target = main + '.' + target elif target.startswith('.'): target = main + target module_name, target = target.rpartition('.')[::2] module_name, version = get_volatile_module_version(module_name) ref_module = session.find_module(module_name, version or '*') target = craftr.targetbuilder.get_full_name(target, ref_module) if target not in available_targets: parser.error('no such target: {}'.format(target)) targets.append(target) # Execute the ninja build. cmd = [ninja_bin] if args.verbose: cmd += ['-v'] cmd += targets shell.run(cmd)
def execute(self, parser, args): session.path.extend(map(path.norm, args.include_path)) if self.mode == "export": # Determine the module to execute, either from the current working # directory or find it by name if one is specified. if not args.module: for fn in [MANIFEST_FILENAME, path.join("craftr", MANIFEST_FILENAME)]: if path.isfile(fn): module = session.parse_manifest(fn) break else: parser.error('"{}" does not exist'.format(MANIFEST_FILENAME)) else: # TODO: For some reason, prints to stdout are not visible here. # TODO: Prints to stderr however work fine. try: module_name, version = parse_module_spec(args.module) except ValueError as exc: parser.error("{} (note: you have to escape > and < characters)".format(exc)) try: module = session.find_module(module_name, version) except Module.NotFound as exc: parser.error("module not found: " + str(exc)) else: module = None ninja_bin, ninja_version = get_ninja_info() # Create and switch to the build directory. session.builddir = path.abs(args.build_dir) path.makedirs(session.builddir) os.chdir(session.builddir) # Read the cache and parse command-line options. cachefile = path.join(session.builddir, ".craftrcache") if not read_cache(cachefile) and self.mode != "export": logger.error('Unable to load "{}", can not {}'.format(cachefile, self.mode)) logger.error("Make sure to generate a build tree with 'craftr export'") return 1 # Prepare options, loaders and execute. if self.mode == "export": session.expand_relative_options(module.manifest.name) session.cache["build"] = {} try: module.run() except Module.InvalidOption as exc: for error in exc.format_errors(): logger.error(error) return 1 except craftr.defaults.ModuleError as exc: logger.error("error:", exc) return 1 finally: if sys.exc_info(): # We still want to write the cache, especially so that data already # loaded with loaders doesn't need to be re-loaded. They'll find out # when the cached information was not valid. write_cache(cachefile) # Write the cache back. session.cache["build"]["targets"] = list(session.graph.targets.keys()) session.cache["build"]["main"] = module.ident session.cache["build"]["options"] = args.options write_cache(cachefile) # Write the Ninja manifest. with open("build.ninja", "w") as fp: platform = core.build.get_platform_helper() context = core.build.ExportContext(ninja_version) writer = core.build.NinjaWriter(fp) session.graph.export(writer, context, platform) else: parse_cmdline_options(session.cache["build"]["options"]) main = session.cache["build"]["main"] available_targets = frozenset(session.cache["build"]["targets"]) logger.debug("build main module:", main) session.expand_relative_options(get_volatile_module_version(main)[0]) # Check the targets and if they exist. targets = [] for target in args.targets: if "." not in target: target = main + "." + target elif target.startswith("."): target = main + target module_name, target = target.rpartition(".")[::2] module_name, version = get_volatile_module_version(module_name) ref_module = session.find_module(module_name, version or "*") target = craftr.targetbuilder.get_full_name(target, ref_module) if target not in available_targets: parser.error("no such target: {}".format(target)) targets.append(target) # Execute the ninja build. cmd = [ninja_bin] if args.verbose: cmd += ["-v"] if self.mode == "clean": cmd += ["-t", "clean"] if not args.recursive: cmd += ["-r"] cmd += targets return shell.run(cmd).returncode