예제 #1
0
    def test_locate(self):
        with pytest.raises(ParseContext.ContextError):
            ParseContext.locate()

        with temporary_dir() as root_dir:
            a_context = ParseContext(create_buildfile(root_dir, 'a'))
            b_context = ParseContext(create_buildfile(root_dir, 'b'))

            def test_in_a():
                self.assertEquals(a_context, ParseContext.locate())
                return b_context.do_in_context(lambda: ParseContext.locate())

            self.assertEquals(b_context, a_context.do_in_context(test_in_a))
예제 #2
0
    def test_sibling_references(self):
        with temporary_dir() as root_dir:
            buildfile = create_buildfile(root_dir,
                                         'a',
                                         name='BUILD',
                                         content=dedent("""
          dependencies(name='util',
            dependencies=[
              jar(org='com.twitter', name='util', rev='0.0.1')
            ]
          )
        """).strip())
            sibling = create_buildfile(root_dir,
                                       'a',
                                       name='BUILD.sibling',
                                       content=dedent("""
          dependencies(name='util-ex',
            dependencies=[
              pants(':util'),
              jar(org='com.twitter', name='util-ex', rev='0.0.1')
            ]
          )
        """).strip())
            ParseContext(buildfile).parse()

            utilex = Target.get(
                Address.parse(root_dir, 'a:util-ex', is_relative=False))
            utilex_deps = set(utilex.resolve())

            util = Target.get(
                Address.parse(root_dir, 'a:util', is_relative=False))
            util_deps = set(util.resolve())

            self.assertEquals(util_deps, util_deps.intersection(utilex_deps))
예제 #3
0
파일: target.py 프로젝트: wfarner/commons
    def get(address):
        """Returns the specified module target if already parsed; otherwise, parses the buildfile in the
    context of its parent directory and returns the parsed target."""
        def lookup():
            return Target._targets_by_address.get(address, None)

        target = lookup()
        if target:
            return target
        else:
            ParseContext(address.buildfile).parse()
            return lookup()
예제 #4
0
 def test_parse(self):
     with temporary_dir() as root_dir:
         buildfile = create_buildfile(root_dir,
                                      'a',
                                      content=dedent("""
       with open('%s/a/b', 'w') as b:
         b.write('jack spratt')
     """ % root_dir).strip())
         b_file = os.path.join(root_dir, 'a', 'b')
         self.assertFalse(os.path.exists(b_file))
         ParseContext(buildfile).parse()
         with open(b_file, 'r') as b:
             self.assertEquals('jack spratt', b.read())
예제 #5
0
파일: target.py 프로젝트: wickman/commons
    def get_all_addresses(cls, buildfile):
        """Returns all of the target addresses in the specified buildfile if already parsed; otherwise,
    parses the buildfile to find all the addresses it contains and then returns them."""
        def lookup():
            if buildfile in cls._addresses_by_buildfile:
                return cls._addresses_by_buildfile[buildfile]
            else:
                return OrderedSet()

        addresses = lookup()
        if addresses:
            return addresses
        else:
            ParseContext(buildfile).parse()
            return lookup()
예제 #6
0
    def test_on_context_exit(self):
        with temporary_dir() as root_dir:
            parse_context = ParseContext(create_buildfile(root_dir, 'a'))
            with pytest.raises(parse_context.ContextError):
                parse_context.on_context_exit(lambda: 37)

        with temporary_dir() as root_dir:
            buildfile = create_buildfile(root_dir,
                                         'a',
                                         content=dedent("""
          import os
          from twitter.pants.base.parse_context import ParseContext
          def leave_a_trail(file, contents=''):
            with open(file, 'w') as b:
              b.write(contents)
          b_file = os.path.join(os.path.dirname(__file__), 'b')
          ParseContext.locate().on_context_exit(leave_a_trail, b_file, contents='42')
          assert not os.path.exists(b_file), 'Expected context exit action to be delayed.'
        """).strip())
            b_file = os.path.join(root_dir, 'a', 'b')
            self.assertFalse(os.path.exists(b_file))
            ParseContext(buildfile).parse()
            with open(b_file, 'r') as b:
                self.assertEquals('42', b.read())
예제 #7
0
  def find(cls, target):
    """Finds the source root for the given target.

    If none is registered, returns the parent directory of the target's BUILD file.
    """
    target_path = os.path.relpath(target.address.buildfile.parent_path, get_buildroot())

    def _find():
      for root_dir, types in cls._TYPES_BY_ROOT.items():
        if target_path.startswith(root_dir):  # The only candidate root for this target.
          # Validate the target type, if restrictions were specified.
          if types and not isinstance(target, tuple(types)):
            # TODO: Find a way to use the BUILD file aliases in the error message, instead
            # of target.__class__.__name__. E.g., java_tests instead of JavaTests.
            raise TargetDefinitionException(target,
                'Target type %s not allowed under %s' % (target.__class__.__name__, root_dir))
          return root_dir
      return None

    # Try already registered roots
    root = _find()
    if root:
      return root

    # Fall back to searching the ancestor path for a root.
    # TODO(John Sirois): We currently allow for organic growth of maven multi-module layout style
    # projects (for example) and do not require a global up-front registration of all source roots
    # and instead do lazy resolution here.  This allows for parse cycles that lead to surprising
    # runtime errors.  Re-consider allowing lazy source roots at all.
    for buildfile in reversed(target.address.buildfile.ancestors()):
      if buildfile not in cls._SEARCHED:
        ParseContext(buildfile).parse()
        cls._SEARCHED.add(buildfile)
        root = _find()
        if root:
          return root

    # Finally, resolve files relative to the BUILD file parent dir as the target base
    return target_path
예제 #8
0
파일: target.py 프로젝트: wickman/commons
 def do_in_context(self, work):
     return ParseContext(self.address.buildfile).do_in_context(work)
예제 #9
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)