def execute(self): def add_targets(dir, buildfile): try: self.targets.extend(Target.get(addr) for addr in Target.get_all_addresses(buildfile)) except (TypeError, ImportError): error(dir, include_traceback=True) except (IOError, SyntaxError): error(dir) if self.options.recursive_directory: with self.check_errors('There was a problem scanning the ' 'following directories for targets:') as error: for dir in self.options.recursive_directory: for buildfile in BuildFile.scan_buildfiles(self.root_dir, dir): add_targets(dir, buildfile) if self.options.target_directory: with self.check_errors("There was a problem loading targets " "from the following directory's BUILD files") as error: for dir in self.options.target_directory: add_targets(dir, BuildFile(self.root_dir, dir)) timer = None if self.options.time: class Timer(object): def now(self): return time.time() def log(self, message): print message timer = Timer() logger = None if self.options.log or self.options.log_level: from twitter.common.log import init from twitter.common.log.options import LogOptions LogOptions.set_stdout_log_level((self.options.log_level or 'info').upper()) logdir = self.config.get('goals', 'logdir') if logdir: safe_mkdir(logdir) LogOptions.set_log_dir(logdir) init('goals') logger = log context = Context(self.config, self.options, self.targets, log=logger) unknown = [] for phase in self.phases: if not phase.goals(): unknown.append(phase) if unknown: print 'Unknown goal(s): %s' % ' '.join(phase.name for phase in unknown) print return Phase.execute(context, 'goals') return Phase.attempt(context, self.phases, timer=timer)
def execute(self, targets): goal = self.context.options.help_goal if goal is None: return self.list_goals('You must supply a goal name to provide help for.') phase = Phase(goal) if not phase.goals(): return self.list_goals('Goal %s is unknown.' % goal) parser = Help.parser() parser.set_usage('%s goal %s ([target]...)' % (sys.argv[0], goal)) parser.epilog = phase.description Phase.setup_parser(parser, [], [phase]) parser.parse_args(['--help'])
def execute(self, targets): print 'Installed goals:' documented_rows = [] undocumented = [] max_width = 0 for phase, _ in Phase.all(): if phase.description: documented_rows.append((phase.name, phase.description)) max_width = max(max_width, len(phase.name)) elif self.context.options.goal_list_all: undocumented.append(phase.name) for name, description in documented_rows: print ' %s: %s' % (name.rjust(max_width), description) if undocumented: print '\nUndocumented goals:\n %s' % ' '.join(undocumented)
def list_goals(self, message): print message print return Phase.execute(self.context, 'goals')
def setup_parser(self, parser, args): self.config = Config.load() parser.add_option("-x", "--time", action="store_true", dest = "time", default = False, help = "Times goal phases and outputs a report.") parser.add_option("-v", "--log", action="store_true", dest = "log", default = False, help = "[%default] Logs extra build output.") parser.add_option("-l", "--level", dest = "log_level", type="choice", choices=['debug', 'info', 'warn'], help = "[info] Sets the logging level to one of 'debug', 'info' or 'warn', " "implies -v if set.") parser.add_option("--all", dest="target_directory", action="append", help = "Adds all targets found in the given directory's BUILD file. Can " "be specified more than once.") parser.add_option("--all-recursive", dest="recursive_directory", action="append", help = "Adds all targets found recursively under the given directory. Can " "be specified more than once to add more than one root target " "directory to scan.") # We support attempting zero or more goals. Multiple goals must be delimited from further # options and non goal args with a '--'. The key permutations we need to support: # ./pants goal => goals # ./pants goal goals => goals # ./pants goal compile src/java/... => compile # ./pants goal compile -x src/java/... => compile # ./pants goal compile src/java/... -x => compile # ./pants goal compile run -- src/java/... => compile, run # ./pants goal compile run -- src/java/... -x => compile, run # ./pants goal compile run -- -x src/java/... => compile, run if not args: args.append('goals') if len(args) == 1 and args[0] in set(['-h', '--help', 'help']): def format_usage(usages): left_colwidth = 0 for left, right in usages: left_colwidth = max(left_colwidth, len(left)) lines = [] for left, right in usages: lines.append(' %s%s%s' % (left, ' ' * (left_colwidth - len(left) + 1), right)) return '\n'.join(lines) usages = [ ("%prog goal goals ([spec]...)", Phase('goals').description), ("%prog goal help [goal] ([spec]...)", Phase('help').description), ("%prog goal [goal] [spec]...", "Attempt goal against one or more targets."), ("%prog goal [goal] ([goal]...) -- [spec]...", "Attempts all the specified goals."), ] parser.set_usage("\n%s" % format_usage(usages)) parser.epilog = ("Either lists all installed goals, provides extra help for a goal or else " "attempts to achieve the specified goal for the listed targets.") parser.print_help() sys.exit(0) else: goals = [] help = False multi = False for i, arg in enumerate(args): help = help or 'help' == arg goals.append(arg) if '--' == arg: multi = True del args[i] goals.pop() break if arg.startswith('-'): break if not multi: goals = [goals[0]] spec_offset = len(goals) + 1 if help else len(goals) specs = [arg for arg in args[spec_offset:] if not arg.startswith('-')] def parse_build(buildfile): # TODO(John Sirois): kill PANTS_NEW and its usages when pants.new is rolled out ParseContext(buildfile).parse(PANTS_NEW=True) # Bootstrap goals by loading any configured bootstrap BUILD files with self.check_errors('The following bootstrap_buildfiles cannot be loaded:') as error: for path in self.config.getlist('goals', 'bootstrap_buildfiles', default = []): try: buildfile = BuildFile(get_buildroot(), os.path.relpath(path, get_buildroot())) parse_build(buildfile) except (TypeError, ImportError): error(path, include_traceback=True) except (IOError, SyntaxError): error(path) # Bootstrap user goals by loading any BUILD files implied by targets self.targets = [] with self.check_errors('The following targets could not be loaded:') as error: for spec in specs: try: address = Address.parse(get_buildroot(), spec) parse_build(address.buildfile) target = Target.get(address) if target: self.targets.append(target) else: siblings = Target.get_all_addresses(address.buildfile) prompt = 'did you mean' if len(siblings) == 1 else 'maybe you meant one of these' error('%s => %s?:\n %s' % (address, prompt, '\n '.join(str(a) for a in siblings))) except (TypeError, ImportError): error(spec, include_traceback=True) except (IOError, SyntaxError): error(spec) self.phases = [Phase(goal) for goal in goals] Phase.setup_parser(parser, args, self.phases)