Esempio n. 1
0
 def test_longest_dir_prefix(self) -> None:
     # Find the longest prefix (standard case).
     prefixes = ["hello", "hello_world", "hello/world", "helloworld"]
     assert longest_dir_prefix("hello/world/pants", prefixes) == "hello/world"
     assert longest_dir_prefix("hello/", prefixes) == "hello"
     assert longest_dir_prefix("hello", prefixes) == "hello"
     assert longest_dir_prefix("scoobydoobydoo", prefixes) is None
Esempio n. 2
0
 def test_longest_dir_prefix(self) -> None:
     # Find the longest prefix (standard case).
     prefixes = ["hello", "hello_world", "hello/world", "helloworld"]
     self.assertEqual(longest_dir_prefix("hello/world/pants", prefixes), "hello/world")
     self.assertEqual(longest_dir_prefix("hello/", prefixes), "hello")
     self.assertEqual(longest_dir_prefix("hello", prefixes), "hello")
     self.assertEqual(longest_dir_prefix("scoobydoobydoo", prefixes), None)
Esempio n. 3
0
 def test_longest_dir_prefix_special(self) -> None:
     # Ensure that something that is a longest prefix, but not a longest dir
     # prefix, is not tagged.
     prefixes = ["helloworldhowareyou", "helloworld"]
     self.assertEqual(
         longest_dir_prefix("helloworldhowareyoufine/", prefixes), None)
     self.assertEqual(
         longest_dir_prefix("helloworldhowareyoufine", prefixes), None)
Esempio n. 4
0
 def test_longest_dir_prefix_special(self):
     # Ensure that something that is a longest prefix, but not a longest dir
     # prefix, is not tagged.
     prefixes = ['helloworldhowareyou', 'helloworld']
     self.assertEqual(
         longest_dir_prefix('helloworldhowareyoufine/', prefixes), None)
     self.assertEqual(
         longest_dir_prefix('helloworldhowareyoufine', prefixes), None)
Esempio n. 5
0
 def test_longest_dir_prefix(self):
     # Find the longest prefix (standard case).
     prefixes = ['hello', 'hello_world', 'hello/world', 'helloworld']
     self.assertEqual(longest_dir_prefix('hello/world/pants', prefixes),
                      'hello/world')
     self.assertEqual(longest_dir_prefix('hello/', prefixes), 'hello')
     self.assertEqual(longest_dir_prefix('hello', prefixes), 'hello')
     self.assertEqual(longest_dir_prefix('scoobydoobydoo', prefixes), None)
Esempio n. 6
0
 def test_longest_dir_prefix_special(self):
   # Ensure that something that is a longest prefix, but not a longest dir
   # prefix, is not tagged.
   prefixes = ['helloworldhowareyou', 'helloworld']
   self.assertEquals(longest_dir_prefix('helloworldhowareyoufine/', prefixes),
                     None)
   self.assertEquals(longest_dir_prefix('helloworldhowareyoufine', prefixes),
                     None)
Esempio n. 7
0
 def test_longest_dir_prefix(self):
   # Find the longest prefix (standard case).
   prefixes = ['hello', 'hello_world', 'hello/world', 'helloworld']
   self.assertEquals(longest_dir_prefix('hello/world/pants', prefixes),
                     'hello/world')
   self.assertEquals(longest_dir_prefix('hello/', prefixes),
                     'hello')
   self.assertEquals(longest_dir_prefix('hello', prefixes),
                     'hello')
   self.assertEquals(longest_dir_prefix('scoobydoobydoo', prefixes),
                     None)
Esempio n. 8
0
  def determine_subproject_spec(self, spec, relative_to):
    subproject_prefix = longest_dir_prefix(relative_to, self.subproject_roots)
    if subproject_prefix:
      spec = join_specs(subproject_prefix, spec)

      logger.debug('Determined that spec {} relative to {} belongs to '
                   'subproject {}'.format(spec, relative_to, subproject_prefix))
    return spec
