Exemple #1
0
 def test_find_by_path(self):
   # No source_root is registered yet
   query = "tests/foo/bar:baz"
   self.assertIsNone(SourceRoot.find_by_path(query),
                     msg="Query {query} Failed for tree: {dump}"
                     .format(query=query, dump=SourceRoot._dump()))
   SourceRoot.register("tests/foo", TestTarget)
   self.assertEquals("tests/foo", SourceRoot.find_by_path(query),
                     msg="Query {query} Failed for tree: {dump}"
                     .format(query=query, dump=SourceRoot._dump()))
   self.assertIsNone(SourceRoot.find_by_path("tests/bar/foobar:qux"),
                                             msg="Failed for tree: {dump}"
                                             .format(dump=SourceRoot._dump()))
Exemple #2
0
 def test_find_by_path(self):
   # No source_root is registered yet
   query = "tests/foo/bar:baz"
   self.assertIsNone(SourceRoot.find_by_path(query),
                     msg="Query {query} Failed for tree: {dump}"
                     .format(query=query, dump=SourceRoot._dump()))
   SourceRoot.register("tests/foo", TestTarget)
   self.assertEquals("tests/foo", SourceRoot.find_by_path(query),
                     msg="Query {query} Failed for tree: {dump}"
                     .format(query=query, dump=SourceRoot._dump()))
   self.assertIsNone(SourceRoot.find_by_path("tests/bar/foobar:qux"),
                                             msg="Failed for tree: {dump}"
                                             .format(dump=SourceRoot._dump()))
Exemple #3
0
  def _calculate_sources(self, targets):
    """
    Find the appropriate source roots used for sources.

    :return: mapping of source roots to  set of sources under the roots
    """
    gentargets = OrderedSet()
    def add_to_gentargets(target):
      if self.is_gentarget(target):
        gentargets.add(target)
    self.context.build_graph.walk_transitive_dependency_graph(
      [target.address for target in targets],
      add_to_gentargets,
      postorder=True)
    sources_by_base = OrderedDict()
    # TODO(Eric Ayers) Extract this logic for general use? When using jar_source_set it is needed
    # to get the correct source root for paths outside the current BUILD tree.
    for target in gentargets:
      for source in target.sources_relative_to_buildroot():
        base = SourceRoot.find_by_path(source)
        if not base:
          base, _ = target.target_base, target.sources_relative_to_buildroot()
          self.context.log.debug('Could not find source root for {source}.'
                                 ' Missing call to SourceRoot.register()?  Fell back to {base}.'
                                 .format(source=source, base=base))
        if base not in sources_by_base:
          sources_by_base[base] = OrderedSet()
        sources_by_base[base].add(source)
    return sources_by_base
Exemple #4
0
    def add_new_target(self,
                       address,
                       target_type,
                       target_base=None,
                       dependencies=None,
                       derived_from=None,
                       **kwargs):
        """Creates a new target, adds it to the context and returns it.

    This method ensures the target resolves files against the given target_base, creating the
    directory if needed and registering a source root.
    """
        target_base = os.path.join(get_buildroot(), target_base
                                   or address.spec_path)
        if not os.path.exists(target_base):
            os.makedirs(target_base)
        if not SourceRoot.find_by_path(target_base):
            SourceRoot.register(target_base)
        if dependencies:
            dependencies = [dep.address for dep in dependencies]

        self.build_graph.inject_synthetic_target(address=address,
                                                 target_type=target_type,
                                                 dependencies=dependencies,
                                                 derived_from=derived_from,
                                                 **kwargs)
        new_target = self.build_graph.get_target(address)

        if derived_from:
            self._synthetic_targets[derived_from].append(new_target)

        return new_target
Exemple #5
0
    def _collapse_by_source_root(source_sets):
        """Collapse SourceSets with common source roots into one SourceSet instance.

    Use the registered source roots to collapse all source paths under a root.
    If any test type of target is allowed under the root, the path is determined to be
    a test path.  This method will give unpredictable results if source root entries overlap.

    :param list source_sets: SourceSets to analyze
    :returns: list of SourceSets collapsed to the source root paths.  There may be duplicate
      entries in this list which will be removed by dedup_sources()
    """
        collapsed_source_sets = []
        for source in source_sets:
            query = os.path.join(source.source_base, source.path)
            source_root = SourceRoot.find_by_path(query)
            if not source_root:
                collapsed_source_sets.append(source)
            else:
                collapsed_source_sets.append(
                    SourceSet(source.root_dir,
                              source_root,
                              "",
                              is_test=source.is_test,
                              resources_only=source.resources_only))
        return collapsed_source_sets
