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
|
/*
* Copyright 2024 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.gradle_recipe.converter
import com.github.rising3.semver.SemVer
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import javax.xml.parsers.DocumentBuilderFactory
import kotlin.system.exitProcess
/**
* Entry point to call [findLatestVersion]
*
* Prints the latest version that begins with majorMinorVersion, or "NA" if no released version
* begins with majorMinorVersion.
*/
fun main(args: Array<String>) {
if (args.size != 2 || args.contains("--help")) {
System.err.println("Usage: LatestVersionFinder <mavenMetadataFile> <majorMinorVersion>")
exitProcess(1)
}
val mavenMetadataFile = args[0]
val majorMinorVersion = args[1]
println(findLatestVersion(File(mavenMetadataFile), majorMinorVersion) ?: "NA")
}
/**
* Parse [mavenMetadataFile] and return the latest version that begins with
* [majorMinorVersion], or return null if no such version found.
*
* [mavenMetadataFile] is assumed to be a xml file in the expected maven metadata format.
*/
fun findLatestVersion(mavenMetadataFile: File, majorMinorVersion: String): String? {
FileInputStream(mavenMetadataFile).use { stream ->
val map = findLatestVersion(stream, listOf(majorMinorVersion))
return map[majorMinorVersion]
}
}
/**
* Parse [mavenMetadataContent] and return the latest version of AGP for all short-versions (x.y) provided
*
* [mavenMetadataContent] is assumed to be a xml file in the expected maven metadata format.
*/
internal fun findLatestVersion(mavenMetadataContent: InputStream, shortAgpVersions: List<String>): Map<String, String> {
val maxMap = mutableMapOf<String, String>()
shortAgpVersions.forEach(::validateMajorMinorVersion)
val versionNodeList =
DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(mavenMetadataContent)
.getElementsByTagName("version")
for (i in 0 until versionNodeList.length) {
val version = versionNodeList.item(i).textContent
for (agpVersion in shortAgpVersions) {
if (version.startsWith("$agpVersion.")) {
when (val max = maxMap[agpVersion]) {
null -> maxMap[agpVersion] = version
else -> if (SemVer.parse(version) > SemVer.parse(max)) {
maxMap[agpVersion] = version
}
}
}
}
}
return maxMap
}
/**
* Throw a RuntimeException if majorMinorVersion not formatted as "X.Y", where X and Y are
* both positive whole numbers
*/
private fun validateMajorMinorVersion(majorMinorVersion: String) {
val pattern = Regex("^\\d+\\.\\d+$")
if (pattern.matches(majorMinorVersion)) {
return
}
throw RuntimeException(
"majorMinorVersion must be formatted as \"X.Y\", where X and Y are positive " +
"whole numbers."
)
}
|