Esempio n. 9
0
def parse_spec(
    spec: str,
    relative_to: Optional[str] = None,
    subproject_roots: Optional[Sequence[str]] = None,
) -> Tuple[str, str]:
    """Parses a target address spec and returns the path from the root of the repo to this target
    and target name.

    :API: public

    :param spec: Target address spec.
    :param relative_to: path to use for sibling specs, ie: ':another_in_same_build_family',
      interprets the missing spec_path part as `relative_to`.
    :param subproject_roots: Paths that correspond with embedded build roots under
      the current build root.

    For example:

        some_target(
            name='mytarget',
            dependencies=['path/to/buildfile:targetname'],
        )

    Where `path/to/buildfile:targetname` is the dependent target address spec.

    In case the target name is empty, it returns the last component of the path as target name, ie:

        spec_path, target_name = parse_spec('path/to/buildfile/foo')

    will return spec_path as 'path/to/buildfile/foo' and target_name as 'foo'.

    Optionally, specs can be prefixed with '//' to denote an absolute spec path.  This is normally
    not significant except when a spec referring to a root level target is needed from deeper in
    the tree. For example, in `path/to/buildfile/BUILD`:

        some_target(
            name='mytarget',
            dependencies=[':targetname'],
        )

    The `targetname` spec refers to a target defined in `path/to/buildfile/BUILD*`. If instead
    you want to reference `targetname` in a root level BUILD file, use the absolute form.
    For example:

        some_target(
            name='mytarget',
            dependencies=['//:targetname'],
        )
    """
    def normalize_absolute_refs(ref: str) -> str:
        return strip_prefix(ref, "//")

    subproject = (longest_dir_prefix(relative_to, subproject_roots)
                  if relative_to and subproject_roots else None)

    def prefix_subproject(spec_path: str) -> str:
        if not subproject:
            return spec_path
        elif spec_path:
            return os.path.join(subproject, spec_path)
        else:
            return os.path.normpath(subproject)

    spec_parts = spec.rsplit(":", 1)
    if len(spec_parts) == 1:
        default_target_spec = spec_parts[0]
        spec_path = prefix_subproject(
            normalize_absolute_refs(default_target_spec))
        target_name = os.path.basename(spec_path)
    else:
        spec_path, target_name = spec_parts
        if not spec_path and relative_to:
            spec_path = fast_relpath(relative_to,
                                     subproject) if subproject else relative_to
        spec_path = prefix_subproject(normalize_absolute_refs(spec_path))

    return spec_path, target_name
Esempio n. 10
0
def parse_spec(spec, relative_to=None, subproject_roots=None):
  """Parses a target address spec and returns the path from the root of the repo to this Target
  and Target name.

  :API: public

  :param string spec: Target address spec.
  :param string relative_to: path to use for sibling specs, ie: ':another_in_same_build_family',
    interprets the missing spec_path part as `relative_to`.
  :param list subproject_roots: Paths that correspond with embedded build roots under
    the current build root.

  For Example::

    some_target(name='mytarget',
      dependencies=['path/to/buildfile:targetname']
    )

  Where ``path/to/buildfile:targetname`` is the dependent target address spec

  In case the target name is empty it returns the last component of the path as target name, ie::

    spec_path, target_name = parse_spec('path/to/buildfile/foo')

  Will return spec_path as 'path/to/buildfile/foo' and target_name as 'foo'.

  Optionally, specs can be prefixed with '//' to denote an absolute spec path.  This is normally
  not significant except when a spec referring to a root level target is needed from deeper in
  the tree.  For example, in ``path/to/buildfile/BUILD``::

    some_target(name='mytarget',
      dependencies=[':targetname']
    )

  The ``targetname`` spec refers to a target defined in ``path/to/buildfile/BUILD*``.  If instead
  you want to reference ``targetname`` in a root level BUILD file, use the absolute form.
  For example::

    some_target(name='mytarget',
      dependencies=['//:targetname']
    )
  """
  def normalize_absolute_refs(ref):
    return strip_prefix(ref, '//')

  subproject = longest_dir_prefix(relative_to, subproject_roots) if subproject_roots else None

  def prefix_subproject(spec_path):
    if not subproject:
      return spec_path
    elif spec_path:
      return os.path.join(subproject, spec_path)
    else:
      return os.path.normpath(subproject)

  spec_parts = spec.rsplit(':', 1)
  if len(spec_parts) == 1:
    spec_path = prefix_subproject(normalize_absolute_refs(spec_parts[0]))
    target_name = os.path.basename(spec_path)
  else:
    spec_path, target_name = spec_parts
    if not spec_path and not subproject and relative_to:
      spec_path = relative_to
    spec_path = prefix_subproject(normalize_absolute_refs(spec_path))

  return spec_path, target_name
