1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145

build / 3pp_common / maven.py [blame]

# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""The fetch.py and install.py helpers for a 3pp Maven module."""

import os
import pathlib
import re
import shutil
import subprocess
import urllib.request

import common

APACHE_MAVEN_URL = 'https://repo.maven.apache.org/maven2'

_POM_TEMPLATE = """\
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>group</groupId>
  <artifactId>artifact</artifactId>
  <version>1</version>
  <dependencies>
    <dependency>
      <groupId>{group_id}</groupId>
      <artifactId>{artifact_id}</artifactId>
      <version>{version}</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>placeholder_id</id>
      <name>placeholder_name</name>
      <url>{maven_url}</url>
    </repository>
  </repositories>
</project>
"""


def _detect_latest(maven_url, package):
    metadata_url = '{}/{}/maven-metadata.xml'.format(
        maven_url,
        package.replace('.', '/').replace(':', '/'))
    metadata = urllib.request.urlopen(metadata_url).read().decode('utf-8')
    # Do not parse xml with the Python included parser since it is susceptible
    # to maliciously crafted xmls. Only use regular expression parsing to be
    # safe. RE should be enough to handle what we need to extract.
    # TODO(agrieve): Use 'if m := ..." once docker image updates from Python 3.6.
    m = re.search('<latest>([^<]+)</latest>', metadata)
    if m:
        latest = m.group(1)
    else:
        # If no latest info was found just hope the versions are sorted and the
        # last one is the latest (as is commonly the case).
        latest = re.findall('<version>([^<]+)</version>', metadata)[-1]
    return latest


def _install(output_prefix,
             deps_prefix,
             maven_url,
             package,
             version,
             jar_name=None,
             post_process_func=None):
    # Runs in a docker container.
    group_id, artifact_id = package.split(':')
    if not jar_name:
        jar_name = f'{artifact_id}.jar'

    pathlib.Path('pom.xml').write_text(
        _POM_TEMPLATE.format(version=version,
                             group_id=group_id,
                             artifact_id=artifact_id,
                             maven_url=maven_url))

    # Set up JAVA_HOME for the mvn command to find the JDK.
    env = os.environ.copy()
    env['JAVA_HOME'] = common.path_within_checkout('third_party/jdk/current')

    # Ensure that mvn works and the environment is set up correctly.
    subprocess.run(['mvn', '-v'], check=True, env=env)

    # Build the jar file, explicitly specify -f to reduce sources of error.
    subprocess.run(['mvn', 'clean', 'assembly:single', '-f', 'pom.xml'],
                   check=True,
                   env=env)

    src_jar_path = 'target/artifact-1-jar-with-dependencies.jar'
    dst_jar_path = os.path.join(output_prefix, jar_name)
    if post_process_func:
        post_process_func(src_jar_path, dst_jar_path)
    else:
        shutil.move(src_jar_path, dst_jar_path)


def main(*,
         package,
         jar_name=None,
         maven_url='https://dl.google.com/android/maven2',
         post_process_func=None,
         version_override=None):
    """3pp entry point for fetch.py.

    Args:
      package: E.g.: some.package:some-thing
      jar_name: Name of .jar. Defaults to |some-thing|.jar
      maven_url: URL of Maven repository.
      post_process_func: Called to finish. Args: src_jar_path, dst_jar_path
      version_override: Use this version instead of the latest one.
    """

    def do_latest():
        return version_override or _detect_latest(maven_url, package)

    def do_install(args):
        _install(args.output_prefix, args.deps_prefix, maven_url, package,
                 args.version, jar_name, post_process_func)

    common.main(do_latest=do_latest,
                do_install=do_install,
                runtime_deps=['//third_party/jdk/current'])