Exemple #6
0
  def _calculate_sources(self, targets):
    """
    Find the appropriate source roots used for sources.

    :return: mapping of source roots to  set of sources under the roots
    """
    gentargets = OrderedSet()
    def add_to_gentargets(target):
      if self.is_gentarget(target):
        gentargets.add(target)
    self.context.build_graph.walk_transitive_dependency_graph(
      [target.address for target in targets],
      add_to_gentargets,
      postorder=True)
    sources_by_base = OrderedDict()
    # TODO(Eric Ayers) Extract this logic for general use? When using unpacked_jars it is needed
    # to get the correct source root for paths outside the current BUILD tree.
    for target in gentargets:
      for source in target.sources_relative_to_buildroot():
        base = SourceRoot.find_by_path(source)
        if not base:
          base, _ = target.target_base, target.sources_relative_to_buildroot()
          self.context.log.debug('Could not find source root for {source}.'
                                 ' Missing call to SourceRoot.register()?  Fell back to {base}.'
                                 .format(source=source, base=base))
        if base not in sources_by_base:
          sources_by_base[base] = OrderedSet()
        sources_by_base[base].add(source)
    return sources_by_base
Exemple #7
0
  def add_new_target(self, address, target_type, target_base=None, dependencies=None,
                     derived_from=None, **kwargs):
    """Creates a new target, adds it to the context and returns it.

    This method ensures the target resolves files against the given target_base, creating the
    directory if needed and registering a source root.
    """
    target_base = os.path.join(get_buildroot(), target_base or address.spec_path)
    if not os.path.exists(target_base):
      os.makedirs(target_base)
    if not SourceRoot.find_by_path(target_base):
      SourceRoot.register(target_base)
    if dependencies:
      dependencies = [dep.address for dep in dependencies]

    self.build_graph.inject_synthetic_target(address=address,
                                             target_type=target_type,
                                             dependencies=dependencies,
                                             derived_from=derived_from,
                                             **kwargs)
    new_target = self.build_graph.get_target(address)

    if derived_from:
      self._synthetic_targets[derived_from].append(new_target)

    return new_target
Exemple #8
0
    def execute_codegen(self, targets):
        # Invoke the generator once per target.  Because the wire compiler has flags that try to reduce
        # the amount of code emitted, Invoking them all together will break if one target specifies a
        # service_writer and another does not, or if one specifies roots and another does not.
        for target in targets:
            sources_by_base = self._calculate_sources([target])
            if self.codegen_strategy.name() == 'isolated':
                sources = OrderedSet(target.sources_relative_to_buildroot())
            else:
                sources = OrderedSet(
                    itertools.chain.from_iterable(sources_by_base.values()))
            if not self.validate_sources_present(sources, [target]):
                continue
            relative_sources = OrderedSet()
            for source in sources:
                source_root = SourceRoot.find_by_path(source)
                if not source_root:
                    source_root = SourceRoot.find(target)
                relative_source = os.path.relpath(source, source_root)
                relative_sources.add(relative_source)
            check_duplicate_conflicting_protos(self, sources_by_base,
                                               relative_sources,
                                               self.context.log)

            args = ['--java_out={0}'.format(self.codegen_workdir(target))]

            # Add all params in payload to args

            if target.payload.get_field_value('no_options'):
                args.append('--no_options')

            service_writer = target.payload.service_writer
            if service_writer:
                args.append('--service_writer={0}'.format(service_writer))

            registry_class = target.payload.registry_class
            if registry_class:
                args.append('--registry_class={0}'.format(registry_class))

            if target.payload.roots:
                args.append('--roots={0}'.format(','.join(
                    target.payload.roots)))

            if target.payload.enum_options:
                args.append('--enum_options={0}'.format(','.join(
                    target.payload.enum_options)))

            args.append('--proto_path={0}'.format(
                os.path.join(get_buildroot(), SourceRoot.find(target))))

            args.extend(relative_sources)

            result = util.execute_java(
                classpath=self.tool_classpath('wire-compiler'),
                main='com.squareup.wire.WireCompiler',
                args=args)
            if result != 0:
                raise TaskError(
                    'Wire compiler exited non-zero ({0})'.format(result))
Exemple #9
0
 def collect_proto_paths(dep):
     if not dep.has_sources():
         return
     for source in dep.sources_relative_to_buildroot():
         if source.endswith('.proto'):
             root = SourceRoot.find_by_path(source)
             if root:
                 proto_paths.add(os.path.join(get_buildroot(), root))
