在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):square/maven-archeologist开源软件地址(OpenSource Url):https://github.com/square/maven-archeologist开源编程语言(OpenSource Language):Kotlin 83.1%开源软件介绍(OpenSource Introduction):Maven Archeologist
A library to make resolving maven artifacts (from various repositories) easy. The library itself wraps the Maven resolver APIs and provides simple HTTP-based resolution. From this any number of tools can be constructed, which require obtaining (and locally caching) maven artifacts, resolving the "effective project model", validating hashes, etc. ContentsUsageThe main entry point to the library, which wraps (and mostly hides) the Maven resolution
infrastructure, is Add to a buildMaven-Archeologist is published as Gradle: dependencies {
implementation 'com.squareup.tools.build:maven-archeologist:0.0.3.1'
} Maven: <dependency>
<groupId>com.squareup.tools.build</groupId>
<artifactId>maven-archeologist</artifactId>
<version>0.0.3.1</version>
</dependency>
Simplest UsageIn this variant, the API just downloads the POM and artifact files and their hash files, validates the files, and returns POM and artifact files to you in a small data class you can destructure easily, containing the pom file, the main artifact file, and optionally the sources file. val resolver = ArtifactResolver() // creates a resolver with repo list defaulting to Maven Central.
val (pom, artifact) = resolver.download("com.google.guava:guava:27.1-jre") To also get source jars, you can do val resolver = ArtifactResolver() // creates a resolver with repo list defaulting to Maven Central.
val (pom, artifact, sourcejar) = resolver.download("com.google.guava:guava:27.1-jre", downloadSources = true)
Resolving MetadataAn artifact can be resolved without automatically downloading via the following: val resolver = ArtifactResolver() // creates a resolver with repo list defaulting to Maven Central.
val artifact = resolver.artifactFor("com.google.guava:guava:27.1-jre") // returns Artifact
val resolvedArtifact = resolver.resolveArtifact(artifact) // returns ResolvedArtifact
val dependencies: List<Dependency> = resolvedArtifact.model.dependencies
Downloading ArtifactsThe resolved artifact can then also be used to fetch the main artifact. The The pom file will be downloaded and in the local cache, upon obtaining a val result = resolver.download(resolvedArtifact) // returns FetchStatus
// if you care about whether it was a cache-hit or not, do this. Otherwise test for "is SUCCESSFUL"
when (result) {
is SUCCESSFUL.FOUND_IN_CACHE -> { /* win! */ }
is SUCCESSFUL.SUCESSFULLY_FETCHED -> { /* win, but remotely! */ }
else -> { /* Handle error */ }
} Once you get one of the two SUCCESSFUL signals shown above, the file will be available for access
in the val pomLines = Files.readAllLines(resolved.pom.localFile) // do what you do with Path objects here.
val mainLines = Files.readAllLines(resolved.main.localFile) // do what you do with Path objects here. Downloading SourcesSource artifacts can be downloaded, similar to the main artifact, simply asking the resolver for them, like so: val result = resolver.downloadSources(resolvedArtifact) // returns FetchStatus
require(result.sources.localFile.exists()) { "File should have existed" }
val lines = Files.readAllLines(resolved.sources.localFile) // do what you do with Path objects here. Sources can also be obtained by the simplified val (pom, artifact, sourcejar) = resolver.download("com.google.guava:guava:27.1-jre", downloadSources = true)
val lines = Files.readAllLines(sourceJar) // do what you do with Path objects here. Downloading Classified Sub-ArtifactsClassified artifacts (artifacts with a classifier) requires a bit more information. Classified sub-artifacts be fully described in the pom, but may not be. A classified file reference can be obtained from the resolved artifact, and requested like so: val artifact = resolver.artifactFor("foo.bar:bar:1.0") // assume this is a "jar" type
val resolved = resolver.resolveArtifact(artifact)
val classified = resolved.subArtifact("extra") // references bar-1.0-extra.jar
val status = resolver.downloadSubArtifact(classified) //
if (status is SUCCESSFUL) {
Files.readAllLines(classified.localFile).forEach { /* do line stuff */ }
} else { /* freak out */ } Some classified sub-artifacts do not have the same file suffix as their main artifact. Such artifacts can be referenced like this: val artifact = resolver.artifactFor("foo.bar:bar:1.0") // assume this is a "jar" type
val resolved = resolver.resolveArtifact(artifact)
val classified = resolved.subArtifact("extra", "zip) // references bar-1.0-extra.zip
val classifiedStatus = resolver.downloadSubArtifact(classified) //
if (status is SUCCESSFUL) {
Files.readAllLines(classified.localFile).forEach { /* do line stuff */ }
} else { /* freak out */ } Adding RepositoriesThe resolver defaults to resolving against Maven Central. Specifying repositories is as simple as: val repo1 = Repository().apply {
id = "some-identifier"
releases = RepositoryPolicy().apply { enabled = "true" }
url = "https://some.server/path/to/repo" // At present, only http/https are supported.
}
val repo2 = ...
val resolver = ArtifactResolver(repositories = listOf(rep1, rep2))
Reasonably popular repositories have been pre-defined in the Local Artifact CacheBy default, artifacts are cached in val resolver = ArtifactResolver(cacheDir = fs.getPath("/some/cache/dir")) Proxies and fetchingMaven Archeologist uses OkHttp 4.0 and HttpArtifactFetcher can be created with a lambda that
supplies a configured Default Environment Variables
To use a proxy in the default setup, set the a variable in the environment in which the app you wish to use will run with the url of the proxy service (including, optionally, a username/password). e.g.: export HTTP_PROXY=localhost:8080
artifact_resolver_cli some:artifact:1.0 Assuming Because some environments need to disallow certain addresses from being routed through the
proxy (for security or performance reasons), setting a list of url matching infixes into
the environment variable export HTTP_PROXY=localhost:8080
export NO_PROXY=.repo.corp,.repo2.corp
artifact_resolver_cli some:artifact:1.0 This would cause artifacts fetched/resolved from (for example) Custom Client ProvisionIf this default machanism isn't appropriate, different heuristics are needed, or for any other reason,
an object HttpClientHelper {
val proxiedClient = OkHttpClient.builder()
// set proxy based on an env var CI_ENVIRONMENT
.build()
fun clientForUrl(url: String) = proxiedClient // doesn't care about URL
}
... later ...
val cacheDir = fs.getPath("/path/to/local/cache")
val fetcher = HttpArtifactFetcher(cacheDir = cacheDir, HttpClientHelper::clientForUrl)
val resolver = ArtifactResolver(cacheDir = fs.getPath("/some/cache/dir")) or object HttpClientHelper {
val unproxied OkHttpClient.builder().build()
val proxied = OkHttpClient.builder()
// set settings
.build()
fun clientForUrl(url: String) = with(URL(url)) {
when {
this.host.startsWith("foo.bar") -> unproxied
this.host.endsWith("blah.foo") -> unproxied
else -> proxied
}
}
... later ...
val cacheDir = fs.getPath("/path/to/local/cache")
val fetcher = HttpArtifactFetcher(cacheDir = cacheDir, HttpClientHelper::clientForUrl)
val resolver = ArtifactResolver(cacheDir = fs.getPath("/some/cache/dir"))
This mechanism can be used to create as many kinds of clients, or as few, as sensibly works for your system. It can return a fresh client every time, or reuse clients with the same configuration, hold builders - whatever you need to configure a request appropriately. Comparing Artifact Versionsmaven-archeologist has a convenience for representing maven versions in a way that they can be
compared according to semantic versioning, or at least the maven 3 variant, rather than merely
lexically. MavenVersion extends val versions = listOf(
MavenVersion.from("2.3.5-SNAPSHOT"),
MavenVersion.from("2.3.5"),
MavenVersion.from("2.0"),
MavenVersion.from("2a.0"),
MavenVersion.from("2.0-beta"),
MavenVersion.from("2.0-beta-SNAPSHOT"),
MavenVersion.from("2.3.5.2"),
).sorted()
println(versions)
// should print [2.0-beta-SNAPSHOT, 2.0-beta, 2.0, 2.3.5-SNAPSHOT, 2.3.5, 2.3.5.2, 2a.0]
Data ModelsMavenA maven metadata model is supplied from a It is an "effective model", meaning all resolution of parent metadata, GradleA Gradle Module metadata object is supplied from a This is a straight json parse (via Moshi) and does not have any particular "resolution" performed on it.
The only dynamics that might be reasonable is the Module Spec EvolutionThe gradle data model is implemented using Currently, there is only one subtype (
Demo CLIThe project also contains a demo CLI app which will resolve and download the maven artifacts listed on the repository, cache them in a defined directory. It is iterative and single-threaded, so not suitable for high-volume resolution, but it can help for small tasks and show how to wield the APIs. bazel run //:resolver -- --local_maven_cache /path/to/cache some:artifact:1 another:artifact:2 Possible uses
Core Capabilities
Known Limitations
Planned features
License
About the projectWhy Archeologist?Because the library handles artifacts, and references to certain movies starring Harrison Ford might garner trademark concerns. Why not Archaeologist?Because 'murica! More seriously, both spellings are accepted english, and while the primary author is Canadian, he lives in the US. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论