Esempio n. 11
0
    def parse(
        cls,
        spec: str,
        relative_to: str | None = None,
        subproject_roots: Sequence[str] | None = None,
    ) -> AddressInput:
        """Parse a string into an AddressInput.

        :param spec: Target address spec.
        :param relative_to: path to use for sibling specs, ie: ':another_in_same_build_family',
          interprets the missing spec_path part as `relative_to`.
        :param subproject_roots: Paths that correspond with embedded build roots under
          the current build root.

        For example:

            some_target(
                name='mytarget',
                dependencies=['path/to/buildfile:targetname'],
            )

        Where `path/to/buildfile:targetname` is the dependent target address spec.

        In there is no target name component, it defaults the default target in the resulting
        Address's spec_path.

        Optionally, specs can be prefixed with '//' to denote an absolute spec path. This is
        normally not significant except when a spec referring to a root level target is needed
        from deeper in the tree. For example, in `path/to/buildfile/BUILD`:

            some_target(
                name='mytarget',
                dependencies=[':targetname'],
            )

        The `targetname` spec refers to a target defined in `path/to/buildfile/BUILD*`. If instead
        you want to reference `targetname` in a root level BUILD file, use the absolute form.
        For example:

            some_target(
                name='mytarget',
                dependencies=['//:targetname'],
            )

        The spec may be for a generated target: `dir:generator#generated`.

        The spec may be a file, such as `a/b/c.txt`. It may include a relative address spec at the
        end, such as `a/b/c.txt:original` or `a/b/c.txt:../original`, to disambiguate which target
        the file comes from; otherwise, it will be assumed to come from the default target in the
        directory, i.e. a target which leaves off `name`.
        """
        subproject = (longest_dir_prefix(relative_to, subproject_roots)
                      if relative_to and subproject_roots else None)

        def prefix_subproject(spec_path: str) -> str:
            if not subproject:
                return spec_path
            if spec_path:
                return os.path.join(subproject, spec_path)
            return os.path.normpath(subproject)

        spec_parts = spec.split(":", maxsplit=1)
        path_component = spec_parts[0]
        if len(spec_parts) == 1:
            target_component = None
            generated_parts = path_component.split("#", maxsplit=1)
            if len(generated_parts) == 1:
                generated_component = None
            else:
                path_component, generated_component = generated_parts
        else:
            generated_parts = spec_parts[1].split("#", maxsplit=1)
            if len(generated_parts) == 1:
                target_component = generated_parts[0]
                generated_component = None
            else:
                target_component, generated_component = generated_parts

        normalized_relative_to = None
        if relative_to:
            normalized_relative_to = (fast_relpath(relative_to, subproject)
                                      if subproject else relative_to)
        if path_component.startswith("./") and normalized_relative_to:
            path_component = os.path.join(normalized_relative_to,
                                          path_component[2:])
        if not path_component and normalized_relative_to:
            path_component = normalized_relative_to

        path_component = prefix_subproject(strip_prefix(path_component, "//"))

        return cls(path_component, target_component, generated_component)
Esempio n. 12
0
def parse_spec(spec, relative_to=None, subproject_roots=None):
    """Parses a target address spec and returns the path from the root of the repo to this Target
  and Target name.

  :API: public

  :param string spec: Target address spec.
  :param string relative_to: path to use for sibling specs, ie: ':another_in_same_build_family',
    interprets the missing spec_path part as `relative_to`.
  :param list subproject_roots: Paths that correspond with embedded build roots under
    the current build root.

  For Example::

    some_target(name='mytarget',
      dependencies=['path/to/buildfile:targetname']
    )

  Where ``path/to/buildfile:targetname`` is the dependent target address spec

  In case the target name is empty it returns the last component of the path as target name, ie::

    spec_path, target_name = parse_spec('path/to/buildfile/foo')

  Will return spec_path as 'path/to/buildfile/foo' and target_name as 'foo'.

  Optionally, specs can be prefixed with '//' to denote an absolute spec path.  This is normally
  not significant except when a spec referring to a root level target is needed from deeper in
  the tree.  For example, in ``path/to/buildfile/BUILD``::

    some_target(name='mytarget',
      dependencies=[':targetname']
    )

  The ``targetname`` spec refers to a target defined in ``path/to/buildfile/BUILD*``.  If instead
  you want to reference ``targetname`` in a root level BUILD file, use the absolute form.
  For example::

    some_target(name='mytarget',
      dependencies=['//:targetname']
    )
  """
    def normalize_absolute_refs(ref):
        return strip_prefix(ref, '//')

    subproject = longest_dir_prefix(
        relative_to, subproject_roots) if subproject_roots else None

    def prefix_subproject(spec_path):
        if not subproject:
            return spec_path
        elif spec_path:
            return os.path.join(subproject, spec_path)
        else:
            return os.path.normpath(subproject)

    spec_parts = spec.rsplit(':', 1)
    if len(spec_parts) == 1:
        spec_path = prefix_subproject(normalize_absolute_refs(spec_parts[0]))
        target_name = os.path.basename(spec_path)
    else:
        spec_path, target_name = spec_parts
        if not spec_path and not subproject and relative_to:
            spec_path = relative_to
        spec_path = prefix_subproject(normalize_absolute_refs(spec_path))

    return spec_path, target_name
