github.com/tiagovtristao/plz@v13.4.0+incompatible/src/parse/rules/java_rules.build_defs (about)

     1  """Built-in rules to compile Java code."""
     2  
     3  
     4  def java_library(name:str, srcs:list=None, src_dir:str=None, resources:list=None, resources_root:str=None,
     5                   deps:list=[], modular:bool=False, exported_deps:list=None, visibility:list=None,
     6                   test_only:bool&testonly=False, javac_flags:list&javacopts=None, labels:list=[]):
     7      """Compiles Java source to a .jar which can be collected by other rules.
     8  
     9      Args:
    10        name (str): Name of the rule
    11        srcs (list): Java source files to compile for this library
    12        src_dir (str): Directory containing Java source files to compile.
    13        resources (list): Resources to include in the .jar file
    14        resources_root (str): Root directory to treat resources relative to; ie. if we are in
    15                              //project/main/resources and resources_root is project/main then
    16                              the resources in the .jar will be in the subdirectory 'resources'.
    17        deps (list): Dependencies of this rule.
    18        modular (bool): Whether the produced file should be modular. Only supported with java 9+.
    19        exported_deps (list): Exported dependencies, ie. dependencies that other things depending on this
    20                              rule will also receive when they're compiling. This is quite important for
    21                              Java; any dependency that forms part of the public API for your classes
    22                              should be an exported dependency.
    23        visibility (list): Visibility declaration of this rule.
    24        test_only (bool): If True, this rule can only be depended on by tests.
    25        javac_flags (list): List of flags passed to javac.
    26        labels (list): Additional labels to apply to this rule.
    27      """
    28      if srcs and src_dir:
    29          raise ParseError('You cannot pass both srcs and src_dir to java_library')
    30      if srcs or src_dir:
    31          if resources:
    32              # Split up resources into a separate rule so we don't have to try to build them here.
    33              res_rule = java_library(
    34                  name = '_%s#res' % name,
    35                  resources = resources,
    36                  resources_root = resources_root,
    37                  test_only=test_only,
    38              )
    39              deps += [res_rule]
    40  
    41          if javac_flags:
    42              # See http://bazel.io/blog/2015/06/25/ErrorProne.html for more info about this flag;
    43              # it doesn't mean anything to us so we must filter it out.
    44              # TODO(peterebden): Push this nonsense down into the javac_worker binary so we don't have to know about it here.
    45              javac_flags = ' '.join([flag for flag in javac_flags if flag != '-extra_checks:off'])
    46          else:
    47              javac_flags = CONFIG.JAVAC_TEST_FLAGS if test_only else CONFIG.JAVAC_FLAGS
    48  
    49          javac_flags = '-encoding utf8 ' + javac_flags
    50  
    51          if CONFIG.JAVA_RELEASE_LEVEL:
    52              javac_flags = f'--release {CONFIG.JAVA_RELEASE_LEVEL} ' + javac_flags
    53          else:
    54              javac_flags = f'-encoding utf8 -source {CONFIG.JAVA_SOURCE_LEVEL} -target {CONFIG.JAVA_TARGET_LEVEL} -g ' + javac_flags
    55  
    56          if not CONFIG.JAVAC_TOOL:
    57              mflag = '--modular' if modular else ''
    58              srcflag = '--src_dir' if src_dir else ''
    59              javac_cmd = f'$(worker {CONFIG.JAVAC_WORKER}) {javac_flags} {mflag} {srcflag}'
    60          else:
    61              find = r'`find $TMP_DIR -name "*.jar" | tr \\\\n :`'
    62              srcflag = '$SRCS' if srcs else '`find $SRCS -name "*.java"`'
    63              javac_cmd = f'mkdir -p _tmp/META-INF && $TOOLS_JAVAC {javac_flags} -classpath .:{find} -d _tmp {srcflag}'
    64  
    65          cmd = ' && '.join([
    66              javac_cmd,
    67              'find _tmp -name "*.class" | sed -e "s|_tmp/|${PKG} |g" -e "s/\\.class/.java/g" | sort > _tmp/META-INF/please_sourcemap',
    68              'cd _tmp',
    69              '$TOOLS_JARCAT z -d -o $OUT -i .',
    70          ])
    71  
    72          src_dir_label = []
    73          if not srcs:
    74              src_dir_label = ['src_dir:'+src_dir]
    75  
    76          return build_rule(
    77              name=name,
    78              srcs=srcs or [src_dir],
    79              deps=deps,
    80              exported_deps=exported_deps,
    81              outs=[name + '.jar'],
    82              visibility=visibility,
    83              cmd=cmd,
    84              building_description="Compiling...",
    85              requires=['java'],
    86              labels = labels + ['rule:java_test_library' if test_only else 'rule:java_library'] + src_dir_label,
    87              test_only=test_only,
    88              tools={
    89                  'javac': [CONFIG.JAVAC_TOOL or CONFIG.JAVAC_WORKER],
    90                  'jarcat': [CONFIG.JARCAT_TOOL],
    91              },
    92          )
    93      elif resources:
    94          # TODO(agenticarus): Turn `resources` into a first-class construct, and just use them in `deps` normally.
    95          # Can't run javac since there are no java files.
    96          if resources_root:
    97              cmd = 'cd ${PKG}/%s && $TOOL z -d -o ${OUT} -i .' % resources_root
    98          else:
    99              cmd = '$TOOL z -d -o ${OUTS} -i .'
   100          return build_rule(
   101              name=name,
   102              srcs=resources,
   103              deps=deps,
   104              exported_deps=exported_deps,
   105              outs=[name + '.jar'],
   106              visibility=visibility,
   107              cmd=cmd,
   108              building_description="Linking...",
   109              requires=['java'],
   110              labels = labels + ['rule:test_resources' if test_only else 'rule:resources'],
   111              test_only=test_only,
   112              tools=[CONFIG.JARCAT_TOOL],
   113          )
   114      else:
   115          # If input is only jar files (as maven_jar produces in some cases) we simply collect them
   116          # all up for other rules to use.
   117          return filegroup(
   118              name=name,
   119              deps=deps,
   120              exported_deps=exported_deps,
   121              visibility=visibility,
   122              output_is_complete=False,
   123              requires=['java'],
   124              labels = labels,
   125              test_only=test_only,
   126          )
   127  
   128  
   129  def java_module(name:str, srcs:list=None, src_dir:str=None, resources:list=None, resources_root:str=None,
   130                  deps:list=None, visibility:list=None, test_only:bool&testonly=False, javac_flags:list&javacopts=None):
   131      """Compiles Java source to a modular .jar which can be collected by other rules.
   132  
   133      Args:
   134        name (str): Name of the rule
   135        srcs (list): Java source files to compile for this library
   136        src_dir (str): Directory containing Java source files to compile.
   137        resources (list): Resources to include in the .jar file
   138        resources_root (str): Root directory to treat resources relative to; ie. if we are in
   139                              //project/main/resources and resources_root is project/main then
   140                              the resources in the .jar will be in the subdirectory 'resources'.
   141        deps (list): Dependencies of this rule.
   142        exported_deps (list): Exported dependencies, ie. dependencies that other things depending on this
   143                              rule will also receive when they're compiling. This is quite important for
   144                              Java; any dependency that forms part of the public API for your classes
   145                              should be an exported dependency.
   146        visibility (list): Visibility declaration of this rule.
   147        test_only (bool): If True, this rule can only be depended on by tests.
   148        javac_flags (list): List of flags passed to javac.
   149      """
   150      return java_library(
   151          name = name,
   152          srcs = srcs,
   153          src_dir = src_dir,
   154          resources = resources,
   155          resources_root = resources_root,
   156          deps = deps,
   157          visibility = visibility,
   158          test_only = test_only,
   159          javac_flags = javac_flags,
   160          modular = True,
   161      )
   162  
   163  
   164  def java_runtime_image(name:str, main_module:str, main_class:str, modules:list, out:str=None,
   165                         deps:list=[], data:list=None, visibility:list=None,
   166                         jlink_args:str='--strip-debug --compress=2'):
   167      """Assembles a set of modules into an executable java runtime image.
   168  
   169      Args:
   170        name (str): Name of the rule.
   171        main_module (str): Main module to set in the manifest. Has to be included in 'modules'.
   172        main_class (str): Main class to set in the manifest. Has to belong to 'main_module'.
   173        modules (list): Modules to be included in the runtime image.
   174        out (str): Name of the folder that contains the runtime image and the binary contained by it. Defaults to 'name'.
   175        deps (list): Dependencies of this rule.
   176        data (list): Runtime data files for this rule.
   177        visibility (list): Visibility declaration of this rule.
   178        jlink_args (str): Arguments to pass to the JVM in the run script.
   179      """
   180      if not CONFIG.JAVA_HOME:
   181          raise Exception('Java home needs to be set to link java runtime images against jmods.')
   182      if not CONFIG.JLINK_TOOL:
   183          raise Exception('A jlink tool is required to build java runtime images.')
   184      if not modules:
   185          raise Exception('You cannot assemble a java runtime image without specifying any modules.')
   186      out = out or name
   187      depflags = r'`find $TMP_DIR -name "*.jar" | tr \\\\n :`'
   188      modules = ','.join(modules)
   189      cmd = f"$TOOL --module-path {depflags}:{CONFIG.JAVA_HOME}/jmods --add-modules {modules} --launcher {name}={main_module}/{main_class} --output {out} {jlink_args}"
   190  
   191      return build_rule(
   192          name=name,
   193          deps=deps,
   194          data=data,
   195          outs=[out],
   196          cmd=cmd,
   197          needs_transitive_deps=True,
   198          output_is_complete=True,
   199          binary=True,
   200          building_description="Creating runtime image...",
   201          requires=['java'],
   202          visibility=visibility,
   203          tools=[CONFIG.JLINK_TOOL],
   204      )
   205  
   206  
   207  def java_binary(name:str, main_class:str=None, out:str=None, srcs:list=None, deps:list=[],
   208                  data:list=None, visibility:list=None, jvm_args:str=None,
   209                  self_executable:bool=False, manifest:str=None):
   210      """Compiles a .jar from a set of Java libraries.
   211  
   212      Args:
   213        name (str): Name of the rule.
   214        main_class (str): Main class to set in the manifest.
   215        out (str): Name of output .jar file. Defaults to name + .jar.
   216        srcs (list): Source files to compile.
   217        deps (list): Dependencies of this rule.
   218        data (list): Runtime data files for this rule.
   219        visibility (list): Visibility declaration of this rule.
   220        jvm_args (str): Arguments to pass to the JVM in the run script.
   221        self_executable (bool): True to make the jar self executable.
   222        manifest (str): Manifest file to put into the jar. Can't be passed at the same time as
   223                        main_class.
   224      """
   225      if main_class and manifest:
   226          raise ParseError("Can't pass both main_class and manifest to java_binary")
   227      if srcs:
   228          lib_rule = java_library(
   229              name = f'_{name}#lib',
   230              srcs = srcs,
   231              deps = deps,
   232          )
   233          deps.append(lib_rule)
   234      if self_executable:
   235          preamble = '#!/bin/sh\nexec java %s -jar $0 ${@}' % (jvm_args or '')
   236          cmd, tools = _jarcat_cmd(main_class, preamble, manifest=manifest)
   237      else:
   238          # This is essentially a hack to get past some Java things (notably Jersey) failing
   239          # in subtle ways when the jar has a preamble (srsly...).
   240          cmd, tools = _jarcat_cmd(main_class, manifest=manifest)
   241      build_rule(
   242          name=name,
   243          deps=deps,
   244          data=data,
   245          outs=[out or name + '.jar'],
   246          srcs=[manifest],
   247          cmd=cmd,
   248          needs_transitive_deps=True,
   249          output_is_complete=True,
   250          binary=True,
   251          building_description="Creating jar...",
   252          requires=['java'],
   253          visibility=visibility,
   254          tools=tools,
   255          labels=None if self_executable else ['java_non_exe'],
   256      )
   257  
   258  
   259  def java_test(name:str, srcs:list, resources:list=None, data:list=None, deps:list=None, worker:str='',
   260                labels:list&features&tags=None, visibility:list=None, flags:str='', container:bool|dict=False,
   261                sandbox:bool=None, timeout:int=0, flaky:bool|int=0, test_outputs:list=None, size:str=None,
   262                test_package:str=CONFIG.DEFAULT_TEST_PACKAGE, jvm_args:str=''):
   263      """Defines a Java test.
   264  
   265      Args:
   266        name (str): Name of the rule.
   267        srcs (list): Java files containing the tests.
   268        resources (list): Resources to include in the .jar file
   269        data (list): Runtime data files for this rule.
   270        deps (list): Dependencies of this rule.
   271        worker (str): Reference to worker script, A persistent worker process that is used to set up the test.
   272        labels (list): Labels to attach to this test.
   273        visibility (list): Visibility declaration of this rule.
   274        flags (str): Flags to pass to the test invocation.
   275        container (bool | dict): True to run this test within a container (eg. Docker).
   276        sandbox (bool): Sandbox the test on Linux to restrict access to namespaces such as network.
   277        timeout (int): Maximum length of time, in seconds, to allow this test to run for.
   278        flaky (int | bool): True to mark this as flaky and automatically rerun.
   279        test_outputs (list): Extra test output files to generate from this test.
   280        size (str): Test size (enormous, large, medium or small).
   281        test_package (str): Java package to scan for test classes to run.
   282        jvm_args (str): Arguments to pass to the JVM in the run script.
   283      """
   284      timeout, labels = _test_size_and_timeout(size, timeout, labels)
   285      if not labels:
   286          labels = []
   287      # It's a bit sucky doing this in two separate steps, but it is
   288      # at least easy and reuses the existing code.
   289      lib_rule = java_library(
   290          name=f'_{name}#lib',
   291          srcs=srcs,
   292          resources=resources,
   293          deps=deps,
   294          test_only=True,
   295          labels=labels + ["rule:java_test"],
   296          # Deliberately not visible outside this package.
   297      )
   298      # As above, would be nicer if we could make the jars self-executing again.
   299      cmd, tools = _jarcat_cmd('build.please.main.TestMain')
   300      tools['junit'] = [CONFIG.JUNIT_RUNNER]
   301      cmd = 'ln -s $TOOLS_JUNIT . && ' + cmd
   302      test_cmd = f'java -Dbuild.please.testpackage={test_package} {jvm_args} -jar $(location :{name}) {flags}'
   303  
   304      deps = [lib_rule]
   305      if worker:
   306          test_cmd = f'$(worker {worker}) && {test_cmd} '
   307          deps += [worker]
   308  
   309      build_rule(
   310          name=name,
   311          cmd=cmd,
   312          test_cmd=test_cmd,
   313          data=data,
   314          outs=[name + '.jar'],
   315          deps=deps,
   316          visibility=visibility,
   317          container=container,
   318          test_sandbox=sandbox,
   319          labels=labels,
   320          test_timeout=timeout,
   321          flaky=flaky,
   322          test_outputs=test_outputs,
   323          requires=['java'],
   324          needs_transitive_deps=True,
   325          output_is_complete=True,
   326          test=True,
   327          binary=True,
   328          building_description="Creating jar...",
   329          tools=tools,
   330      )
   331  
   332  
   333  def maven_jars(name:str, id:str='', ids:list=[], repository:str|list=None, exclude:list=[],
   334                 hashes:list=None, combine:bool=False, hash:str|list=None, deps:list=[],
   335                 visibility:list=None, filename:str=None, deps_only:bool=False, optional:list=None):
   336      """Fetches a transitive set of dependencies from Maven.
   337  
   338      Args:
   339        name (str): Name of the output rule.
   340        id (str): Maven id of the artifact (e.g. org.junit:junit:4.1.0)
   341        ids (list): Maven ids of artifacts to fetch (e.g. org.junit:junit:4.1.0, io.grpc:grpc-all:1.4.0)
   342        repository (str | list): Maven repositories to fetch deps from.
   343        exclude (list): Dependencies to ignore when fetching this one.
   344        hashes (dict): Map of Maven id -> rule hash for each rule produced.
   345        combine (bool): If True, we combine all downloaded .jar files into one uberjar.
   346        hash (str | list): Hash of final produced .jar. For brevity, implies combine=True.
   347        deps (list): Labels of dependencies, as usual.
   348        visibility (list): Visibility label.
   349        filename (str): Filename we attempt to download. Defaults to standard Maven name.
   350        deps_only (bool): If True we fetch only dependent rules, not this one itself. Useful for some that
   351                          have a top-level target as a facade which doesn't have actual code.
   352        optional (list): List of optional dependencies to fetch. By default we fetch none of them.
   353      """
   354      if id:
   355          ids.append(id)
   356      for id in ids:
   357          if id.count(':') != 2:
   358              raise ValueError('Bad Maven id string: %s. Must be in the format group:artifact:id' % id)
   359      combine = combine or hash
   360      source_name = f'_{name}#src'
   361      repository = repository or CONFIG.DEFAULT_MAVEN_REPO
   362      repos = [repository] if isinstance(repository, str) else repository
   363  
   364      def get_hash(id, artifact=None):
   365          if hashes is None:
   366              return None
   367          artifact = artifact or id.split(':')[1]
   368          return hashes.get(id, hashes.get(artifact, '<not given>'))
   369  
   370      def create_maven_deps(_, output):
   371          for line in output:
   372              if not line:
   373                  continue
   374              group, artifact, version, sources, licences = _parse_maven_artifact(line)
   375              if artifact in exclude:
   376                  continue
   377              maven_jar(
   378                  name=artifact,
   379                  id=line,
   380                  repository=repos,
   381                  hash=get_hash(id, artifact),
   382                  licences=licences,
   383                  sources=sources,
   384                  # We deliberately don't make this rule visible externally.
   385              )
   386              # Have to account for require/provide on final rule if it's a jar
   387              final_name = name if deps_only or combine else f'_{name}#bin'
   388              add_exported_dep(final_name, ':' + artifact)
   389              if combine:
   390                  add_exported_dep(source_name, ':' + artifact)
   391  
   392      exclusions = ' '.join(['-e ' + excl for excl in exclude])
   393      options = ' '.join(['-o ' + option for option in optional]) if optional else ''
   394      repo_flags = ' '.join(['-r ' + repo for repo in repos])
   395      build_rule(
   396          name='_%s#deps' % name,
   397          cmd='$TOOL %s %s %s %s' % (repo_flags, ' '.join(ids), exclusions, options),
   398          post_build=create_maven_deps,
   399          building_description='Finding dependencies...',
   400          tools=[CONFIG.PLEASE_MAVEN_TOOL],
   401          sandbox=False,
   402      )
   403      if combine:
   404          download_name = f'_{name}#download'
   405          maven_jar(
   406              name=download_name,
   407              id=id,
   408              repository=repos,
   409              hash=get_hash(id),
   410              deps = deps,
   411              visibility=visibility,
   412              filename=filename,
   413          )
   414          # Combine the sources into a separate uberjar
   415          cmd, tools = _jarcat_cmd()
   416          build_rule(
   417              name=source_name,
   418              output_is_complete=True,
   419              needs_transitive_deps=True,
   420              building_description="Creating source jar...",
   421              deps=[':' + download_name, f':_{name}#deps'] + deps,
   422              outs=[name + '_src.jar'],
   423              cmd=cmd + ' -s src.jar -e ""',
   424              tools=tools,
   425          )
   426          return build_rule(
   427              name=name,
   428              hashes=hash if isinstance(hash, list) else [hash] if hash else None,
   429              output_is_complete=True,
   430              needs_transitive_deps=True,
   431              building_description="Creating jar...",
   432              deps=[':' + download_name, ':' + source_name, f':_{name}#deps'] + deps,
   433              outs=[name + '.jar'],
   434              requires=['java'],
   435              visibility=visibility,
   436              cmd=cmd + ' -e "_src.jar"',
   437              tools=tools,
   438          )
   439      elif not deps_only:
   440          return maven_jar(
   441              name=name,
   442              id=id,
   443              repository=repos,
   444              hash=get_hash(id),
   445              deps = deps + [f':_{name}#deps'],
   446              visibility=visibility,
   447              filename=filename,
   448          )
   449      else:
   450          return build_rule(
   451              name=name,
   452              deps=[f':_{name}#deps'],
   453              exported_deps=deps,
   454              cmd='true',  # do nothing!
   455              visibility=visibility,
   456              requires=['java'],
   457          )
   458  
   459  
   460  def maven_jar(name:str, id:str, repository:str|list=None, hash:str=None, hashes:list=None, deps:list=None,
   461                visibility:list=None, filename:str=None, sources:bool=True, licences:list=None,
   462                native:bool=False, artifact_type:str=None, test_only:bool&testonly=False,
   463                binary:bool=False, classifier:str='', classifier_sources_override:str=''):
   464      """Fetches a single Java dependency from Maven.
   465  
   466      Args:
   467        name (str): Name of the output rule.
   468        id (str): Maven id of the artifact (eg. org.junit:junit:4.1.0)
   469        repository (str | list): Maven repositories to fetch deps from.
   470        hash (str): Hash for produced rule.
   471        hashes (list): List of hashes for produced rule.
   472        deps (list): Labels of dependencies, as usual.
   473        visibility (list): Visibility label.
   474        filename (str): Filename we attempt to download. Defaults to standard Maven name.
   475        sources (bool): True to download source jars as well.
   476        licences (list): Licences this package is subject to.
   477        native (bool): Attempt to download a native jar (i.e. add "-linux-x86_64" etc to the URL).
   478        artifact_type (str): Type of artifact to download (defaults to jar but could be e.g. aar).
   479        test_only (bool): If True, this target can only be used by tests or other test_only rules.
   480        binary (bool): If True, we attempt to fetch and download an executable binary. The output
   481                       is marked as such. Implies native=True and sources=False.
   482        classifier (str): Maven classifier, allows to distinguish artifacts that were built from
   483                       the same POM but differ in their content.
   484        classifier_sources_override (str): Allows to override the classifier used to fetch the
   485                       source artifact.
   486                       e.g. logback-core-1.1.3-tests.jar and logback-core-1.1.3-test-sources.jar
   487      """
   488      if hash and hashes:
   489          raise ParseError('You can pass only one of hash or hashes to maven_jar')
   490      if not artifact_type:
   491          id, _, artifact_type = id.partition('@')
   492          artifact_type = artifact_type or 'jar'
   493      group, artifact, version, sources, licences = _parse_maven_artifact(id, sources, licences)
   494      artifact_type = '.' + artifact_type
   495      out_artifact_type = artifact_type
   496      repository = repository or CONFIG.DEFAULT_MAVEN_REPO
   497      repos = [repository] if isinstance(repository, str) else repository
   498      if classifier:
   499          classifier = '-' + classifier
   500      if binary:
   501          native = True
   502          sources = False
   503          artifact_type = '.exe'  # Maven always describes them this way, even for Linux :(
   504          out_artifact_type = ''  # But we're not peasants so we won't do the same.
   505      if native:
   506          filename = filename or f'{artifact}-{version}-{classifier}$XOS-$XARCH{artifact_type}'
   507      else:
   508          filename = filename or f'{artifact}-{version}{classifier}{artifact_type}'
   509  
   510      group = group.replace('.', '/')
   511      urls = ['/'.join([repo, group, artifact, version, filename]) for repo in repos]
   512      bin_rule  =  remote_file(
   513          name = name,
   514          _tag = 'bin',
   515          url = urls,
   516          out = name + out_artifact_type,
   517          labels = ['maven-classes'],
   518          licences = licences,
   519          exported_deps = deps,  # easiest to assume these are always exported.
   520          test_only = test_only,
   521          binary = binary,
   522      )
   523      provides = {'java': bin_rule}
   524      srcs = [bin_rule]
   525  
   526      if sources:
   527          if classifier_sources_override:
   528              classifier = '-' + classifier_sources_override
   529          filename = f'{artifact}-{version}{classifier}-sources.jar'
   530          urls = ['/'.join([repo, group, artifact, version, filename]) for repo in repos]
   531          src_rule = remote_file(
   532              name = name,
   533              _tag = 'src',
   534              url = urls,
   535              out = name + '_src' + artifact_type,
   536              labels = ['maven-sources'],
   537              licences = licences,
   538              test_only = test_only,
   539          )
   540          srcs.append(src_rule)
   541  
   542      # .aar's have an embedded classes.jar in them. Pull that out so other rules can use it.
   543      if artifact_type == '.aar':
   544          classes_rule = build_rule(
   545              name = name,
   546              tag = 'classes',
   547              srcs = [bin_rule],
   548              cmd = '$TOOL x $SRC classes.jar',
   549              outs = [name + '.jar'],
   550              visibility = visibility,
   551              licences = licences,
   552              requires = ['java'],
   553              exported_deps = deps,
   554              test_only=test_only,
   555              tools = [CONFIG.JARCAT_TOOL],
   556          )
   557          provides = {
   558              'java': classes_rule,
   559              'android': bin_rule,
   560          }
   561          local_deps = [classes_rule]
   562      else:
   563          local_deps = None
   564  
   565      return filegroup(
   566          name = name,
   567          srcs = srcs,
   568          provides = provides,
   569          exported_deps=deps,  # easiest to assume these are always exported.
   570          deps = local_deps,  # ensure the classes_rule gets built correctly if there is one.
   571          hashes = hashes if hashes else [hash] if hash else None,
   572          labels = ['mvn:' + id, 'rule:maven_jar'],
   573          visibility = visibility,
   574          test_only=test_only,
   575          output_is_complete = False,
   576          binary = binary,
   577      )
   578  
   579  
   580  def _parse_maven_artifact(id, sources=True, licences=None):
   581      """Parses a Maven artifact in group:artifact:version format, with possibly some extras."""
   582      parts = id.split(':')
   583      if len(parts) == 5:
   584          group, artifact, version = parts[:3]
   585          sources = parts[3] == 'src'
   586          licences = parts[4].split('|')
   587      elif len(parts) == 4:
   588          group, artifact, version = parts[:3]
   589          sources = parts[3] == 'src'
   590      elif len(parts) == 3:
   591          group, artifact, version = parts
   592      else:
   593          raise ParseError(f'Unknown artifact format: {id} (should be group:artifact:version)')
   594      return group, artifact, version, sources, licences
   595  
   596  
   597  def _jarcat_cmd(main_class=None, preamble=None, manifest=None):
   598      """Returns the command we'd use to invoke jarcat, and the tool paths required."""
   599      cmd = '$TOOLS_JARCAT z -i . -o ${OUTS} -j'
   600      if main_class:
   601          cmd += f' -m "{main_class}"'
   602      if preamble:
   603          cmd += f" -p '{preamble}'"
   604      if manifest:
   605          cmd += ' --manifest "$SRCS"'
   606      return cmd, {'jarcat': [CONFIG.JARCAT_TOOL]}
   607  
   608  
   609  if CONFIG.BAZEL_COMPATIBILITY:
   610      def java_toolchain(javac=None, source_version=None, target_version=None):
   611          """Mimics some effort at Bazel compatibility.
   612  
   613          This doesn't really have the same semantics and ignores a bunch of arguments but it
   614          isn't easy for us to behave the same way that they do.
   615          """
   616          package(
   617              javac_tool = javac,
   618              java_source_level = source_version,
   619              java_target_level = target_version,
   620          )
   621  
   622      def java_import(name, jars, deps=None, exports=None, test_only=False, visibility=None):
   623          """Mimics java_import, as far as I can tell we don't need to do much here."""
   624          filegroup(
   625              name = name,
   626              srcs = jars,
   627              deps = deps,
   628              exported_deps = exports,
   629              test_only = test_only,
   630              visibility = visibility,
   631          )