def export(self, writer, context, platform): name = str(self)[1:] if not self.preamble and not self.environ: self.exported_command = shell.join(self.command) else: filename = path.join('.tools', name) command, filename = platform.write_command_file( filename, list(self.preamble) + [self.command], environ=self.environ, accept_additional_args=True) self.exported_command = shell.join(command) writer.variable(name, self.exported_command)
def write_command_file(self, filename, commands, inputs=None, outputs=None, cwd=None, environ=None, foreach=False, suffix='.cmd', dry=False, accept_additional_args=False): if suffix is not None: filename = path.addsuffix(filename, suffix) result = ['cmd', '/Q', '/c', filename] if foreach: result += ['$in', '$out'] inputs, outputs = ['%1'], ['%2'] commands = self.replace_commands_inout_vars(commands, inputs, outputs) if dry: return result, filename path.makedirs(path.dirname(path.abs(filename))) with open(filename, 'w') as fp: fp.write('REM This file is automatically generated with Craftr. It is \n') fp.write('REM not recommended to modify it manually.\n\n') if cwd is not None: fp.write('cd ' + shell.quote(cwd) + '\n\n') for key, value in environ.items(): fp.write('set ' + shell.quote('{}={}'.format(key, value), for_ninja=True) + '\n') fp.write('\n') for index, command in enumerate(commands): if accept_additional_args and index == len(commands)-1: command.append(shell.safe('%*')) fp.write(shell.join(command) + '\n') fp.write('if %errorlevel% neq 0 exit %errorlevel%\n\n') return result, filename
def export(self, writer, context, platform): """ Export the target to a Ninja manifest. """ writer.comment("target: {}".format(self.name)) writer.comment("--------" + "-" * len(self.name)) commands = platform.prepare_commands( [list(map(str, c)) for c in self.commands]) # Check if we need to export a command file or can export the command # directly. if not self.environ and len(commands) == 1: commands = [platform.prepare_single_command(commands[0], self.cwd)] else: filename = path.join('.commands', self.name) command, __ = platform.write_command_file(filename, commands, self.inputs, self.outputs, cwd=self.cwd, environ=self.environ, foreach=self.foreach) commands = [command] assert len(commands) == 1 command = shell.join(commands[0], for_ninja=True) writer.rule(self.name, command, pool=self.pool, deps=self.deps, depfile=self.depfile, description=self.description) if self.msvc_deps_prefix: # We can not write msvc_deps_prefix on the rule level with Ninja # versions older than 1.7.1. Write it global instead, but that *could* # lead to issues... indent = 1 if context.ninja_version > '1.7.1' else 0 writer.variable('msvc_deps_prefix', self.msvc_deps_prefix, indent) writer.newline() if self.foreach: assert len(self.inputs) == len(self.outputs) for infile, outfile in zip(self.inputs, self.outputs): writer.build([outfile], self.name, [infile], implicit=self.implicit_deps, order_only=self.order_only_deps) else: writer.build(self.outputs or [self.name], self.name, self.inputs, implicit=self.implicit_deps, order_only=self.order_only_deps) if self.outputs and self.name not in self.outputs and not self.explicit: writer.build(self.name, 'phony', self.outputs)
def export(self, writer, context, platform): name = str(self)[1:] if not self.preamble and not self.environ: self.exported_command = shlex.join(self.command) else: filename = path.join('.tools', name) command, filename = platform.write_command_file( filename, list(self.preamble) + [self.command], environ=self.environ, accept_additional_args=True) self.exported_command = shell.join(command) writer.variable(name, self.exported_command)
def export(self, writer, context, platform): """ Export the target to a Ninja manifest. """ writer.comment("target: {}".format(self.name)) writer.comment("--------" + "-" * len(self.name)) commands = platform.prepare_commands([list(map(str, c)) for c in self.commands]) # Check if we need to export a command file or can export the command # directly. if not self.environ and len(commands) == 1: commands = [platform.prepare_single_command(commands[0], self.cwd)] else: filename = path.join('.commands', self.name) command, __ = platform.write_command_file(filename, commands, self.inputs, self.outputs, cwd=self.cwd, environ=self.environ, foreach=self.foreach) commands = [command] assert len(commands) == 1 command = shell.join(commands[0], for_ninja=True) writer.rule(self.name, command, pool=self.pool, deps=self.deps, depfile=self.depfile, description=self.description) if self.msvc_deps_prefix: # We can not write msvc_deps_prefix on the rule level with Ninja # versions older than 1.7.1. Write it global instead, but that *could* # lead to issues... indent = 1 if context.ninja_version > '1.7.1' else 0 writer.variable('msvc_deps_prefix', self.msvc_deps_prefix, indent) writer.newline() if self.foreach: assert len(self.inputs) == len(self.outputs) for infile, outfile in zip(self.inputs, self.outputs): writer.build( [outfile], self.name, [infile], implicit=self.implicit_deps, order_only=self.order_only_deps) else: writer.build( self.outputs or [self.name], self.name, self.inputs, implicit=self.implicit_deps, order_only=self.order_only_deps) if self.outputs and self.name not in self.outputs and not self.explicit: writer.build(self.name, 'phony', self.outputs)
def write_command_file(self, filename, commands, inputs=None, outputs=None, cwd=None, environ=None, foreach=False, suffix='.sh', dry=False, accept_additional_args=False): if suffix is not None: filename = path.addsuffix(filename, suffix) result = [filename] if foreach: result += ['$in', '$out'] inputs, outputs = ['%1'], ['%2'] commands = self.replace_commands_inout_vars(commands, inputs, outputs) if dry: return result, filename path.makedirs(path.dirname(filename)) with open(filename, 'w') as fp: # TODO: Make sure this also works for shells other than bash. fp.write('#!' + shell.find_program(environ.get('SHELL', 'bash')) + '\n') fp.write('set -e\n') if cwd: fp.write('cd ' + shell.quote(cwd) + '\n') fp.write('\n') for key, value in environ.items(): fp.write('export {}={}\n'.format(key, shell.quote(value))) fp.write('\n') for index, command in enumerate(commands): if accept_additional_args and index == len(commands) - 1: command.append(shell.safe('$*')) fp.write(shell.join(command)) fp.write('\n') os.chmod(filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH) # rwxrw-r-- return result, filename
def write_command_file(self, filename, commands, inputs=None, outputs=None, cwd=None, environ=None, foreach=False, suffix='.cmd', dry=False, accept_additional_args=False): if suffix is not None: filename = path.addsuffix(filename, suffix) result = ['cmd', '/Q', '/c', filename] if foreach: result += ['$in', '$out'] inputs, outputs = ['%1'], ['%2'] commands = self.replace_commands_inout_vars(commands, inputs, outputs) if dry: return result, filename path.makedirs(path.dirname(path.abs(filename))) with open(filename, 'w') as fp: fp.write( 'REM This file is automatically generated with Craftr. It is \n' ) fp.write('REM not recommended to modify it manually.\n\n') if cwd is not None: fp.write('cd ' + shell.quote(cwd) + '\n\n') for key, value in environ.items(): fp.write( 'set ' + shell.quote('{}={}'.format(key, value), for_ninja=True) + '\n') fp.write('\n') for index, command in enumerate(commands): if accept_additional_args and index == len(commands) - 1: command.append(shell.safe('%*')) fp.write(shell.join(command) + '\n') fp.write('if %errorlevel% neq 0 exit %errorlevel%\n\n') return result, filename
def write_response_file(arguments, builder=None, name=None, force_file=False, suffix=''): """ Creates a response-file with the specified *name* in the in the ``buildfiles/`` directory and writes the *arguments* list quoted into the file. If *builder* is specified, it must be a :class:`TargetBuilder` and the response file will be added to the implicit dependencies. If *force_file* is set to True, a file will always be written. Otherwise, the function will into possible limitations of the platform and decide whether to write a response file or to return the *arguments* as is. Returns a tuple of ``(filename, arguments)``. If a response file is written, the returned *arguments* will be a list with a single string that is the filename prepended with ``@``. The *filename* part can be None if no response file needed to be exported. """ if not name: if not builder: raise ValueError('builder must be specified if name is bot') name = builder.name + suffix + '.response.txt' if platform.name != 'win': return None, arguments # We'll just assume that there won't be more than 2048 characters for # other flags. The windows max buffer size is 8192. content = shell.join(arguments) if len(content) < 6144: return None, arguments filename = buildlocal(path.join('buildfiles', name)) if builder: builder.implicit_deps.append(filename) if session.builddir: path.makedirs(path.dirname(filename)) with open(filename, 'w') as fp: fp.write(content) return filename, ['@' + filename]
def write_response_file(arguments, builder=None, name=None, force_file=False): """ Creates a response-file with the specified *name* in the in the ``buildfiles/`` directory and writes the *arguments* list quoted into the file. If *builder* is specified, it must be a :class:`TargetBuilder` and the response file will be added to the implicit dependencies. If *force_file* is set to True, a file will always be written. Otherwise, the function will into possible limitations of the platform and decide whether to write a response file or to return the *arguments* as is. Returns a tuple of ``(filename, arguments)``. If a response file is written, the returned *arguments* will be a list with a single string that is the filename prepended with ``@``. The *filename* part can be None if no response file needed to be exported. """ if not name: if not builder: raise ValueError('builder must be specified if name is bot') name = builder.name + '.response.txt' if platform.name != 'win': return None, arguments # We'll just assume that there won't be more than 2048 characters for # other flags. The windows max buffer size is 8192. content = shell.join(arguments) if len(content) < 6144: return None, arguments filename = buildlocal(path.join('buildfiles', name)) if builder: builder.implicit_deps.append(filename) if session.builddir: path.makedirs(path.dirname(filename)) with open(filename, 'w') as fp: fp.write(content) return filename, ['@' + filename]
def write_command_file(self, filename, commands, inputs=None, outputs=None, cwd=None, environ=None, foreach=False, suffix='.sh', dry=False, accept_additional_args=False): if suffix is not None: filename = path.addsuffix(filename, suffix) result = [filename] if foreach: result += ['$in', '$out'] inputs, outputs = ['%1'], ['%2'] commands = self.replace_commands_inout_vars(commands, inputs, outputs) if dry: return result, filename path.makedirs(path.dirname(filename)) with open(filename, 'w') as fp: # TODO: Make sure this also works for shells other than bash. fp.write('#!' + shell.find_program(environ.get('SHELL', 'bash')) + '\n') fp.write('set -e\n') if cwd: fp.write('cd ' + shell.quote(cwd) + '\n') fp.write('\n') for key, value in environ.items(): fp.write('export {}={}\n'.format(key, shell.quote(value))) fp.write('\n') for index, command in enumerate(commands): if accept_additional_args and index == len(commands)-1: command.append(shell.safe('$*')) fp.write(shell.join(command)) fp.write('\n') os.chmod(filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH) # rwxrw-r-- return result, filename
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)