Esempio n. 13
0
    def parse(
        cls,
        spec: str,
        *,
        relative_to: str | None = None,
        subproject_roots: Sequence[str] | None = None,
        description_of_origin: str,
    ) -> AddressInput:
        """Parse a string into an AddressInput.

        :param spec: Target address spec.
        :param relative_to: path to use for sibling specs, ie: ':another_in_same_build_family',
          interprets the missing spec_path part as `relative_to`.
        :param subproject_roots: Paths that correspond with embedded build roots under
          the current build root.
        :param description_of_origin: where the AddressInput comes from, e.g. "CLI arguments" or
          "the option `--paths-from`". This is used for better error messages.

        For example:

            some_target(
                name='mytarget',
                dependencies=['path/to/buildfile:targetname'],
            )

        Where `path/to/buildfile:targetname` is the dependent target address spec.

        In there is no target name component, it defaults the default target in the resulting
        Address's spec_path.

        Optionally, specs can be prefixed with '//' to denote an absolute spec path. This is
        normally not significant except when a spec referring to a root level target is needed
        from deeper in the tree. For example, in `path/to/buildfile/BUILD`:

            some_target(
                name='mytarget',
                dependencies=[':targetname'],
            )

        The `targetname` spec refers to a target defined in `path/to/buildfile/BUILD*`. If instead
        you want to reference `targetname` in a root level BUILD file, use the absolute form.
        For example:

            some_target(
                name='mytarget',
                dependencies=['//:targetname'],
            )

        The spec may be for a generated target: `dir:generator#generated`.

        The spec may be a file, such as `a/b/c.txt`. It may include a relative address spec at the
        end, such as `a/b/c.txt:original` or `a/b/c.txt:../original`, to disambiguate which target
        the file comes from; otherwise, it will be assumed to come from the default target in the
        directory, i.e. a target which leaves off `name`.
        """
        subproject = (longest_dir_prefix(relative_to, subproject_roots)
                      if relative_to and subproject_roots else None)

        def prefix_subproject(spec_path: str) -> str:
            if not subproject:
                return spec_path
            if spec_path:
                return os.path.join(subproject, spec_path)
            return os.path.normpath(subproject)

        (
            (
                path_component,
                target_component,
                generated_component,
                parameters,
            ),
            wildcard,
        ) = native_engine.address_spec_parse(spec)

        if wildcard:
            raise UnsupportedWildcard(
                softwrap(f"""
                    The address `{spec}` from {description_of_origin} ended in a wildcard
                    (`{wildcard}`), which is not supported.
                    """))

        normalized_relative_to = None
        if relative_to:
            normalized_relative_to = (fast_relpath(relative_to, subproject)
                                      if subproject else relative_to)
        if path_component.startswith("./") and normalized_relative_to:
            path_component = os.path.join(normalized_relative_to,
                                          path_component[2:])
        if not path_component and normalized_relative_to:
            path_component = normalized_relative_to

        path_component = prefix_subproject(strip_prefix(path_component, "//"))

        return cls(
            path_component,
            target_component,
            generated_component=generated_component,
            parameters=FrozenDict(sorted(parameters)),
            description_of_origin=description_of_origin,
        )