示例#1
0
 def address_map_from_spec_path(self, spec_path):
   build_file = BuildFile.from_cache(self._root_dir, spec_path)
   family_address_map_by_build_file = self.parse_build_file_family(build_file)
   address_map = {}
   for build_file, sibling_address_map in family_address_map_by_build_file.items():
     address_map.update(sibling_address_map)
   return address_map
示例#2
0
  def setup(self):
    options_bootstrapper = OptionsBootstrapper()

    # Force config into the cache so we (and plugin/backend loading code) can use it.
    # TODO: Plumb options in explicitly.
    options_bootstrapper.get_bootstrap_options()
    self.config = Config.from_cache()

    # Add any extra paths to python path (eg for loading extra source backends)
    extra_paths = self.config.getlist('backends', 'python-path', [])
    if extra_paths:
      sys.path.extend(extra_paths)

    # Load plugins and backends.
    backend_packages = self.config.getlist('backends', 'packages', [])
    plugins = self.config.getlist('backends', 'plugins', [])
    build_configuration = load_plugins_and_backends(plugins, backend_packages)

    # Now that plugins and backends are loaded, we can gather the known scopes.
    self.targets = []
    known_scopes = ['']
    for goal in Goal.all():
      # Note that enclosing scopes will appear before scopes they enclose.
      known_scopes.extend(filter(None, goal.known_scopes()))

    # Now that we have the known scopes we can get the full options.
    self.options = options_bootstrapper.get_full_options(known_scopes=known_scopes)
    self.register_options()

    self.run_tracker = RunTracker.from_config(self.config)
    report = initial_reporting(self.config, self.run_tracker)
    self.run_tracker.start(report)
    url = self.run_tracker.run_info.get_info('report_url')
    if url:
      self.run_tracker.log(Report.INFO, 'See a report at: %s' % url)
    else:
      self.run_tracker.log(Report.INFO, '(To run a reporting server: ./pants server)')

    self.build_file_parser = BuildFileParser(build_configuration=build_configuration,
                                             root_dir=self.root_dir,
                                             run_tracker=self.run_tracker)
    self.address_mapper = BuildFileAddressMapper(self.build_file_parser)
    self.build_graph = BuildGraph(run_tracker=self.run_tracker,
                                  address_mapper=self.address_mapper)

    with self.run_tracker.new_workunit(name='bootstrap', labels=[WorkUnit.SETUP]):
      # construct base parameters to be filled in for BuildGraph
      for path in self.config.getlist('goals', 'bootstrap_buildfiles', default=[]):
        build_file = BuildFile.from_cache(root_dir=self.root_dir, relpath=path)
        # TODO(pl): This is an unfortunate interface leak, but I don't think
        # in the long run that we should be relying on "bootstrap" BUILD files
        # that do nothing except modify global state.  That type of behavior
        # (e.g. source roots, goal registration) should instead happen in
        # project plugins, or specialized configuration files.
        self.build_file_parser.parse_build_file_family(build_file)

    # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
    self.run_tracker.run_info.add_scm_info()

    self._expand_goals_and_specs()
示例#3
0
    def _expand_goals_and_specs(self):
        goals = self.options.goals
        specs = self.options.target_specs
        fail_fast = self.options.for_global_scope().fail_fast

        for goal in goals:
            if BuildFile.from_cache(get_buildroot(), goal,
                                    must_exist=False).exists():
                logger.warning(
                    " Command-line argument '{0}' is ambiguous and was assumed to be "
                    "a goal. If this is incorrect, disambiguate it with ./{0}."
                    .format(goal))

        if self.options.print_help_if_requested():
            sys.exit(0)

        self.requested_goals = goals

        with self.run_tracker.new_workunit(name='setup',
                                           labels=[WorkUnit.SETUP]):
            spec_parser = CmdLineSpecParser(
                self.root_dir,
                self.address_mapper,
                spec_excludes=self.spec_excludes,
                exclude_target_regexps=self.global_options.
                exclude_target_regexp)
            with self.run_tracker.new_workunit(name='parse',
                                               labels=[WorkUnit.SETUP]):
                for spec in specs:
                    for address in spec_parser.parse_addresses(
                            spec, fail_fast):
                        self.build_graph.inject_address_closure(address)
                        self.targets.append(
                            self.build_graph.get_target(address))
        self.goals = [Goal.by_name(goal) for goal in goals]