Exemple #10
0
    def test_register_none(self):
        self._assert_source_root_empty()

        SourceRoot.register("tests")
        self.assertEquals({"tests": OrderedSet()}, SourceRoot.all_roots())
        self.assertEquals(OrderedSet(), SourceRoot.types("tests"))
        self.assertEquals("tests", SourceRoot.find(TestTarget("//tests/foo/bar:baz")))
        self.assertEquals("tests", SourceRoot.find_by_path("tests/foo/bar"))
Exemple #11
0
 def collect_proto_paths(dep):
     if not dep.has_sources():
         return
     for source in dep.sources_relative_to_buildroot():
         if source.endswith(".proto"):
             root = SourceRoot.find_by_path(source)
             if root:
                 proto_paths.add(os.path.join(get_buildroot(), root))
Exemple #12
0
  def test_register_none(self):
    self._assert_source_root_empty()

    SourceRoot.register("tests", )
    self.assertEquals({"tests": OrderedSet()}, SourceRoot.all_roots())
    self.assertEquals(OrderedSet(), SourceRoot.types("tests"))
    self.assertEquals("tests", SourceRoot.find(TestTarget("//tests/foo/bar:baz")))
    self.assertEquals("tests", SourceRoot.find_by_path("tests/foo/bar"))
Exemple #13
0
  def execute_codegen(self, targets):
    # Invoke the generator once per target.  Because the wire compiler has flags that try to reduce
    # the amount of code emitted, Invoking them all together will break if one target specifies a
    # service_writer and another does not, or if one specifies roots and another does not.
    for target in targets:
      sources_by_base = self._calculate_sources([target])
      if self.codegen_strategy.name() == 'isolated':
        sources = OrderedSet(target.sources_relative_to_buildroot())
      else:
        sources = OrderedSet(itertools.chain.from_iterable(sources_by_base.values()))
      if not self.validate_sources_present(sources, [target]):
        continue
      relative_sources = OrderedSet()
      for source in sources:
        source_root = SourceRoot.find_by_path(source)
        if not source_root:
          source_root = SourceRoot.find(target)
        relative_source = os.path.relpath(source, source_root)
        relative_sources.add(relative_source)
      check_duplicate_conflicting_protos(self, sources_by_base, relative_sources, self.context.log)

      args = ['--java_out={0}'.format(self.codegen_workdir(target))]

      # Add all params in payload to args

      if target.payload.get_field_value('no_options'):
        args.append('--no_options')

      service_writer = target.payload.service_writer
      if service_writer:
        args.append('--service_writer={0}'.format(service_writer))

      registry_class = target.payload.registry_class
      if registry_class:
        args.append('--registry_class={0}'.format(registry_class))

      if target.payload.roots:
        args.append('--roots={0}'.format(','.join(target.payload.roots)))

      if target.payload.enum_options:
        args.append('--enum_options={0}'.format(','.join(target.payload.enum_options)))

      args.append('--proto_path={0}'.format(os.path.join(get_buildroot(),
                                                         SourceRoot.find(target))))

      args.extend(relative_sources)

      result = util.execute_java(classpath=self.tool_classpath('wire-compiler'),
                                 main='com.squareup.wire.WireCompiler',
                                 args=args)
      if result != 0:
        raise TaskError('Wire compiler exited non-zero ({0})'.format(result))
    def genlang(self, lang, targets):
        # Invoke the generator once per target.  Because the wire compiler has flags that try to reduce
        # the amount of code emitted, Invoking them all together will break if one target specifies a
        # service_writer and another does not, or if one specifies roots and another does not.
        for target in targets:
            sources_by_base = self._calculate_sources([target])
            sources = OrderedSet(itertools.chain.from_iterable(sources_by_base.values()))
            relative_sources = OrderedSet()
            for source in sources:
                source_root = SourceRoot.find_by_path(source)
                if not source_root:
                    source_root = SourceRoot.find(target)
                relative_source = os.path.relpath(source, source_root)
                relative_sources.add(relative_source)
            check_duplicate_conflicting_protos(self, sources_by_base, relative_sources, self.context.log)

            if lang != "java":
                raise TaskError("Unrecognized wire gen lang: {0}".format(lang))

            args = ["--java_out={0}".format(self.java_out)]

            # Add all params in payload to args

            if target.payload.get_field_value("no_options"):
                args.append("--no_options")

            service_writer = target.payload.service_writer
            if service_writer:
                args.append("--service_writer={0}".format(service_writer))

            registry_class = target.payload.registry_class
            if registry_class:
                args.append("--registry_class={0}".format(registry_class))

            for root in target.payload.roots:
                args.append("--roots={0}".format(root))

            for enum_option in target.payload.enum_options:
                args.append("--enum_options={0}".format(enum_option))

            args.append("--proto_path={0}".format(os.path.join(get_buildroot(), SourceRoot.find(target))))

            args.extend(relative_sources)

            result = util.execute_java(
                classpath=self.tool_classpath("wire-compiler"), main="com.squareup.wire.WireCompiler", args=args
            )
            if result != 0:
                raise TaskError("Wire compiler exited non-zero ({0})".format(result))
