Exemple #1
0
    def parse(cls, root_dir, spec, is_relative=True):
        """Parses the given spec into an Address.

    An address spec can be one of:
    1.) the (relative) path of a BUILD file
    2.) the (relative) path of a directory containing a BUILD file child
    3.) either of 1 or 2 with a ':[module name]' suffix
    4.) a bare ':[module name]' indicating the BUILD file to use is the one in the current directory

    If the spec does not have a target name suffix the target name is taken to be the same name
    as the BUILD file's parent directory.  In this way the containing directory name
    becomes the 'default' target name for a BUILD file.

    If there is no BUILD file at the path pointed to, or if there is but the specified target name
    is not defined in the BUILD file, an IOError is raised.
    """

        if spec.startswith(':'):
            spec = '.' + spec
        parts = spec.split(':', 1)
        path = parts[0]
        if is_relative:
            path = os.path.relpath(os.path.abspath(path), root_dir)
        buildfile = BuildFile(root_dir, path)

        name = os.path.basename(os.path.dirname(
            buildfile.relpath)) if len(parts) == 1 else parts[1]
        return Address(buildfile, name)
def create_buildfile(root_dir, relpath, name='BUILD', content=''):
    path = os.path.join(root_dir, relpath)
    safe_mkdir(path)
    buildfile = os.path.join(path, name)
    with open(buildfile, 'a') as f:
        f.write(content)
    return BuildFile(root_dir, relpath)
Exemple #3
0
    def parse(cls, root_dir, pathish, is_relative=True):
        """Parses pathish into an Address.  A pathish can be one of:
    1.) the (relative) path of a BUILD file
    2.) the (relative) path of a directory containing a BUILD file child
    3.) either of 1 or 2 with a ':[module name]' suffix
    4.) a bare ':[module name]' indicating the BUILD file to use is the one in the current directory

    If the pathish does not have a module suffix the targeted module name is taken to be the same
    name as the BUILD file's containing directory.  In this way the containing directory name
    becomes the 'default' module target for pants.

    If there is no BUILD file at the path pointed to, or if there is but the specified module target
    is not defined in the BUILD file, an IOError is raised."""

        parts = pathish.split(':') if not pathish.startswith(':') else [
            '.', pathish[1:]
        ]
        path, is_meta = Address._parse_meta(parts[0])
        if is_relative:
            path = os.path.relpath(os.path.abspath(path), root_dir)
        buildfile = BuildFile(root_dir, path)

        if len(parts) == 1:
            parent_name = os.path.basename(os.path.dirname(buildfile.relpath))
            return Address(buildfile, parent_name, is_meta)
        else:
            target_name, is_meta = Address._parse_meta(':'.join(parts[1:]))
            return Address(buildfile, target_name, is_meta)
Exemple #4
0
 def _candidate_owners(self, file):
   build_file = BuildFile(get_buildroot(), relpath=os.path.dirname(file), must_exist=False)
   if build_file.exists():
     yield build_file
   for sibling in build_file.siblings():
     yield sibling
   for ancestor in build_file.ancestors():
     yield ancestor
Exemple #5
0
 def _parse_addresses(self, spec):
   if spec.endswith('::'):
     dir = self._get_dir(spec[:-len('::')])
     for buildfile in BuildFile.scan_buildfiles(self._root_dir, os.path.join(self._root_dir, dir)):
       for address in Target.get_all_addresses(buildfile):
         yield address
   elif spec.endswith(':'):
     dir = self._get_dir(spec[:-len(':')])
     for address in Target.get_all_addresses(BuildFile(self._root_dir, dir)):
       yield address
   else:
     yield Address.parse(self._root_dir, spec)
Exemple #6
0
    def setup_parser(self, parser, args):
        self.config = Config.load()
        Goal.add_global_options(parser)

        # 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."
                """
                       Note that target specs accept two special forms:
                         [dir]:  to include all targets in the specified directory
                         [dir]:: to include all targets found in all BUILD files recursively under
                                 the directory""")

            parser.print_help()
            sys.exit(0)
        else:
            goals, specs = Goal.parse_args(args)
            self.requested_goals = goals

            with self.run_tracker.new_workunit(name='setup',
                                               labels=[WorkUnit.SETUP]):
                # Bootstrap goals by loading any configured bootstrap BUILD files
                with self.check_errors(
                        'The following bootstrap_buildfiles cannot be loaded:'
                ) as error:
                    with self.run_tracker.new_workunit(name='bootstrap',
                                                       labels=[WorkUnit.SETUP
                                                               ]):
                        for path in self.config.getlist('goals',
                                                        'bootstrap_buildfiles',
                                                        default=[]):
                            try:
                                buildfile = BuildFile(
                                    get_buildroot(),
                                    os.path.relpath(path, get_buildroot()))
                                ParseContext(buildfile).parse()
                            except (TypeError, ImportError, TaskError,
                                    GoalError):
                                error(path, include_traceback=True)
                            except (IOError, SyntaxError):
                                error(path)
                # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
                self.run_tracker.run_info.add_scm_info()

                # Bootstrap user goals by loading any BUILD files implied by targets.
                spec_parser = SpecParser(self.root_dir)
                with self.check_errors(
                        'The following targets could not be loaded:') as error:
                    with self.run_tracker.new_workunit(name='parse',
                                                       labels=[WorkUnit.SETUP
                                                               ]):
                        for spec in specs:
                            try:
                                for target, address in spec_parser.parse(spec):
                                    if target:
                                        self.targets.append(target)
                                        # Force early BUILD file loading if this target is an alias that expands
                                        # to others.
                                        unused = list(target.resolve())
                                    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, TaskError,
                                    GoalError):
                                error(spec, include_traceback=True)
                            except (IOError, SyntaxError,
                                    TargetDefinitionException):
                                error(spec)

            self.phases = [Phase(goal) for goal in goals]

            rcfiles = self.config.getdefault('rcfiles', type=list, default=[])
            if rcfiles:
                rcfile = RcFile(rcfiles,
                                default_prepend=False,
                                process_default=True)

                # Break down the goals specified on the command line to the full set that will be run so we
                # can apply default flags to inner goal nodes.  Also break down goals by Task subclass and
                # register the task class hierarchy fully qualified names so we can apply defaults to
                # baseclasses.

                sections = OrderedSet()
                for phase in Engine.execution_order(self.phases):
                    for goal in phase.goals():
                        sections.add(goal.name)
                        for clazz in goal.task_type.mro():
                            if clazz == Task:
                                break
                            sections.add('%s.%s' %
                                         (clazz.__module__, clazz.__name__))

                augmented_args = rcfile.apply_defaults(sections, args)
                if augmented_args != args:
                    del args[:]
                    args.extend(augmented_args)
                    sys.stderr.write(
                        "(using pantsrc expansion: pants goal %s)\n" %
                        ' '.join(augmented_args))

            Phase.setup_parser(parser, args, self.phases)
 def buildfile(cls, path):
   return BuildFile(BuildFileTest.root_dir, path)