示例#4
0
  def _expand_goals_and_specs(self):
    goals = self.options.goals
    specs = self.options.target_specs
    fail_fast = self.options.for_global_scope().fail_fast

    for goal in goals:
      if BuildFile.from_cache(get_buildroot(), goal, must_exist=False).exists():
        logger.warning(" Command-line argument '{0}' is ambiguous and was assumed to be "
                       "a goal. If this is incorrect, disambiguate it with ./{0}.".format(goal))

    if self.options.print_help_if_requested():
      sys.exit(0)

    self.requested_goals = goals

    with self.run_tracker.new_workunit(name='setup', labels=[WorkUnit.SETUP]):
      spec_parser = CmdLineSpecParser(self.root_dir, self.address_mapper,
                                      spec_excludes=self.spec_excludes,
                                      exclude_target_regexps=self.global_options.exclude_target_regexp)
      with self.run_tracker.new_workunit(name='parse', labels=[WorkUnit.SETUP]):
        for spec in specs:
          for address in spec_parser.parse_addresses(spec, fail_fast):
            self.build_graph.inject_address_closure(address)
            self.targets.append(self.build_graph.get_target(address))
    self.goals = [Goal.by_name(goal) for goal in goals]
示例#5
0
文件: command.py 项目: sikopet/pants
    def __init__(self,
                 run_tracker,
                 root_dir,
                 parser,
                 args,
                 build_file_parser,
                 address_mapper,
                 build_graph,
                 needs_old_options=True):
        """run_tracker: The (already opened) RunTracker to track this run with
    root_dir: The root directory of the pants workspace
    parser: an OptionParser
    args: the subcommand arguments to parse"""
        self.run_tracker = run_tracker
        self.root_dir = root_dir
        self.build_file_parser = build_file_parser
        self.address_mapper = address_mapper
        self.build_graph = build_graph

        config = Config.from_cache()

        with self.run_tracker.new_workunit(name='bootstrap',
                                           labels=[WorkUnit.SETUP]):
            # construct base parameters to be filled in for BuildGraph
            for path in config.getlist('goals',
                                       'bootstrap_buildfiles',
                                       default=[]):
                build_file = BuildFile.from_cache(root_dir=self.root_dir,
                                                  relpath=path)
                # TODO(pl): This is an unfortunate interface leak, but I don't think
                # in the long run that we should be relying on "bootstrap" BUILD files
                # that do nothing except modify global state.  That type of behavior
                # (e.g. source roots, goal registration) should instead happen in
                # project plugins, or specialized configuration files.
                self.build_file_parser.parse_build_file_family(build_file)

        # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
        self.run_tracker.run_info.add_scm_info()

        # Override the OptionParser's error with more useful output
        def error(message=None, show_help=True):
            if message:
                print(message + '\n')
            if show_help:
                parser.print_help()
            parser.exit(status=1)

        parser.error = error
        self.error = error

        self.register_options()
        self.setup_parser(parser, args)
        if needs_old_options:
            self.old_options, self.args = parser.parse_args(args)
        else:
            # Ensure a predictable error if anything under goal tries to use these.
            self.old_options = None
            self.args = None
示例#6
0
  def setup_parser(self, parser, args):
    if not args:
      args.append('help')

    logger = logging.getLogger(__name__)

    goals = self.new_options.goals
    specs = self.new_options.target_specs
    fail_fast = self.new_options.for_global_scope().fail_fast

    for goal in goals:
      if BuildFile.from_cache(get_buildroot(), goal, must_exist=False).exists():
        logger.warning(" Command-line argument '{0}' is ambiguous and was assumed to be "
                       "a goal. If this is incorrect, disambiguate it with ./{0}.".format(goal))

    if self.new_options.is_help:
      self.new_options.print_help(goals=goals)
      sys.exit(0)

    self.requested_goals = goals

    with self.run_tracker.new_workunit(name='setup', labels=[WorkUnit.SETUP]):
      spec_parser = CmdLineSpecParser(self.root_dir, self.address_mapper,
                                      spec_excludes=self.get_spec_excludes())
      with self.run_tracker.new_workunit(name='parse', labels=[WorkUnit.SETUP]):
        for spec in specs:
          for address in spec_parser.parse_addresses(spec, fail_fast):
            self.build_graph.inject_address_closure(address)
            self.targets.append(self.build_graph.get_target(address))
    self.goals = [Goal.by_name(goal) for goal in goals]

    rcfiles = self.config.getdefault('rcfiles', type=list,
                                     default=['/etc/pantsrc', '~/.pants.rc'])
    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 goal in Engine.execution_order(self.goals):
        for task_name in goal.ordered_task_names():
          sections.add(task_name)
          task_type = goal.task_type_by_name(task_name)
          for clazz in 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:
        # TODO(John Sirois): Cleanup this currently important mutation of the passed in args
        # once the 2-layer of command -> goal is squashed into one.
        args[:] = augmented_args
        sys.stderr.write("(using pantsrc expansion: pants goal %s)\n" % ' '.join(augmented_args))
