plugin: Support S3 repositories

This commit is contained in:
Tad Fisher
2021-02-02 16:43:35 -08:00
parent 55b3b60535
commit 80b8a7d52e
28 changed files with 1475 additions and 3842 deletions

24
ivy/build.gradle.kts Normal file
View File

@@ -0,0 +1,24 @@
plugins {
kotlin("jvm")
}
dependencies {
api("org.apache.ivy:ivy:latest.release")
api("com.amazonaws:aws-java-sdk-s3:latest.release")
testImplementation("com.adobe.testing:s3mock-junit5:latest.release")
testImplementation("io.strikt:strikt-core:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:latest.release")
}
tasks {
test {
useJUnitPlatform {
includeEngines("junit-jupiter")
}
systemProperty("fixtures", "$rootDir/fixtures")
}
}

123
ivy/gradle.lockfile Normal file
View File

@@ -0,0 +1,123 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
ch.qos.logback:logback-classic:1.2.3=testCompileClasspath,testRuntimeClasspath
ch.qos.logback:logback-core:1.2.3=testCompileClasspath,testRuntimeClasspath
com.adobe.testing:s3mock-junit5:2.1.28=testCompileClasspath,testRuntimeClasspath
com.adobe.testing:s3mock-testsupport-common:2.1.28=testCompileClasspath,testRuntimeClasspath
com.adobe.testing:s3mock:2.1.28=testCompileClasspath,testRuntimeClasspath
com.amazonaws:aws-java-sdk-core:1.11.946=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.amazonaws:aws-java-sdk-kms:1.11.946=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.amazonaws:aws-java-sdk-s3:1.11.946=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.amazonaws:jmespath-java:1.11.946=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.christophsturm:filepeek:0.1.2=testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.6.0=compileClasspath,runtimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.9.0=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.6.7=compileClasspath,runtimeClasspath
com.fasterxml.jackson.core:jackson-core:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.6.7.4=compileClasspath,runtimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.9.9.3=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.6.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9=testCompileClasspath,testRuntimeClasspath
com.fasterxml.woodstox:woodstox-core:5.1.0=testCompileClasspath,testRuntimeClasspath
com.fasterxml:classmate:1.3.4=testCompileClasspath,testRuntimeClasspath
com.typesafe.netty:netty-reactive-streams-http:2.0.0=testRuntimeClasspath
com.typesafe.netty:netty-reactive-streams:2.0.0=testRuntimeClasspath
commons-codec:commons-codec:1.11=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.6=testCompileClasspath,testRuntimeClasspath
commons-logging:commons-logging:1.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-buffer:4.1.33.Final=testRuntimeClasspath
io.netty:netty-codec-http2:4.1.33.Final=testRuntimeClasspath
io.netty:netty-codec-http:4.1.33.Final=testRuntimeClasspath
io.netty:netty-codec:4.1.33.Final=testRuntimeClasspath
io.netty:netty-common:4.1.33.Final=testRuntimeClasspath
io.netty:netty-handler:4.1.33.Final=testRuntimeClasspath
io.netty:netty-resolver:4.1.33.Final=testRuntimeClasspath
io.netty:netty-transport-native-epoll:4.1.33.Final=testRuntimeClasspath
io.netty:netty-transport-native-unix-common:4.1.33.Final=testRuntimeClasspath
io.netty:netty-transport:4.1.33.Final=testRuntimeClasspath
io.strikt:strikt-core:0.28.2=testCompileClasspath,testRuntimeClasspath
javax.annotation:javax.annotation-api:1.3.2=testCompileClasspath,testRuntimeClasspath
javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath
javax.validation:validation-api:2.0.1.Final=testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.8.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-lang3:3.8.1=testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpclient:4.5.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpcore:4.4.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.ivy:ivy:2.5.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.logging.log4j:log4j-api:2.11.2=testCompileClasspath,testRuntimeClasspath
org.apache.logging.log4j:log4j-to-slf4j:2.11.2=testCompileClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.0=testCompileClasspath,testRuntimeClasspath
org.codehaus.woodstox:stax2-api:4.1=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-continuation:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-http:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-io:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-security:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-server:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-servlet:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-servlets:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-webapp:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-xml:9.4.19.v20190610=testCompileClasspath,testRuntimeClasspath
org.hibernate.validator:hibernate-validator:6.0.17.Final=testCompileClasspath,testRuntimeClasspath
org.jboss.logging:jboss-logging:3.3.2.Final=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-reflect:1.4.21-2=testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20=compileClasspath,runtimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.21-2=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21-2=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.21-2=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.4.20=compileClasspath,runtimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.4.21-2=testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.2=testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2=testRuntimeClasspath
org.jetbrains:annotations:13.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.7.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.7.0=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.7.0=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.7.0=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.7.0=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.7.0=testRuntimeClasspath
org.junit:junit-bom:5.7.0=testCompileClasspath,testRuntimeClasspath
org.mortbay.jasper:apache-el:8.5.40=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath
org.reactivestreams:reactive-streams:1.0.2=testCompileClasspath,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.28=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.28=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-jetty:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-json:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-logging:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-web:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot-starter:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework.boot:spring-boot:2.1.9.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-aop:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-beans:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-context:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-core:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-expression:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-jcl:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-web:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.springframework:spring-webmvc:5.1.10.RELEASE=testCompileClasspath,testRuntimeClasspath
org.yaml:snakeyaml:1.23=testRuntimeClasspath
software.amazon.awssdk:annotations:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:apache-client:2.7.19=testRuntimeClasspath
software.amazon.awssdk:auth:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:aws-core:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:aws-query-protocol:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:aws-xml-protocol:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:http-client-spi:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:netty-nio-client:2.7.19=testRuntimeClasspath
software.amazon.awssdk:profiles:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:protocol-core:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:regions:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:s3:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:sdk-core:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:url-connection-client:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.awssdk:utils:2.7.19=testCompileClasspath,testRuntimeClasspath
software.amazon.eventstream:eventstream:1.0.1=testCompileClasspath,testRuntimeClasspath
software.amazon.ion:ion-java:1.0.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
empty=

