def execute(self, parser, args): directory = args.directory or args.name if path.maybedir(directory): directory = path.join(directory, args.name) if not path.exists(directory): logger.debug('creating directory "{}"'.format(directory)) path.makedirs(directory) elif not path.isdir(directory): logger.error('"{}" is not a directory'.format(directory)) return 1 if args.nested: directory = path.join(directory, 'craftr') path.makedirs(directory) mfile = path.join(directory, 'manifest.' + args.format) sfile = path.join(directory, 'Craftrfile') for fn in [mfile, sfile]: if path.isfile(fn): logger.error('"{}" already exists'.format(fn)) return 1 logger.debug('creating file "{}"'.format(mfile)) with open(mfile, 'w') as fp: if args.format == 'cson': lines = textwrap.dedent(''' name: "%s" version: "%s" project_dir: ".." author: "" url: "" dependencies: {} options: {} ''' % (args.name, args.version)).lstrip().split('\n') if not args.nested: del lines[2] elif args.format == 'json': lines = textwrap.dedent(''' { "name": "%s", "version": "%s", "project_dir": "..", "author": "", "url": "", "dependencies": {}, "options": {} }''' % (args.name, args.version)).lstrip().split('\n') if not args.nested: del lines[3] fp.write('\n'.join(lines)) logger.debug('creating file "{}"'.format(sfile)) with open(sfile, 'w') as fp: print('# {}'.format(args.name), file=fp)
def write_cache(cachefile): # Write back the cache. try: path.makedirs(path.dirname(cachefile)) with open(cachefile, 'w') as fp: session.write_cache(fp) except OSError as exc: logger.error('error writing cache file:', cachefile) logger.error(exc, indent=1) else: logger.debug('cache written:', cachefile)
def execute(self, parser, args): directory = args.directory or args.name if path.maybedir(directory): directory = path.join(directory, args.name) if not path.exists(directory): logger.debug('creating directory "{}"'.format(directory)) path.makedirs(directory) elif not path.isdir(directory): logger.error('"{}" is not a directory'.format(directory)) return 1 if args.nested: directory = path.join(directory, "craftr") path.makedirs(directory) mfile = path.join(directory, MANIFEST_FILENAME) sfile = path.join(directory, "Craftrfile") for fn in [mfile, sfile]: if path.isfile(fn): logger.error('"{}" already exists'.format(fn)) return 1 logger.debug('creating file "{}"'.format(mfile)) with open(mfile, "w") as fp: lines = ( textwrap.dedent( """ { "name": "%s", "version": "%s", "project_dir": "..", "author": "", "url": "", "dependencies": {}, "options": {} }\n""" % (args.name, args.version) ) .lstrip() .split("\n") ) if not args.nested: del lines[3] fp.write("\n".join(lines)) logger.debug('creating file "{}"'.format(sfile)) with open(sfile, "w") as fp: print("# {}".format(args.name), file=fp)
def read_cache(show_errors_and_exit=True): cachefile = os.path.join(session.builddir, '.craftrcache') try: with open(cachefile) as fp: try: session.read_cache(fp) except ValueError as exc: logger.warn('Invalid cache: "{}"'.format(cachefile)) logger.warn('Load error is: {}'.format(exc)) return False except IOError as exc: if show_errors_and_exit: logger.error('Unable to find file: "{}"'.format(cachefile)) logger.error('Does not seem to be a build directory: "{}"'.format( session.builddir)) logger.error( "Export build information using the 'craftr export' command.") sys.exit(1) return False return True
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 _build_or_clean(self, args): """ Will be called for the 'build' and 'clean' modes. Loads the Craftr cache and invokes Ninja. """ # Read the cache and parse command-line options. if not read_cache(True): sys.exit(1) parse_cmdline_options(session.cache['build']['options']) main = session.cache['build']['main'] available_targets = frozenset(session.cache['build']['targets']) available_modules = unserialise_loaded_module_info( session.cache['build']['modules']) logger.debug('build main module:', main) session.expand_relative_options(get_volatile_module_version(main)[0]) # Check if any of the modules changed, so we can let the user know he # might have to re-export the build files. changed_modules = [] for name, versions in available_modules.items(): for version, info in versions.items(): if info['changed']: changed_modules.append('{}-{}'.format(name, version)) if changed_modules: if len(changed_modules) == 1: logger.info( 'note: module "{}" has changed, maybe you should re-export' .format(changed_modules[0])) else: logger.info( 'note: some modules have changed, maybe you should re-export' ) for name in changed_modules: logger.info(' -', name) # Check the targets and if they exist. targets = [] for target_name in args.targets: if '.' not in target_name: target_name = main + '.' + target_name elif target_name.startswith('.'): target_name = main + target_name module_name, target_name = target_name.rpartition('.')[::2] module_name, version = get_volatile_module_version(module_name) if module_name not in available_modules: error('no such module:', module_name) if not version: version = max(available_modules[module_name].keys()) target_name = craftr.targetbuilder.get_full_name( target_name, module_name=module_name, version=version) if target_name not in available_targets: logger.error('no such target: {}'.format(target_name)) return 1 targets.append(target_name) # Make sure we get all the output before running the subcommand. logger.flush() # Execute the ninja build. cmd = [self.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
def _export_run_or_help(self, args, module): """ Called when the mode is 'export' or 'run'. Will execute the specified *module* and eventually export a Ninja manifest and Cache. """ read_cache(False) session.expand_relative_options() session.cache['build'] = {} # Load the dependency lock information if it exists. deplock_fn = path.join(path.dirname(module.manifest.filename), '.dependency-lock') if os.path.isfile(deplock_fn): with open(deplock_fn) as fp: session.preferred_versions = cson.load(fp) logger.debug('note: dependency lock file "{}" loaded'.format( deplock_fn)) 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() and self.mode == 'export': # 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(self.cachefile) # Fill the cache. session.cache['build']['targets'] = list(session.graph.targets.keys()) session.cache['build']['modules'] = serialise_loaded_module_info() session.cache['build']['main'] = module.ident session.cache['build']['options'] = args.options session.cache['build']['dependency_lock_filename'] = deplock_fn if self.mode == 'export': # Add the Craftr_run_command variable which is necessary for tasks # to properly executed. run_command = ['craftr', '-q', '-P', path.rel(session.maindir)] if args.no_config: run_command += ['-C'] run_command += ['-c' + x for x in args.config] run_command += ['run'] if args.module: run_command += ['-m', args.module] run_command += ['-i' + x for x in args.include_path] run_command += ['-b', path.rel(session.builddir)] session.graph.vars['Craftr_run_command'] = shell.join(run_command) write_cache(self.cachefile) # Write the Ninja manifest. with open("build.ninja", 'w') as fp: platform = core.build.get_platform_helper() context = core.build.ExportContext(self.ninja_version) writer = core.build.NinjaWriter(fp) session.graph.export(writer, context, platform) logger.info('exported "build.ninja"') return 0 elif self.mode == 'run': if args.task: if args.task not in session.graph.tasks: logger.error('no such task exists: "{}"'.format(args.task)) return 1 task = session.graph.tasks[args.task] return task.invoke(args.task_args) return 0 elif self.mode == 'help': if args.name not in vars(module.namespace): logger.error('symbol not found: "{}:{}"'.format( module.manifest.name, args.name)) return 1 help(getattr(module.namespace, args.name)) return 0 assert False, "unhandled mode: {}".format(self.mode)
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