diff --git a/gazelle/kotlin/tests/gcsutil/BUILD.in b/gazelle/kotlin/tests/gcsutil/BUILD.in new file mode 100644 index 000000000..f6ad5f59e --- /dev/null +++ b/gazelle/kotlin/tests/gcsutil/BUILD.in @@ -0,0 +1 @@ +# gazelle:resolve kotlin com.google.cloud.storage.contrib.nio @maven//:com_google_cloud_google_cloud_nio diff --git a/gazelle/kotlin/tests/gcsutil/BUILD.out b/gazelle/kotlin/tests/gcsutil/BUILD.out new file mode 100644 index 000000000..d776aebfa --- /dev/null +++ b/gazelle/kotlin/tests/gcsutil/BUILD.out @@ -0,0 +1,9 @@ +load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +# gazelle:resolve kotlin com.google.cloud.storage.contrib.nio @maven//:com_google_cloud_google_cloud_nio + +kt_jvm_library( + name = "gcsutil", + srcs = ["gcsutil.kt"], + deps = ["@maven//:com_google_cloud_google_cloud_nio"], +) diff --git a/gazelle/kotlin/tests/gcsutil/WORKSPACE b/gazelle/kotlin/tests/gcsutil/WORKSPACE new file mode 100644 index 000000000..105b24c73 --- /dev/null +++ b/gazelle/kotlin/tests/gcsutil/WORKSPACE @@ -0,0 +1,2 @@ +# This is a Bazel workspace for the Gazelle test data. +workspace(name = "simple_file") diff --git a/gazelle/kotlin/tests/gcsutil/gcsutil.kt b/gazelle/kotlin/tests/gcsutil/gcsutil.kt new file mode 100644 index 000000000..3fc49ab10 --- /dev/null +++ b/gazelle/kotlin/tests/gcsutil/gcsutil.kt @@ -0,0 +1,132 @@ +package gazelle.kotlin.tests.gcsutil + +import com.google.cloud.storage.contrib.nio.CloudStorageFileSystem +import com.google.cloud.storage.contrib.nio.CloudStoragePath +import java.net.URI + +private fun quote(value: String): String = "\"$value\"" + +/** + * Checks that the uri is formatted like "gs://bucket/file/path.txt", the form accepted by + * gsutil, and returns a [CloudStorageUri]. + * + * @throws IllegalArgumentException if the scheme is not a valid GCS path. + * @return a wrapper around [URI] that ensures the URI passed + */ +fun URI.toCloudStorageUri(): CloudStorageUri = CloudStorageUri(this) + +/** + * Returns true if the URI is a valid GCS URI as accepted by [CloudStorageUri]. + */ +fun URI.isCloudStorageUri(): Boolean { + return try { + this.validateGoogleCloudStorageUri() + true + } catch (e: java.lang.IllegalArgumentException) { + false + } +} + +private fun URI.validateGoogleCloudStorageUri() { + if (this.scheme != "gs") { + throw IllegalArgumentException( + "URI doesn't start with gs://, got scheme ${this.scheme}", + ) + } + val fragment = this.rawFragment ?: "" + if (fragment.isNotEmpty()) { + throw IllegalArgumentException( + "GCS uris must not have a fragment, got ${quote(fragment)}", + ) + } + val query = this.rawQuery ?: "" + if (query.isNotEmpty()) { + throw IllegalArgumentException( + "GCS uris must not have a query part, got ${quote(query)}", + ) + } + val path = this.rawPath + if (path.contains("//")) { + throw IllegalArgumentException( + "GCS URIs should not contain two adjacent slashes: ${quote(this)}", + ) + } +} + +/** + * A class for keeping a validated (per [validateGoogleCloudStorageUri]) URI. + * + * @throws IllegalArgumentException if the passed uri isn't a GCS URI. + */ +// TODO(reddaly): Add more checks to ensure the bucket characters comply with GCS requirements. +@JvmInline +value class CloudStorageUri(val uri: URI) { + constructor(gsUri: String) : this(URI.create(gsUri)) + + init { + uri.validateGoogleCloudStorageUri() + } + + /** + * Returns a [CloudStoragePath] for this "gs://"-style URI. + */ + val path: CloudStoragePath get() = CloudStorageFileSystemSet.DEFAULT.pathFromGsUri(this) + + /** + * Returns the GCS path without a leading gs://. The result is formatted like + * / + */ + val pathStringWithBucketName: String get() = this.uri.toString().removePrefix("gs://") + + /** + * Returns the GCS bucket name for this path. + */ + val bucket: String get() = this.uri.authority + + /** + * The path of the file within the bucket. For "gs://bucket-x/foo/bar", returns "foo/bar". + * For "gs://bucket-x", returns "". + */ + val bucketRelativePath: String get() = this.uri.path.removePrefix("/") + + /** + * Returns a string like "gs://foo/bar". + */ + override fun toString(): String = this.uri.toString() + + /** + * Resolves a GCS path using [URI.resolve] on the URI version of this object. + * + * CloudStorageUri("gs://foo/bar", "baz") returns + * CloudStorageUri("gs://foo/bar/baz"). + */ + fun child(relativePath: String): CloudStorageUri = + CloudStorageUri(URI("$this/$relativePath")) +} + +// TODO: Workaround for https://github.com/googleapis/java-storage-nio/issues/1153 - +private class CloudStorageFileSystemSet { + companion object { + /** + * A singleton instance of CloudStorageFileSystemSet. + */ + val DEFAULT = CloudStorageFileSystemSet() + } + + private val fileSystemByBucketName: MutableMap = + mutableMapOf() + + /** + * Returns the value of a "gs://bucket/file/path.txt"-style GCP location as a [Path]. + */ + fun pathFromGsUri(uri: CloudStorageUri): CloudStoragePath { + val bucket = uri.bucket + val relativePath = uri.bucketRelativePath + val fs = synchronized(this.fileSystemByBucketName) { + this.fileSystemByBucketName.getOrPut(bucket) { + CloudStorageFileSystem.forBucket(bucket) + } + } + return fs.getPath(relativePath) + } +} diff --git a/gazelle/kotlin/tests/simple_file2/BUILD.in b/gazelle/kotlin/tests/simple_file2/BUILD.in new file mode 100644 index 000000000..d6cedcf3d --- /dev/null +++ b/gazelle/kotlin/tests/simple_file2/BUILD.in @@ -0,0 +1 @@ +# gazelle:resolve kotlin com.google.cloud.storage.contrib.nio @maven//:com_google_cloud_google_cloud_nio \ No newline at end of file diff --git a/gazelle/kotlin/tests/simple_file2/BUILD.out b/gazelle/kotlin/tests/simple_file2/BUILD.out new file mode 100644 index 000000000..8e14af6bf --- /dev/null +++ b/gazelle/kotlin/tests/simple_file2/BUILD.out @@ -0,0 +1,9 @@ +load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +# gazelle:resolve kotlin com.google.cloud.storage.contrib.nio @maven//:com_google_cloud_google_cloud_nio + +kt_jvm_library( + name = "simple_file", + srcs = ["lib.kt"], + deps = ["@maven//:com_google_cloud_google_cloud_nio"], +) diff --git a/gazelle/kotlin/tests/simple_file2/WORKSPACE b/gazelle/kotlin/tests/simple_file2/WORKSPACE new file mode 100644 index 000000000..105b24c73 --- /dev/null +++ b/gazelle/kotlin/tests/simple_file2/WORKSPACE @@ -0,0 +1,2 @@ +# This is a Bazel workspace for the Gazelle test data. +workspace(name = "simple_file") diff --git a/gazelle/kotlin/tests/simple_file2/lib.kt b/gazelle/kotlin/tests/simple_file2/lib.kt new file mode 100644 index 000000000..251677628 --- /dev/null +++ b/gazelle/kotlin/tests/simple_file2/lib.kt @@ -0,0 +1,8 @@ +package xyz.example.gcsutil + +import com.google.cloud.storage.contrib.nio.CloudStoragePath + +fun hello(): CloudStoragePath? { + println("Hello world!") + return null +} diff --git a/go.bzl b/go.bzl index 4ba7c6152..347f12f5a 100644 --- a/go.bzl +++ b/go.bzl @@ -728,10 +728,10 @@ def deps(): name = "com_github_smacker_go_tree_sitter", build_file_proto_mode = "disable_global", importpath = "github.com/smacker/go-tree-sitter", - sum = "h1:exZ0FwfhblsYbgfqYH+W/3sFye821WD02NjBmc+ENhE=", - version = "v0.0.0-20230501083651-a7d92773b3aa", + commit = "0e314ace747f49b293ec3a5ec9d7df8395269b53", + vcs = "git", + remote = "git@github.com:reddaly/go-tree-sitter.git", ) - go_repository( name = "com_github_spf13_afero", build_file_proto_mode = "disable_global",