View File

@@ -0,0 +1,294 @@
package org.nixos.gradle2nix
import com.amazonaws.AmazonServiceException
import com.amazonaws.ClientConfiguration
import com.amazonaws.auth.AWSCredentials
import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.client.builder.AwsClientBuilder
import com.amazonaws.regions.Region
import com.amazonaws.regions.RegionUtils
import com.amazonaws.regions.Regions
import com.amazonaws.services.s3.AmazonS3
import com.amazonaws.services.s3.AmazonS3ClientBuilder
import com.amazonaws.services.s3.model.GetObjectRequest
import com.amazonaws.services.s3.model.ListObjectsRequest
import com.amazonaws.services.s3.model.ObjectMetadata
import com.amazonaws.services.s3.model.S3Object
import com.amazonaws.services.s3.model.S3ObjectInputStream
import com.amazonaws.util.AwsHostNameUtils
import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
import org.apache.ivy.core.settings.TimeoutConstraint
import org.apache.ivy.plugins.repository.AbstractRepository
import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.repository.TransferEvent
import org.apache.ivy.util.FileUtil
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.Socket
import java.net.URI
import java.security.KeyManagementException
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLEngine
import javax.net.ssl.TrustManager
import javax.net.ssl.X509ExtendedTrustManager
class S3Repository(
private val client: AmazonS3,
timeoutConstraint: TimeoutConstraint? = null
) : AbstractRepository(timeoutConstraint) {
constructor(
credentials: AWSCredentials?,
endpoint: URI?,
timeoutConstraint: TimeoutConstraint?
) : this(
AmazonS3ClientBuilder.standard().apply {
credentials?.let { setCredentials(AWSStaticCredentialsProvider(it)) }
if (endpoint != null) {
setEndpointConfiguration(
AwsClientBuilder.EndpointConfiguration(
endpoint.toString(),
AwsHostNameUtils.parseRegion(endpoint.host, null) ?: Regions.US_EAST_1.name
)
)
isChunkedEncodingDisabled = true
isPathStyleAccessEnabled = true
} else {
region = Regions.US_EAST_1.name
}
if (System.getProperty("org.nixos.gradle2nix.s3test") != null) {
clientConfiguration = ClientConfiguration().apply {
apacheHttpClientConfig.sslSocketFactory = SSLConnectionSocketFactory(
createBlindlyTrustingSslContext(),
NoopHostnameVerifier.INSTANCE
)
}
}
}.build(),
timeoutConstraint
)
private val cache = mutableMapOf<String, S3Resource>()
private val progress = RepositoryCopyProgressListener(this)
override fun getResource(source: String): Resource =
cache.getOrPut(source) { S3Resource(this, URI(source)) }
override fun get(source: String, destination: File) {
fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET)
try {
val res = getResource(source)
val totalLength = res.contentLength
if (totalLength > 0) {
progress.totalLength = totalLength
}
destination.parentFile?.mkdirs()
FileUtil.copy(
res.openStream(),
FileOutputStream(destination),
progress,
true
)
fireTransferCompleted(res.contentLength)
} catch (e: Exception) {
fireTransferError(e)
throw e
} finally {
progress.totalLength = null
}
}
override fun list(parent: String): List<String> =
S3Resource(this, URI(parent))
.let { resource ->
generateSequence({
try {
withClient(resource) {
listObjects(
ListObjectsRequest()
.withBucketName(resource.bucket)
.withPrefix(resource.key)
.withDelimiter("/")
)
}
} catch (e: AmazonServiceException) {
throw S3RepositoryException(e)
}
}) { prev ->
if (!prev.isTruncated) {
null
} else {
try {
withClient(resource) {
listNextBatchOfObjects(prev)
}
} catch (e: AmazonServiceException) {
throw S3RepositoryException(e)
}
}
}
}
.flatMap { listing ->
listing.commonPrefixes.asSequence() +
listing.objectSummaries.asSequence().map { it.key }
}
.toList()
internal fun <T> withClient(
resource: S3Resource,
block: AmazonS3.() -> T
): T = client.apply {
resource.region?.let { setRegion(it) }
}.block()
}
class S3Resource(
private val repository: S3Repository,
private val url: URI
) : Resource {
private val source: Source by lazy {
REGIONAL_ENDPOINT_PATTERN.find(url.normalize().toString())
?.let {
val (bucket, region, _, key) = it.destructured
Source(
bucket = bucket,
key = key,
region = when (region) {
"external-1" -> Region.getRegion(Regions.US_EAST_1)
else -> RegionUtils.getRegion(region)
}
)
}
?: Source(
bucket = url.bucket(),
key = url.key(),
region = null
)
}
private val metadata: Metadata by lazy {
try {
getMetadata()
} catch (e: AmazonServiceException) {
null
}?.let { meta ->
Metadata(
exists = true,
contentLength = meta.contentLength,
lastModified = meta.lastModified.time
)
} ?: Metadata(
exists = false,
contentLength = 0,
lastModified = 0
)
}
val bucket: String get() = source.bucket
val key: String get() = source.key
val region: Region? get() = source.region
override fun getName(): String = url.toString()
override fun getLastModified(): Long = metadata.lastModified
override fun getContentLength(): Long = metadata.contentLength
override fun exists(): Boolean = metadata.exists
override fun isLocal(): Boolean = false
override fun clone(cloneName: String): Resource = S3Resource(repository, URI(cloneName))
override fun openStream(): InputStream =
try { getContent() }
catch (e: AmazonServiceException) { throw S3RepositoryException(e) }
?: throw S3RepositoryException()
private fun getMetadata(): ObjectMetadata? =
getObject(withContent = false)?.objectMetadata
private fun getContent(): S3ObjectInputStream? =
getObject(withContent = true)?.objectContent
private fun getObject(withContent: Boolean = true): S3Object? {
val request = GetObjectRequest(bucket, key)
if (!withContent) {
request.setRange(0, 0)
}
return try {
repository.withClient(this) { getObject(request) }
} catch (e: AmazonServiceException) {
val errorCode = e.errorCode
if (errorCode != null && "NoSuchKey".compareTo(errorCode, ignoreCase = true) == 0) {
null
} else {
e.printStackTrace()
throw e
}
}
}
private data class Source(
val bucket: String,
val key: String,
val region: Region?
)
private data class Metadata(
val exists: Boolean,
val contentLength: Long,
val lastModified: Long
)
companion object {
private val REGIONAL_ENDPOINT_PATTERN =
Regex("""^s3://(.+)?\.s3[.-]([a-z0-9-]+)\.amazonaws\.com(\.[a-z]+)?/(.+)""")
}
}
class S3RepositoryException : RuntimeException {
constructor() : super()
constructor(throwable: Throwable) : super(throwable)
}
private fun URI.bucket(): String = normalize().host
private fun URI.key(): String = normalize().path.removePrefix("/")
// Used for testing.
private fun createBlindlyTrustingSslContext(): SSLContext? {
return try {
SSLContext.getInstance("TLS").apply {
init(null, arrayOf<TrustManager>(object : X509ExtendedTrustManager() {
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
override fun checkClientTrusted(arg0: Array<X509Certificate?>?, arg1: String?, arg2: Socket?) {}
override fun checkClientTrusted(arg0: Array<X509Certificate?>?, arg1: String?, arg2: SSLEngine?) {}
override fun checkClientTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
override fun checkServerTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
override fun checkServerTrusted(arg0: Array<X509Certificate?>?, arg1: String?, arg2: Socket?) {}
override fun checkServerTrusted(arg0: Array<X509Certificate?>?, arg1: String?, arg2: SSLEngine?) {}
}), SecureRandom())
}
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Unexpected exception", e)
} catch (e: KeyManagementException) {
throw RuntimeException("Unexpected exception", e)
}
}