示例#7
0
 def _candidate_owners(self, path):
   build_file = BuildFile.from_cache(get_buildroot(),
                                     relpath=os.path.dirname(path),
                                     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
示例#8
0
    def _parse_spec(self, spec):
        def normalize_spec_path(path):
            is_abs = not path.startswith('//') and os.path.isabs(path)
            if is_abs:
                path = os.path.realpath(path)
                if os.path.commonprefix([self._root_dir, path
                                         ]) != self._root_dir:
                    raise self.BadSpecError(
                        'Absolute address path {0} does not share build root {1}'
                        .format(path, self._root_dir))
            else:
                if path.startswith('//'):
                    path = path[2:]
                path = os.path.join(self._root_dir, path)

            normalized = os.path.relpath(path, self._root_dir)
            if normalized == '.':
                normalized = ''
            return normalized

        if spec.endswith('::'):
            addresses = set()
            spec_path = spec[:-len('::')]
            spec_dir = normalize_spec_path(spec_path)
            if not os.path.isdir(os.path.join(self._root_dir, spec_dir)):
                raise self.BadSpecError(
                    'Can only recursive glob directories and {0} is not a valid dir'
                    .format(spec_dir))
            try:
                for build_file in BuildFile.scan_buildfiles(
                        self._root_dir, spec_dir):
                    addresses.update(
                        self._address_mapper.addresses_in_spec_path(
                            build_file.spec_path))
                return addresses
            except (BuildFile.BuildFileError, AddressLookupError) as e:
                raise self.BadSpecError(e)
        elif spec.endswith(':'):
            spec_path = spec[:-len(':')]
            spec_dir = normalize_spec_path(spec_path)
            try:
                return set(
                    self._address_mapper.addresses_in_spec_path(spec_dir))
            except AddressLookupError as e:
                raise self.BadSpecError(e)
        else:
            spec_parts = spec.rsplit(':', 1)
            spec_parts[0] = normalize_spec_path(spec_parts[0])
            spec_path, target_name = parse_spec(':'.join(spec_parts))
            try:
                build_file = BuildFile.from_cache(self._root_dir, spec_path)
                return set([BuildFileAddress(build_file, target_name)])
            except BuildFile.BuildFileError as e:
                raise self.BadSpecError(e)
示例#9
0
 def is_spec(spec):
   if os.sep in spec or ':' in spec:
     return True # Definitely not a goal.
   if not (spec in goal_names):
     return True # Definitely not a (known) goal.
   if has_double_dash:
     # This means that we're parsing the half of the expression before a --, so assume it's a
     # goal without warning.
     return False
   # Here, it's possible we have a goal and target with the same name. For now, always give
   # priority to the goal, but give a warning if they might have meant the target (if the BUILD
   # file exists).
   try:
     BuildFile.from_cache(get_buildroot(), spec)
     msg = (' Command-line argument "{spec}" is ambiguous, and was assumed to be a goal.'
            ' If this is incorrect, disambiguate it with the "--" argument to separate goals'
            ' from targets.')
     logger.warning(msg.format(spec=spec))
   except IOError: pass # Awesome, it's unambiguous.
   return False
示例#10
0
文件: command.py 项目: rgbenson/pants
  def __init__(self,
               run_tracker,
               root_dir,
               parser,
               args,
               build_file_parser,
               address_mapper,
               build_graph,
               needs_old_options=True):
    """run_tracker: The (already opened) RunTracker to track this run with
    root_dir: The root directory of the pants workspace
    parser: an OptionParser
    args: the subcommand arguments to parse"""
    self.run_tracker = run_tracker
    self.root_dir = root_dir
    self.build_file_parser = build_file_parser
    self.address_mapper = address_mapper
    self.build_graph = build_graph

    config = Config.from_cache()

    with self.run_tracker.new_workunit(name='bootstrap', labels=[WorkUnit.SETUP]):
      # construct base parameters to be filled in for BuildGraph
      for path in config.getlist('goals', 'bootstrap_buildfiles', default=[]):
        build_file = BuildFile.from_cache(root_dir=self.root_dir, relpath=path)
        # TODO(pl): This is an unfortunate interface leak, but I don't think
        # in the long run that we should be relying on "bootstrap" BUILD files
        # that do nothing except modify global state.  That type of behavior
        # (e.g. source roots, goal registration) should instead happen in
        # project plugins, or specialized configuration files.
        self.build_file_parser.parse_build_file_family(build_file)

    # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
    self.run_tracker.run_info.add_scm_info()

    # Override the OptionParser's error with more useful output
    def error(message=None, show_help=True):
      if message:
        print(message + '\n')
      if show_help:
        parser.print_help()
      parser.exit(status=1)
    parser.error = error
    self.error = error

    self.register_options()
    self.setup_parser(parser, args)
    if needs_old_options:
      self.old_options, self.args = parser.parse_args(args)
    else:
      # Ensure a predictable error if anything under goal tries to use these.
      self.old_options = None
      self.args = None
示例#11
0
 def address_map_from_spec_path(self, spec_path):
   try:
     build_file = BuildFile.from_cache(self._root_dir, spec_path)
   except BuildFile.BuildFileError as e:
     raise self.BuildFileScanError("{message}\n searching {spec_path}"
                                   .format(message=e,
                                           spec_path=spec_path))
   family_address_map_by_build_file = self.parse_build_file_family(build_file)
   address_map = {}
   for build_file, sibling_address_map in family_address_map_by_build_file.items():
     address_map.update(sibling_address_map)
   return address_map
示例#12
0
 def resolve(self, address):
   """Maps an address in the virtual address space to an object.
   :param Address address: the address to lookup in a BUILD file
   :raises AddressLookupError: if the path to the address is not found.
   :returns: Addressable from a build file specified by address
   """
   address_map = self.address_map_from_spec_path(address.spec_path)
   if address not in address_map:
     build_file = BuildFile.from_cache(self.root_dir, address.spec_path, must_exist=False)
     self._raise_incorrect_address_error(build_file, address.target_name, address_map)
   else:
     return address_map[address]
示例#13
0
 def resolve(self, address):
   """Maps an address in the virtual address space to an object.
   :param Address address: the address to lookup in a BUILD file
   :raises AddressLookupError: if the path to the address is not found.
   :returns: Addressable from a build file specified by address
   """
   address_map = self.address_map_from_spec_path(address.spec_path)
   if address not in address_map:
     build_file = BuildFile.from_cache(self.root_dir, address.spec_path, must_exist=False)
     self._raise_incorrect_address_error(build_file, address.target_name, address_map)
   else:
     return address_map[address]
示例#14
0
 def spec_to_address(self, spec, relative_to=''):
   """A helper method for mapping a spec to the correct BuildFileAddress.
   :param spec: a spec to lookup in the map.
   :raises AddressLookupError: if the BUILD file cannot be found in the path specified by the spec
   :returns a new BuildFileAddress instanace
   """
   spec_path, name = parse_spec(spec, relative_to=relative_to)
   try:
     build_file = BuildFile.from_cache(self.root_dir, spec_path)
   except BuildFile.BuildFileError as e:
     raise self.InvalidBuildFileReference('{message}\n  when translating spec {spec}'
                                          .format(message=e, spec=spec))
   return BuildFileAddress(build_file, name)
示例#15
0
 def spec_to_address(self, spec, relative_to=''):
   """A helper method for mapping a spec to the correct BuildFileAddress.
   :param spec: a spec to lookup in the map.
   :raises AddressLookupError: if the BUILD file cannot be found in the path specified by the spec
   :returns a new BuildFileAddress instanace
   """
   spec_path, name = parse_spec(spec, relative_to=relative_to)
   try:
     build_file = BuildFile.from_cache(self.root_dir, spec_path)
   except BuildFile.BuildFileError as e:
     raise self.InvalidBuildFileReference('{message}\n  when translating spec {spec}'
                                          .format(message=e, spec=spec))
   return BuildFileAddress(build_file, name)
示例#16
0
  def _parse_spec(self, spec):
    def normalize_spec_path(path):
      is_abs = not path.startswith('//') and os.path.isabs(path)
      if is_abs:
        path = os.path.realpath(path)
        if os.path.commonprefix([self._root_dir, path]) != self._root_dir:
          raise self.BadSpecError('Absolute spec path {0} does not share build root {1}'
                                  .format(path, self._root_dir))
      else:
        if path.startswith('//'):
          path = path[2:]
        path = os.path.join(self._root_dir, path)

      normalized = os.path.relpath(path, self._root_dir)
      if normalized == '.':
        normalized = ''
      return normalized

    if spec.endswith('::'):
      addresses = set()
      spec_path = spec[:-len('::')]
      spec_dir = normalize_spec_path(spec_path)
      if not os.path.isdir(os.path.join(self._root_dir, spec_dir)):
        raise self.BadSpecError('Can only recursive glob directories and {0} is not a valid dir'
                                .format(spec_dir))
      try:
        for build_file in BuildFile.scan_buildfiles(self._root_dir, spec_dir):
          addresses.update(self._address_mapper.addresses_in_spec_path(build_file.spec_path))
        return addresses
      except (IOError, BuildFile.MissingBuildFileError, AddressLookupError) as e:
        raise self.BadSpecError(e)
    elif spec.endswith(':'):
      spec_path = spec[:-len(':')]
      spec_dir = normalize_spec_path(spec_path)
      try:
        return set(self._address_mapper.addresses_in_spec_path(spec_dir))
      except (IOError,  BuildFile.MissingBuildFileError, AddressLookupError) as e:
        raise self.BadSpecError(e)
    else:
      spec_parts = spec.rsplit(':', 1)
      spec_parts[0] = normalize_spec_path(spec_parts[0])
      spec_path, target_name = parse_spec(':'.join(spec_parts))
      try:
        build_file = BuildFile.from_cache(self._root_dir, spec_path)
        return set([BuildFileAddress(build_file, target_name)])
      except (IOError, BuildFile.MissingBuildFileError) as e:
        raise self.BadSpecError(e)
示例#17
0
 def is_spec(spec):
     if os.sep in spec or ':' in spec:
         return True  # Definitely not a goal.
     if not (spec in goal_names):
         return True  # Definitely not a (known) goal.
     if has_double_dash:
         # This means that we're parsing the half of the expression before a --, so assume it's a
         # goal without warning.
         return False
     # Here, it's possible we have a goal and target with the same name. For now, always give
     # priority to the goal, but give a warning if they might have meant the target (if the BUILD
     # file exists).
     if BuildFile.from_cache(get_buildroot(), spec,
                             must_exist=False).exists():
         logger.warning(
             ' Command-line argument "{spec}" is ambiguous, and was assumed to be a '
             'goal.  If this is incorrect, disambiguate it with the "--" argument to '
             'separate goals from targets.'.format(spec=spec))
     return False
示例#18
0
 def is_spec(spec):
     if os.sep in spec or ":" in spec:
         return True  # Definitely not a goal.
     if not (spec in goal_names):
         return True  # Definitely not a (known) goal.
     if has_double_dash:
         # This means that we're parsing the half of the expression before a --, so assume it's a
         # goal without warning.
         return False
     # Here, it's possible we have a goal and target with the same name. For now, always give
     # priority to the goal, but give a warning if they might have meant the target (if the BUILD
     # file exists).
     if BuildFile.from_cache(get_buildroot(), spec, must_exist=False).exists():
         logger.warning(
             ' Command-line argument "{spec}" is ambiguous, and was assumed to be a '
             'goal.  If this is incorrect, disambiguate it with the "--" argument to '
             "separate goals from targets.".format(spec=spec)
         )
     return False
示例#19
0
    def _find_owners(self, source):
        """Searches for BUILD files adjacent or above a source in the file hierarchy.
    - Walks up the directory tree until it reaches a previously searched path.
    - Stops after looking in the buildroot.

    If self._stop_after_match is set, stops searching once a source is mapped, even if the parent
    has yet to be searched. See class docstring for discussion.

    :param str source: The source at which to start the search.
    """
        # Bail instantly if a source has already been searched
        if source in self._searched_sources:
            return
        self._searched_sources.add(source)

        root = get_buildroot()
        path = os.path.dirname(source)

        # a top-level source has empty dirname, so do/while instead of straight while loop.
        walking = True
        while walking:
            # It is possible
            if path not in self._mapped_paths:
                candidate = BuildFile.from_cache(root_dir=root,
                                                 relpath=path,
                                                 must_exist=False)
                if candidate.exists():
                    self._map_sources_from_family(candidate.family())
                self._mapped_paths.add(path)
            elif not self._stop_after_match:
                # If not in stop-after-match mode, once a path is seen visited, all parents can be assumed.
                return

            # See class docstring
            if self._stop_after_match and source in self._source_to_address:
                return

            walking = bool(path)
            path = os.path.dirname(path)
示例#20
0
  def _find_owners(self, source):
    """Searches for BUILD files adjacent or above a source in the file hierarchy.
    - Walks up the directory tree until it reaches a previously searched path.
    - Stops after looking in the buildroot.

    If self._stop_after_match is set, stops searching once a source is mapped, even if the parent
    has yet to be searched. See class docstring for discussion.

    :param str source: The source at which to start the search.
    """
    # Bail instantly if a source has already been searched
    if source in self._searched_sources:
      return
    self._searched_sources.add(source)

    root = get_buildroot()
    path = os.path.dirname(source)

    # a top-level source has empty dirname, so do/while instead of straight while loop.
    walking = True
    while walking:
      # It is possible
      if path not in self._mapped_paths:
        candidate = BuildFile.from_cache(root_dir=root, relpath=path, must_exist=False)
        if candidate.exists():
          self._map_sources_from_family(candidate.family())
        self._mapped_paths.add(path)
      elif not self._stop_after_match:
        # If not in stop-after-match mode, once a path is seen visited, all parents can be assumed.
        return

      # See class docstring
      if self._stop_after_match and source in self._source_to_address:
        return

      walking = bool(path)
      path = os.path.dirname(path)
示例#21
0
 def spec_to_address(self, spec, relative_to=''):
   """A helper method for mapping a spec to the correct BuildFileAddress."""
   spec_path, name = parse_spec(spec, relative_to=relative_to)
   build_file = BuildFile.from_cache(self.root_dir, spec_path)
   return BuildFileAddress(build_file, name)
示例#22
0
文件: py.py 项目: sheltowt/pants
    def __init__(self, *args, **kwargs):
        super(Py, self).__init__(*args, **kwargs)

        self.binary = None
        self.targets = []
        self.extra_requirements = []
        self.config = Config.load()

        interpreters = self.options.interpreters or [b'']
        self.interpreter_cache = PythonInterpreterCache(self.config,
                                                        logger=self.debug)
        self.interpreter_cache.setup(filters=interpreters)
        interpreters = self.interpreter_cache.select_interpreter(
            list(self.interpreter_cache.matches(interpreters)))
        if len(interpreters) != 1:
            self.error('Unable to detect suitable interpreter.')
        self.interpreter = interpreters[0]

        for req in self.options.extra_requirements:
            self.extra_requirements.append(
                PythonRequirement(req, use_2to3=True))

        # We parse each arg in the context of the cli usage:
        #   ./pants command (options) [spec] (build args)
        #   ./pants command (options) [spec]... -- (build args)
        # Our command token and our options are parsed out so we see args of the form:
        #   [spec] (build args)
        #   [spec]... -- (build args)
        for k in range(len(self.args)):
            arg = self.args.pop(0)
            if arg == '--':
                break

            def not_a_target(debug_msg):
                self.debug('Not a target, assuming option: %s.' % debug_msg)
                # We failed to parse the arg as a target or else it was in valid address format but did not
                # correspond to a real target.  Assume this is the 1st of the build args and terminate
                # processing args for target addresses.
                self.args.insert(0, arg)

            try:
                print(self.root_dir, arg, file=sys.stderr)
                self.build_graph.inject_spec_closure(arg)
                spec_path, target_name = parse_spec(arg)
                build_file = BuildFile.from_cache(self.root_dir, spec_path)
                address = BuildFileAddress(build_file, target_name)
                target = self.build_graph.get_target(address)
                if target is None:
                    not_a_target(debug_msg='Unrecognized target')
                    break
            except Exception as e:
                not_a_target(debug_msg=e)
                break

            if isinstance(target, PythonBinary):
                if self.binary:
                    self.error(
                        'Can only process 1 binary target. Found %s and %s.' %
                        (self.binary, target))
                else:
                    self.binary = target
            self.targets.append(target)

        if not self.targets:
            self.error('No valid targets specified!')
示例#23
0
    def setup(self):
        options_bootstrapper = OptionsBootstrapper()

        # Force config into the cache so we (and plugin/backend loading code) can use it.
        # TODO: Plumb options in explicitly.
        bootstrap_options = options_bootstrapper.get_bootstrap_options()
        self.config = Config.from_cache()

        # Add any extra paths to python path (eg for loading extra source backends)
        for path in bootstrap_options.for_global_scope().pythonpath:
            sys.path.append(path)
            pkg_resources.fixup_namespace_packages(path)

        # Load plugins and backends.
        backend_packages = self.config.getlist('backends', 'packages', [])
        plugins = self.config.getlist('backends', 'plugins', [])
        build_configuration = load_plugins_and_backends(
            plugins, backend_packages)

        # Now that plugins and backends are loaded, we can gather the known scopes.
        self.targets = []
        # TODO: Create a 'Subsystem' abstraction instead of special-casing run-tracker here
        # and in register_options().
        known_scopes = ['', 'run-tracker']
        for goal in Goal.all():
            # Note that enclosing scopes will appear before scopes they enclose.
            known_scopes.extend(filter(None, goal.known_scopes()))

        # Now that we have the known scopes we can get the full options.
        self.options = options_bootstrapper.get_full_options(
            known_scopes=known_scopes)
        self.register_options()

        # TODO(Eric Ayers) We are missing log messages. Set the log level earlier
        # Enable standard python logging for code with no handle to a context/work-unit.
        self._setup_logging()  # NB: self.options are needed for this call.

        self.run_tracker = RunTracker.from_options(self.options)
        report = initial_reporting(self.config, self.run_tracker)
        self.run_tracker.start(report)
        url = self.run_tracker.run_info.get_info('report_url')
        if url:
            self.run_tracker.log(Report.INFO, 'See a report at: %s' % url)
        else:
            self.run_tracker.log(
                Report.INFO, '(To run a reporting server: ./pants server)')

        self.build_file_parser = BuildFileParser(
            build_configuration=build_configuration,
            root_dir=self.root_dir,
            run_tracker=self.run_tracker)
        self.address_mapper = BuildFileAddressMapper(self.build_file_parser)
        self.build_graph = BuildGraph(run_tracker=self.run_tracker,
                                      address_mapper=self.address_mapper)

        with self.run_tracker.new_workunit(name='bootstrap',
                                           labels=[WorkUnit.SETUP]):
            # construct base parameters to be filled in for BuildGraph
            for path in self.config.getlist('goals',
                                            'bootstrap_buildfiles',
                                            default=[]):
                build_file = BuildFile.from_cache(root_dir=self.root_dir,
                                                  relpath=path)
                # TODO(pl): This is an unfortunate interface leak, but I don't think
                # in the long run that we should be relying on "bootstrap" BUILD files
                # that do nothing except modify global state.  That type of behavior
                # (e.g. source roots, goal registration) should instead happen in
                # project plugins, or specialized configuration files.
                self.build_file_parser.parse_build_file_family(build_file)

        # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
        self.run_tracker.run_info.add_scm_info()

        self._expand_goals_and_specs()
示例#24
0
    def setup_parser(self, parser, args):
        if not args:
            args.append('help')

        logger = logging.getLogger(__name__)

        goals = self.new_options.goals
        specs = self.new_options.target_specs
        fail_fast = self.new_options.for_global_scope().fail_fast

        for goal in goals:
            if BuildFile.from_cache(get_buildroot(), goal,
                                    must_exist=False).exists():
                logger.warning(
                    " Command-line argument '{0}' is ambiguous and was assumed to be "
                    "a goal. If this is incorrect, disambiguate it with ./{0}."
                    .format(goal))

        if self.new_options.is_help:
            self.new_options.print_help(goals=goals)
            sys.exit(0)

        self.requested_goals = goals

        with self.run_tracker.new_workunit(name='setup',
                                           labels=[WorkUnit.SETUP]):
            spec_parser = CmdLineSpecParser(
                self.root_dir,
                self.address_mapper,
                spec_excludes=self.get_spec_excludes())
            with self.run_tracker.new_workunit(name='parse',
                                               labels=[WorkUnit.SETUP]):
                for spec in specs:
                    for address in spec_parser.parse_addresses(
                            spec, fail_fast):
                        self.build_graph.inject_address_closure(address)
                        self.targets.append(
                            self.build_graph.get_target(address))
        self.goals = [Goal.by_name(goal) for goal in goals]

        rcfiles = self.config.getdefault(
            'rcfiles', type=list, default=['/etc/pantsrc', '~/.pants.rc'])
        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 goal in Engine.execution_order(self.goals):
                for task_name in goal.ordered_task_names():
                    sections.add(task_name)
                    task_type = goal.task_type_by_name(task_name)
                    for clazz in 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:
                # TODO(John Sirois): Cleanup this currently important mutation of the passed in args
                # once the 2-layer of command -> goal is squashed into one.
                args[:] = augmented_args
                sys.stderr.write("(using pantsrc expansion: pants goal %s)\n" %
                                 ' '.join(augmented_args))
示例#25
0
    def _parse_spec(self, spec, fail_fast=False):
        def normalize_spec_path(path):
            is_abs = not path.startswith('//') and os.path.isabs(path)
            if is_abs:
                path = os.path.realpath(path)
                if os.path.commonprefix([self._root_dir, path
                                         ]) != self._root_dir:
                    raise self.BadSpecError(
                        'Absolute address path {0} does not share build root {1}'
                        .format(path, self._root_dir))
            else:
                if path.startswith('//'):
                    path = path[2:]
                path = os.path.join(self._root_dir, path)

            normalized = os.path.relpath(path, self._root_dir)
            if normalized == '.':
                normalized = ''
            return normalized

        errored_out = []

        if spec.endswith('::'):
            addresses = set()
            spec_path = spec[:-len('::')]
            spec_dir = normalize_spec_path(spec_path)
            if not os.path.isdir(os.path.join(self._root_dir, spec_dir)):
                raise self.BadSpecError(
                    'Can only recursive glob directories and {0} is not a valid dir'
                    .format(spec_dir))
            try:
                build_files = BuildFile.scan_buildfiles(
                    self._root_dir,
                    spec_dir,
                    spec_excludes=self._spec_excludes)
            except (BuildFile.BuildFileError, AddressLookupError) as e:
                raise self.BadSpecError(e)

            for build_file in build_files:
                try:
                    # This attempts to filter out broken BUILD files before we parse them.
                    if self._not_excluded_spec(build_file.spec_path):
                        addresses.update(
                            self._address_mapper.addresses_in_spec_path(
                                build_file.spec_path))
                except (BuildFile.BuildFileError, AddressLookupError) as e:
                    if fail_fast:
                        raise self.BadSpecError(e)
                    errored_out.append('--------------------')
                    errored_out.append(traceback.format_exc())
                    errored_out.append('Exception message: {0}'.format(
                        e.message))

            if errored_out:
                error_msg = '\n'.join(
                    errored_out +
                    ["Invalid BUILD files for [{0}]".format(spec)])
                raise self.BadSpecError(error_msg)
            return addresses

        elif spec.endswith(':'):
            spec_path = spec[:-len(':')]
            spec_dir = normalize_spec_path(spec_path)
            try:
                return set(
                    self._address_mapper.addresses_in_spec_path(spec_dir))
            except AddressLookupError as e:
                raise self.BadSpecError(e)
        else:
            spec_parts = spec.rsplit(':', 1)
            spec_parts[0] = normalize_spec_path(spec_parts[0])
            spec_path, target_name = parse_spec(':'.join(spec_parts))
            try:
                build_file = BuildFile.from_cache(self._root_dir, spec_path)
                return set([BuildFileAddress(build_file, target_name)])
            except BuildFile.BuildFileError as e:
                raise self.BadSpecError(e)
示例#26
0
  def _parse_spec(self, spec, fail_fast=False):
    def normalize_spec_path(path):
      is_abs = not path.startswith('//') and os.path.isabs(path)
      if is_abs:
        path = os.path.realpath(path)
        if os.path.commonprefix([self._root_dir, path]) != self._root_dir:
          raise self.BadSpecError('Absolute address path {0} does not share build root {1}'
                                  .format(path, self._root_dir))
      else:
        if path.startswith('//'):
          path = path[2:]
        path = os.path.join(self._root_dir, path)

      normalized = os.path.relpath(path, self._root_dir)
      if normalized == '.':
        normalized = ''
      return normalized

    errored_out = []

    if spec.endswith('::'):
      addresses = set()
      spec_path = spec[:-len('::')]
      spec_dir = normalize_spec_path(spec_path)
      if not os.path.isdir(os.path.join(self._root_dir, spec_dir)):
        raise self.BadSpecError('Can only recursive glob directories and {0} is not a valid dir'
                                .format(spec_dir))
      try:
        build_files = BuildFile.scan_buildfiles(self._root_dir, spec_dir, spec_excludes=self._spec_excludes)
      except (BuildFile.BuildFileError, AddressLookupError) as e:
        raise self.BadSpecError(e)

      for build_file in build_files:
        try:
          # This attempts to filter out broken BUILD files before we parse them.
          if self._not_excluded_spec(build_file.spec_path):
            addresses.update(self._address_mapper.addresses_in_spec_path(build_file.spec_path))
        except (BuildFile.BuildFileError, AddressLookupError) as e:
          if fail_fast:
            raise self.BadSpecError(e)
          errored_out.append('--------------------')
          errored_out.append(traceback.format_exc())
          errored_out.append('Exception message: {0}'.format(e.message))

      if errored_out:
        error_msg = '\n'.join(errored_out + ["Invalid BUILD files for [{0}]".format(spec)])
        raise self.BadSpecError(error_msg)
      return addresses

    elif spec.endswith(':'):
      spec_path = spec[:-len(':')]
      spec_dir = normalize_spec_path(spec_path)
      try:
        return set(self._address_mapper.addresses_in_spec_path(spec_dir))
      except AddressLookupError as e:
        raise self.BadSpecError(e)
    else:
      spec_parts = spec.rsplit(':', 1)
      spec_parts[0] = normalize_spec_path(spec_parts[0])
      spec_path, target_name = parse_spec(':'.join(spec_parts))
      try:
        build_file = BuildFile.from_cache(self._root_dir, spec_path)
        return set([BuildFileAddress(build_file, target_name)])
      except BuildFile.BuildFileError as e:
        raise self.BadSpecError(e)
示例#27
0
文件: py.py 项目: rgbenson/pants
  def __init__(self, *args, **kwargs):
    super(Py, self).__init__(*args, **kwargs)

    self.binary = None
    self.targets = []
    self.extra_requirements = []
    self.config = Config.from_cache()

    interpreters = self.old_options.interpreters or [b'']
    self.interpreter_cache = PythonInterpreterCache(self.config, logger=self.debug)
    self.interpreter_cache.setup(filters=interpreters)
    interpreters = self.interpreter_cache.select_interpreter(
        list(self.interpreter_cache.matches(interpreters)))
    if len(interpreters) != 1:
      self.error('Unable to detect suitable interpreter.')
    self.interpreter = interpreters[0]

    for req in self.old_options.extra_requirements:
      self.extra_requirements.append(PythonRequirement(req, use_2to3=True))

    # We parse each arg in the context of the cli usage:
    #   ./pants command (options) [spec] (build args)
    #   ./pants command (options) [spec]... -- (build args)
    # Our command token and our options are parsed out so we see args of the form:
    #   [spec] (build args)
    #   [spec]... -- (build args)
    for k in range(len(self.args)):
      arg = self.args.pop(0)
      if arg == '--':
        break

      def not_a_target(debug_msg):
        self.debug('Not a target, assuming option: %s.' % debug_msg)
        # We failed to parse the arg as a target or else it was in valid address format but did not
        # correspond to a real target.  Assume this is the 1st of the build args and terminate
        # processing args for target addresses.
        self.args.insert(0, arg)

      try:
        print(self.root_dir, arg, file=sys.stderr)
        self.build_graph.inject_spec_closure(arg)
        spec_path, target_name = parse_spec(arg)
        build_file = BuildFile.from_cache(self.root_dir, spec_path)
        address = BuildFileAddress(build_file, target_name)
        target = self.build_graph.get_target(address)
        if target is None:
          not_a_target(debug_msg='Unrecognized target')
          break
      except Exception as e:
        not_a_target(debug_msg=e)
        break

      if isinstance(target, PythonBinary):
        if self.binary:
          self.error('Can only process 1 binary target. Found %s and %s.' % (self.binary, target))
        else:
          self.binary = target
      self.targets.append(target)

    if not self.targets:
      self.error('No valid targets specified!')