Exemple #15
0
  def _collapse_by_source_root(source_sets):
    """Collapse SourceSets with common source roots into one SourceSet instance.

    Use the registered source roots to collapse all source paths under a root.
    If any test type of target is allowed under the root, the path is determined to be
    a test path.  This method will give unpredictable results if source root entries overlap.

    :param list source_sets: SourceSets to analyze
    :returns: list of SourceSets collapsed to the source root paths.  There may be duplicate
      entries in this list which will be removed by dedup_sources()
    """
    collapsed_source_sets = []
    for source in source_sets:
      query = os.path.join(source.source_base, source.path)
      source_root = SourceRoot.find_by_path(query)
      if not source_root:
        collapsed_source_sets.append(source)
      else:
        collapsed_source_sets.append(SourceSet(source.root_dir, source_root, "",
                                               is_test=source.is_test,
                                               resources_only=source.resources_only))
    return collapsed_source_sets
Exemple #16
0
  def _collapse_by_source_root(source_sets):
    """Collapse SourceSets with common source roots into one SourceSet instance.

    Use the registered source roots to collapse all source paths under a root.
    If any test type of target is allowed under the root, the path is determined to be
    a test path.  This method will give unpredictable results if source root entries overlap.

    :param list source_sets: SourceSets to analyze
    :returns: list of SourceSets collapsed to the source root paths.
    """

    roots_found = set()  # remember the roots we've already encountered
    collapsed_source_sets = []
    for source in source_sets:
      query = os.path.join(source.source_base, source.path)
      source_root = SourceRoot.find_by_path(query)
      if not source_root:
        collapsed_source_sets.append(source)
      elif not source_root in roots_found:
        roots_found.add(source_root)
        collapsed_source_sets.append(SourceSet(source.root_dir, source_root, "", source.is_test))
    return collapsed_source_sets
Exemple #17
0
  def _collapse_by_source_root(source_sets):
    """Collapse SourceSets with common source roots into one SourceSet instance.

    Use the registered source roots to collapse all source paths under a root.
    If any test type of target is allowed under the root, the path is determined to be
    a test path.  This method will give unpredictable results if source root entries overlap.

    :param list source_sets: SourceSets to analyze
    :returns: list of SourceSets collapsed to the source root paths.
    """

    roots_found = set()  # remember the roots we've already encountered
    collapsed_source_sets = []
    for source in source_sets:
      query = os.path.join(source.source_base, source.path)
      source_root = SourceRoot.find_by_path(query)
      if not source_root:
        collapsed_source_sets.append(source)
      elif not source_root in roots_found:
        roots_found.add(source_root)
        collapsed_source_sets.append(SourceSet(source.root_dir, source_root, "", source.is_test))
    return collapsed_source_sets
