1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2024 The Chromium Authors 2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 4*8975f5c5SAndroid Build Coastguard Worker"""The fetch.py and install.py helpers for a 3pp Maven module.""" 5*8975f5c5SAndroid Build Coastguard Worker 6*8975f5c5SAndroid Build Coastguard Workerimport os 7*8975f5c5SAndroid Build Coastguard Workerimport pathlib 8*8975f5c5SAndroid Build Coastguard Workerimport re 9*8975f5c5SAndroid Build Coastguard Workerimport shutil 10*8975f5c5SAndroid Build Coastguard Workerimport subprocess 11*8975f5c5SAndroid Build Coastguard Workerimport urllib.request 12*8975f5c5SAndroid Build Coastguard Worker 13*8975f5c5SAndroid Build Coastguard Workerimport common 14*8975f5c5SAndroid Build Coastguard Worker 15*8975f5c5SAndroid Build Coastguard WorkerAPACHE_MAVEN_URL = 'https://repo.maven.apache.org/maven2' 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Worker_POM_TEMPLATE = """\ 18*8975f5c5SAndroid Build Coastguard Worker<project> 19*8975f5c5SAndroid Build Coastguard Worker <modelVersion>4.0.0</modelVersion> 20*8975f5c5SAndroid Build Coastguard Worker <groupId>group</groupId> 21*8975f5c5SAndroid Build Coastguard Worker <artifactId>artifact</artifactId> 22*8975f5c5SAndroid Build Coastguard Worker <version>1</version> 23*8975f5c5SAndroid Build Coastguard Worker <dependencies> 24*8975f5c5SAndroid Build Coastguard Worker <dependency> 25*8975f5c5SAndroid Build Coastguard Worker <groupId>{group_id}</groupId> 26*8975f5c5SAndroid Build Coastguard Worker <artifactId>{artifact_id}</artifactId> 27*8975f5c5SAndroid Build Coastguard Worker <version>{version}</version> 28*8975f5c5SAndroid Build Coastguard Worker <scope>runtime</scope> 29*8975f5c5SAndroid Build Coastguard Worker </dependency> 30*8975f5c5SAndroid Build Coastguard Worker </dependencies> 31*8975f5c5SAndroid Build Coastguard Worker <build> 32*8975f5c5SAndroid Build Coastguard Worker <plugins> 33*8975f5c5SAndroid Build Coastguard Worker <plugin> 34*8975f5c5SAndroid Build Coastguard Worker <artifactId>maven-assembly-plugin</artifactId> 35*8975f5c5SAndroid Build Coastguard Worker <version>3.3.0</version> 36*8975f5c5SAndroid Build Coastguard Worker <configuration> 37*8975f5c5SAndroid Build Coastguard Worker <descriptorRefs> 38*8975f5c5SAndroid Build Coastguard Worker <descriptorRef>jar-with-dependencies</descriptorRef> 39*8975f5c5SAndroid Build Coastguard Worker </descriptorRefs> 40*8975f5c5SAndroid Build Coastguard Worker </configuration> 41*8975f5c5SAndroid Build Coastguard Worker <executions> 42*8975f5c5SAndroid Build Coastguard Worker <execution> 43*8975f5c5SAndroid Build Coastguard Worker <phase>package</phase> 44*8975f5c5SAndroid Build Coastguard Worker <goals> 45*8975f5c5SAndroid Build Coastguard Worker <goal>single</goal> 46*8975f5c5SAndroid Build Coastguard Worker </goals> 47*8975f5c5SAndroid Build Coastguard Worker </execution> 48*8975f5c5SAndroid Build Coastguard Worker </executions> 49*8975f5c5SAndroid Build Coastguard Worker </plugin> 50*8975f5c5SAndroid Build Coastguard Worker </plugins> 51*8975f5c5SAndroid Build Coastguard Worker </build> 52*8975f5c5SAndroid Build Coastguard Worker <repositories> 53*8975f5c5SAndroid Build Coastguard Worker <repository> 54*8975f5c5SAndroid Build Coastguard Worker <id>placeholder_id</id> 55*8975f5c5SAndroid Build Coastguard Worker <name>placeholder_name</name> 56*8975f5c5SAndroid Build Coastguard Worker <url>{maven_url}</url> 57*8975f5c5SAndroid Build Coastguard Worker </repository> 58*8975f5c5SAndroid Build Coastguard Worker </repositories> 59*8975f5c5SAndroid Build Coastguard Worker</project> 60*8975f5c5SAndroid Build Coastguard Worker""" 61*8975f5c5SAndroid Build Coastguard Worker 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Workerdef _detect_latest(maven_url, package): 64*8975f5c5SAndroid Build Coastguard Worker metadata_url = '{}/{}/maven-metadata.xml'.format( 65*8975f5c5SAndroid Build Coastguard Worker maven_url, 66*8975f5c5SAndroid Build Coastguard Worker package.replace('.', '/').replace(':', '/')) 67*8975f5c5SAndroid Build Coastguard Worker metadata = urllib.request.urlopen(metadata_url).read().decode('utf-8') 68*8975f5c5SAndroid Build Coastguard Worker # Do not parse xml with the Python included parser since it is susceptible 69*8975f5c5SAndroid Build Coastguard Worker # to maliciously crafted xmls. Only use regular expression parsing to be 70*8975f5c5SAndroid Build Coastguard Worker # safe. RE should be enough to handle what we need to extract. 71*8975f5c5SAndroid Build Coastguard Worker # TODO(agrieve): Use 'if m := ..." once docker image updates from Python 3.6. 72*8975f5c5SAndroid Build Coastguard Worker m = re.search('<latest>([^<]+)</latest>', metadata) 73*8975f5c5SAndroid Build Coastguard Worker if m: 74*8975f5c5SAndroid Build Coastguard Worker latest = m.group(1) 75*8975f5c5SAndroid Build Coastguard Worker else: 76*8975f5c5SAndroid Build Coastguard Worker # If no latest info was found just hope the versions are sorted and the 77*8975f5c5SAndroid Build Coastguard Worker # last one is the latest (as is commonly the case). 78*8975f5c5SAndroid Build Coastguard Worker latest = re.findall('<version>([^<]+)</version>', metadata)[-1] 79*8975f5c5SAndroid Build Coastguard Worker return latest 80*8975f5c5SAndroid Build Coastguard Worker 81*8975f5c5SAndroid Build Coastguard Worker 82*8975f5c5SAndroid Build Coastguard Workerdef _install(output_prefix, 83*8975f5c5SAndroid Build Coastguard Worker deps_prefix, 84*8975f5c5SAndroid Build Coastguard Worker maven_url, 85*8975f5c5SAndroid Build Coastguard Worker package, 86*8975f5c5SAndroid Build Coastguard Worker version, 87*8975f5c5SAndroid Build Coastguard Worker jar_name=None, 88*8975f5c5SAndroid Build Coastguard Worker post_process_func=None): 89*8975f5c5SAndroid Build Coastguard Worker # Runs in a docker container. 90*8975f5c5SAndroid Build Coastguard Worker group_id, artifact_id = package.split(':') 91*8975f5c5SAndroid Build Coastguard Worker if not jar_name: 92*8975f5c5SAndroid Build Coastguard Worker jar_name = f'{artifact_id}.jar' 93*8975f5c5SAndroid Build Coastguard Worker 94*8975f5c5SAndroid Build Coastguard Worker pathlib.Path('pom.xml').write_text( 95*8975f5c5SAndroid Build Coastguard Worker _POM_TEMPLATE.format(version=version, 96*8975f5c5SAndroid Build Coastguard Worker group_id=group_id, 97*8975f5c5SAndroid Build Coastguard Worker artifact_id=artifact_id, 98*8975f5c5SAndroid Build Coastguard Worker maven_url=maven_url)) 99*8975f5c5SAndroid Build Coastguard Worker 100*8975f5c5SAndroid Build Coastguard Worker # Set up JAVA_HOME for the mvn command to find the JDK. 101*8975f5c5SAndroid Build Coastguard Worker env = os.environ.copy() 102*8975f5c5SAndroid Build Coastguard Worker env['JAVA_HOME'] = common.path_within_checkout('third_party/jdk/current') 103*8975f5c5SAndroid Build Coastguard Worker 104*8975f5c5SAndroid Build Coastguard Worker # Ensure that mvn works and the environment is set up correctly. 105*8975f5c5SAndroid Build Coastguard Worker subprocess.run(['mvn', '-v'], check=True, env=env) 106*8975f5c5SAndroid Build Coastguard Worker 107*8975f5c5SAndroid Build Coastguard Worker # Build the jar file, explicitly specify -f to reduce sources of error. 108*8975f5c5SAndroid Build Coastguard Worker subprocess.run(['mvn', 'clean', 'assembly:single', '-f', 'pom.xml'], 109*8975f5c5SAndroid Build Coastguard Worker check=True, 110*8975f5c5SAndroid Build Coastguard Worker env=env) 111*8975f5c5SAndroid Build Coastguard Worker 112*8975f5c5SAndroid Build Coastguard Worker src_jar_path = 'target/artifact-1-jar-with-dependencies.jar' 113*8975f5c5SAndroid Build Coastguard Worker dst_jar_path = os.path.join(output_prefix, jar_name) 114*8975f5c5SAndroid Build Coastguard Worker if post_process_func: 115*8975f5c5SAndroid Build Coastguard Worker post_process_func(src_jar_path, dst_jar_path) 116*8975f5c5SAndroid Build Coastguard Worker else: 117*8975f5c5SAndroid Build Coastguard Worker shutil.move(src_jar_path, dst_jar_path) 118*8975f5c5SAndroid Build Coastguard Worker 119*8975f5c5SAndroid Build Coastguard Worker 120*8975f5c5SAndroid Build Coastguard Workerdef main(*, 121*8975f5c5SAndroid Build Coastguard Worker package, 122*8975f5c5SAndroid Build Coastguard Worker jar_name=None, 123*8975f5c5SAndroid Build Coastguard Worker maven_url='https://dl.google.com/android/maven2', 124*8975f5c5SAndroid Build Coastguard Worker post_process_func=None, 125*8975f5c5SAndroid Build Coastguard Worker version_override=None): 126*8975f5c5SAndroid Build Coastguard Worker """3pp entry point for fetch.py. 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Worker Args: 129*8975f5c5SAndroid Build Coastguard Worker package: E.g.: some.package:some-thing 130*8975f5c5SAndroid Build Coastguard Worker jar_name: Name of .jar. Defaults to |some-thing|.jar 131*8975f5c5SAndroid Build Coastguard Worker maven_url: URL of Maven repository. 132*8975f5c5SAndroid Build Coastguard Worker post_process_func: Called to finish. Args: src_jar_path, dst_jar_path 133*8975f5c5SAndroid Build Coastguard Worker version_override: Use this version instead of the latest one. 134*8975f5c5SAndroid Build Coastguard Worker """ 135*8975f5c5SAndroid Build Coastguard Worker 136*8975f5c5SAndroid Build Coastguard Worker def do_latest(): 137*8975f5c5SAndroid Build Coastguard Worker return version_override or _detect_latest(maven_url, package) 138*8975f5c5SAndroid Build Coastguard Worker 139*8975f5c5SAndroid Build Coastguard Worker def do_install(args): 140*8975f5c5SAndroid Build Coastguard Worker _install(args.output_prefix, args.deps_prefix, maven_url, package, 141*8975f5c5SAndroid Build Coastguard Worker args.version, jar_name, post_process_func) 142*8975f5c5SAndroid Build Coastguard Worker 143*8975f5c5SAndroid Build Coastguard Worker common.main(do_latest=do_latest, 144*8975f5c5SAndroid Build Coastguard Worker do_install=do_install, 145*8975f5c5SAndroid Build Coastguard Worker runtime_deps=['//third_party/jdk/current']) 146