View File

@@ -0,0 +1,113 @@
package org.nixos.gradle2nix
import com.adobe.testing.s3mock.junit5.S3MockExtension
import com.amazonaws.services.s3.AmazonS3
import org.apache.ivy.ant.IvyDependencyArtifact
import org.apache.ivy.core.module.descriptor.Artifact
import org.apache.ivy.core.module.descriptor.DefaultArtifact
import org.apache.ivy.core.module.id.ArtifactRevisionId
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.resolver.IBiblioResolver
import org.apache.ivy.plugins.resolver.URLResolver
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.extension.RegisterExtension
import strikt.api.expectThat
import strikt.assertions.containsExactly
import strikt.assertions.isEmpty
import strikt.assertions.isEqualTo
import strikt.assertions.isFalse
import strikt.assertions.isNotEqualTo
import strikt.assertions.isNotNull
import strikt.assertions.isTrue
import java.io.File
import java.net.URI
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createTempDirectory
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class S3Test {
companion object {
const val bucket = "repositories"
val fixtureRoot = File(System.getProperty("fixtures")).resolve(bucket)
@JvmField
@RegisterExtension
val s3mock: S3MockExtension = S3MockExtension.builder().withInitialBuckets(bucket).build()
}
@BeforeAll
fun populateBucket(client: AmazonS3) {
fixtureRoot.walkTopDown()
.filter { it.isFile }
.forEach { file ->
val key = file.toRelativeString(fixtureRoot)
client.putObject(bucket, key, file)
}
}
@Test
fun listsContents(client: AmazonS3) {
val repository = S3Repository(client)
expectThat(repository.list("s3://repositories/m2/org/apache/test/1.0.0/")).containsExactly(
"m2/org/apache/test/1.0.0/test-1.0.0.jar",
"m2/org/apache/test/1.0.0/test-1.0.0.pom",
)
}
@Test
fun findsResourceMetadata(client: AmazonS3) {
val repository = S3Repository(client)
val resource: Resource = S3Resource(repository, URI("s3://repositories/m2/org/apache/test/1.0.0/test-1.0.0.pom"))
expectThat(resource).and {
get { exists() }.isTrue()
get { contentLength }.isNotEqualTo(-1L)
get { lastModified }.isNotEqualTo(-1L)
}
}
@Test
fun downloadsResource(client: AmazonS3) {
val repository = S3Repository(client)
val resource: Resource = S3Resource(repository, URI("s3://repositories/m2/org/apache/test/1.0.0/test-1.0.0.pom"))
val source = fixtureRoot.resolve("m2/org/apache/test/1.0.0/test-1.0.0.pom").readText()
expectThat(resource.openStream().bufferedReader().readText()).isEqualTo(source)
}
@ExperimentalPathApi
@Test
fun locatesArtifact(client: AmazonS3) {
val resolver = IBiblioResolver().apply {
name = "s3"
root = "s3://repositories/m2/"
isM2compatible = true
settings = IvySettings().apply {
defaultInit()
setDefaultRepositoryCacheBasedir(createTempDirectory().toString())
}
repository = S3Repository(client)
}
val origin = resolver.locate(DefaultArtifact(
ArtifactRevisionId.newInstance(
ModuleRevisionId.newInstance("org.apache", "test", "1.0.0"),
"test",
"jar",
"jar"
),
null,
null,
false
))
expectThat(origin).isNotNull().and {
get { isExists }.isTrue()
get { isLocal }.isFalse()
get { location }.isEqualTo("s3://repositories/m2/org/apache/test/1.0.0/test-1.0.0.jar")
}
}
}