Exemple #18
0
    def format_args_for_target(self, target):
        """Calculate the arguments to pass to the command line for a single target."""
        sources_by_base = self._calculate_sources([target])
        if self.codegen_strategy.name() == "isolated":
            sources = OrderedSet(target.sources_relative_to_buildroot())
        else:
            sources = OrderedSet(itertools.chain.from_iterable(sources_by_base.values()))
        if not self.validate_sources_present(sources, [target]):
            return None
        relative_sources = OrderedSet()
        for source in sources:
            source_root = SourceRoot.find_by_path(source)
            if not source_root:
                source_root = SourceRoot.find(target)
            relative_source = os.path.relpath(source, source_root)
            relative_sources.add(relative_source)
        check_duplicate_conflicting_protos(self, sources_by_base, relative_sources, self.context.log)

        args = ["--java_out={0}".format(self.codegen_workdir(target))]

        # Add all params in payload to args

        if target.payload.get_field_value("no_options"):
            args.append("--no_options")

        def append_service_opts(service_type_name, service_type_value, options_values):
            """Append --service_writer or --service_factory args as appropriate.

      :param str service_type_name: the target parameter/option prefix
      :param str service_type_value: class passed to the --service_x= option
      :param list options_values: string options to be passed with --service_x_opt
      """
            if service_type_value:
                args.append("--{0}={1}".format(service_type_name, service_type_value))
                if options_values:
                    for opt in options_values:
                        args.append("--{0}_opt".format(service_type_name))
                        args.append(opt)

        # A check is done in the java_wire_library target  to make sure only one of --service_writer or
        # --service_factory is specified.
        if self.wire_compiler_version < Revision(2, 0):
            if target.payload.service_factory:
                raise TaskError(
                    "{spec} used service_factory, which is not available before Wire 2.0. You "
                    "should use service_writer instead.".format(spec=target.address.spec)
                )
            append_service_opts("service_writer", target.payload.service_writer, target.payload.service_writer_options)
        else:
            if target.payload.service_writer:
                raise TaskError(
                    "{spec} used service_writer, which is not available after Wire 2.0. You "
                    "should use service_factory instead.".format(spec=target.address.spec)
                )
            append_service_opts(
                "service_factory", target.payload.service_factory, target.payload.service_factory_options
            )

        registry_class = target.payload.registry_class
        if registry_class:
            args.append("--registry_class={0}".format(registry_class))

        if target.payload.roots:
            args.append("--roots={0}".format(",".join(target.payload.roots)))

        if target.payload.enum_options:
            args.append("--enum_options={0}".format(",".join(target.payload.enum_options)))

        if self.wire_compiler_version < Revision(2, 0):
            args.append("--proto_path={0}".format(os.path.join(get_buildroot(), SourceRoot.find(target))))
        else:
            # NB(gmalmquist): Support for multiple --proto_paths was introduced in Wire 2.0.
            for path in self._calculate_proto_paths(target):
                args.append("--proto_path={0}".format(path))

        args.extend(relative_sources)
        return args
Exemple #19
0
    def format_args_for_target(self, target):
        """Calculate the arguments to pass to the command line for a single target."""
        sources_by_base = self._calculate_sources([target])
        if self.codegen_strategy.name() == 'isolated':
            sources = OrderedSet(target.sources_relative_to_buildroot())
        else:
            sources = OrderedSet(
                itertools.chain.from_iterable(sources_by_base.values()))
        if not self.validate_sources_present(sources, [target]):
            return None
        relative_sources = OrderedSet()
        for source in sources:
            source_root = SourceRoot.find_by_path(source)
            if not source_root:
                source_root = SourceRoot.find(target)
            relative_source = os.path.relpath(source, source_root)
            relative_sources.add(relative_source)
        check_duplicate_conflicting_protos(self, sources_by_base,
                                           relative_sources, self.context.log)

        args = ['--java_out={0}'.format(self.codegen_workdir(target))]

        # Add all params in payload to args

        if target.payload.get_field_value('no_options'):
            args.append('--no_options')

        def append_service_opts(service_type_name, service_type_value,
                                options_values):
            """Append --service_writer or --service_factory args as appropriate.

      :param str service_type_name: the target parameter/option prefix
      :param str service_type_value: class passed to the --service_x= option
      :param list options_values: string options to be passed with --service_x_opt
      """
            if service_type_value:
                args.append('--{0}={1}'.format(service_type_name,
                                               service_type_value))
                if options_values:
                    for opt in options_values:
                        args.append('--{0}_opt'.format(service_type_name))
                        args.append(opt)

        # A check is done in the java_wire_library target  to make sure only one of --service_writer or
        # --service_factory is specified.
        if self.wire_compiler_version < Revision(2, 0):
            if target.payload.service_factory:
                raise TaskError(
                    '{spec} used service_factory, which is not available before Wire 2.0. You '
                    'should use service_writer instead.'.format(
                        spec=target.address.spec))
            append_service_opts('service_writer',
                                target.payload.service_writer,
                                target.payload.service_writer_options)
        else:
            if target.payload.service_writer:
                raise TaskError(
                    '{spec} used service_writer, which is not available after Wire 2.0. You '
                    'should use service_factory instead.'.format(
                        spec=target.address.spec))
            append_service_opts('service_factory',
                                target.payload.service_factory,
                                target.payload.service_factory_options)

        registry_class = target.payload.registry_class
        if registry_class:
            args.append('--registry_class={0}'.format(registry_class))

        if target.payload.roots:
            args.append('--roots={0}'.format(','.join(target.payload.roots)))

        if target.payload.enum_options:
            args.append('--enum_options={0}'.format(','.join(
                target.payload.enum_options)))

        if self.wire_compiler_version < Revision(2, 0):
            args.append('--proto_path={0}'.format(
                os.path.join(get_buildroot(), SourceRoot.find(target))))
        else:
            # NB(gmalmquist): Support for multiple --proto_paths was introduced in Wire 2.0.
            for path in self._calculate_proto_paths(target):
                args.append('--proto_path={0}'.format(path))

        args.extend(relative_sources)
        return args