You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
7.1 KiB
219 lines
7.1 KiB
4 years ago
|
import io.ktor.client.*
|
||
|
import io.ktor.client.engine.jetty.*
|
||
|
import kotlinx.coroutines.runBlocking
|
||
|
import org.apache.commons.io.FilenameUtils
|
||
|
import space.jetbrains.api.runtime.*
|
||
|
import space.jetbrains.api.runtime.resources.projects
|
||
|
import space.jetbrains.api.runtime.types.*
|
||
|
import java.util.*
|
||
|
import kotlin.collections.ArrayList
|
||
|
|
||
|
val checkJavaVersion = tasks.register("checkJavaVersion") {
|
||
|
doLast {
|
||
|
check(JavaVersion.current() >= JavaVersion.VERSION_1_9) {
|
||
|
"Use JDK 9+ to run this task"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tasks.register("listProjectsAndPackageRepositories") {
|
||
|
dependsOn(checkJavaVersion)
|
||
|
|
||
|
doLast {
|
||
|
Space().listProjectsAndPackageRepositories()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
val packagesToDeleteFile: File
|
||
|
get() = project.buildDir.resolve("packages-to-delete.txt")
|
||
|
|
||
|
tasks.register("generateListOfPackagesToDelete") {
|
||
|
dependsOn(checkJavaVersion)
|
||
|
doLast {
|
||
|
Space().preparePackagesToDelete(packagesToDeleteFile)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tasks.register("deletePackages") {
|
||
|
dependsOn(checkJavaVersion)
|
||
|
doLast {
|
||
|
Space().deletePackages(packagesToDeleteFile)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fun getLocalProperties() =
|
||
|
Properties().apply {
|
||
|
val file = project.file("local.properties")
|
||
|
if (file.exists()) {
|
||
|
file.inputStream().buffered().use { input ->
|
||
|
load(input)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Space {
|
||
|
private val localProperties = getLocalProperties()
|
||
|
|
||
|
fun property(name: String): String =
|
||
|
(localProperties.getProperty(name))
|
||
|
?: (project.findProperty(name) as? String)
|
||
|
?: error("Property '$name' is not set")
|
||
|
|
||
|
|
||
|
val token by lazy { property("space.auth.token") }
|
||
|
val server by lazy { property("space.server.url") }
|
||
|
val projectId by lazy { ProjectIdentifier.Id(property("space.project.id")) }
|
||
|
val repoId by lazy { PackageRepositoryIdentifier.Id(property("space.repo.id")) }
|
||
|
val packageVersionToDelete by lazy { property("space.package.version") }
|
||
|
|
||
|
fun withSpaceClient(fn: suspend SpaceHttpClientWithCallContext.() -> Unit) {
|
||
|
runBlocking<Unit> {
|
||
|
HttpClient(Jetty).use { client ->
|
||
|
val space = SpaceHttpClient(client).withPermanentToken(
|
||
|
token = token,
|
||
|
serverUrl = server
|
||
|
)
|
||
|
space.fn()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fun batches(batchSize: Int = 100) =
|
||
|
generateSequence(0) { it + batchSize }
|
||
|
.map { BatchInfo(it.toString(), batchSize) }
|
||
|
|
||
|
suspend fun <T> forAllInAllBatches(
|
||
|
getBatch: suspend (BatchInfo) -> Batch<T>,
|
||
|
fn: suspend (T) -> Unit
|
||
|
) {
|
||
|
for (batchInfo in batches()) {
|
||
|
val batch = getBatch(batchInfo)
|
||
|
|
||
|
for (element in batch.data) {
|
||
|
fn(element)
|
||
|
}
|
||
|
|
||
|
if (batch.data.isEmpty() || (batch.next.toIntOrNull() ?: 0) >= (batch.totalCount ?: 0)) return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
suspend fun SpaceHttpClientWithCallContext.forEachPackage(fn: suspend (PackageData) -> Unit) {
|
||
|
forAllInAllBatches({ batch ->
|
||
|
projects.packages.repositories.packages.getAllPackages(
|
||
|
project = projectId,
|
||
|
repository = repoId,
|
||
|
query = "",
|
||
|
batchInfo = batch
|
||
|
)
|
||
|
}, fn)
|
||
|
}
|
||
|
|
||
|
suspend fun SpaceHttpClientWithCallContext.forEachVersion(packageName: String, fn: suspend (String) -> Unit) {
|
||
|
forAllInAllBatches({ batch ->
|
||
|
projects.packages.repositories.packages.versions.getAllPackageVersions(
|
||
|
projectId, repoId,
|
||
|
packageName,
|
||
|
query = "",
|
||
|
sortColumn = PackagesSortColumn.Created,
|
||
|
sortOrder = ColumnSortOrder.DESC,
|
||
|
batchInfo = batch
|
||
|
)
|
||
|
}) { fn(it.version) }
|
||
|
}
|
||
|
|
||
|
suspend fun SpaceHttpClientWithCallContext.forEachProject(fn: suspend (PR_Project) -> Unit) {
|
||
|
forAllInAllBatches({ batch ->
|
||
|
projects.getAllProjects(batchInfo = batch)
|
||
|
}, fn)
|
||
|
}
|
||
|
|
||
|
suspend fun SpaceHttpClientWithCallContext.forEachPackageRepository(
|
||
|
proj: PR_Project,
|
||
|
fn: (ProjectPackageRepository) -> Unit
|
||
|
) {
|
||
|
projects.packages.repositories.getRepositories(
|
||
|
ProjectIdentifier.Id(proj.id)
|
||
|
).forEach(fn)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fun Space.listProjectsAndPackageRepositories() {
|
||
|
withSpaceClient {
|
||
|
forEachProject { proj ->
|
||
|
logger.quiet("Project '${proj.name}'(id: ${proj.id})")
|
||
|
forEachPackageRepository(proj) { repo ->
|
||
|
logger.quiet(" Package repository '${repo.name}(id: ${repo.id})'")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fun Space.preparePackagesToDelete(packagesFile: File) {
|
||
|
logger.quiet("Preparing list of packages for deletion. This may take some time...")
|
||
|
|
||
|
val packagesToDelete = ArrayList<PackageInfo>()
|
||
|
withSpaceClient {
|
||
|
forEachPackage { pkg ->
|
||
|
forEachVersion(pkg.name) { version ->
|
||
|
if (FilenameUtils.wildcardMatch(version, packageVersionToDelete)) {
|
||
|
packagesToDelete.add(PackageInfo(name = pkg.name, version = version))
|
||
|
}
|
||
|
}
|
||
|
logger.quiet("Analyzed package: ${pkg.name}")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
packagesFile.parentFile.mkdirs()
|
||
|
packagesFile.writer().buffered().use { writer ->
|
||
|
packagesToDelete.forEach {
|
||
|
writer.write("#")
|
||
|
writer.write(it.name)
|
||
|
writer.write(":")
|
||
|
writer.write(it.version)
|
||
|
writer.newLine()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
logger.quiet("List of packages to delete is written to:\n $packagesFile")
|
||
|
logger.quiet("Uncomment packages you want to delete and rerun the task!")
|
||
|
}
|
||
|
|
||
|
fun Space.deletePackages(packagesFile: File) {
|
||
|
if (!packagesFile.exists()) {
|
||
|
error("A list of packages to delete does not exist, run 'generateListOfPackagesToDelete' first")
|
||
|
}
|
||
|
val packagesToDelete = ArrayList<PackageInfo>()
|
||
|
packagesFile.forEachLine { line ->
|
||
|
if (!line.startsWith("#")) {
|
||
|
val split = line.split(":")
|
||
|
if (split.size == 2) {
|
||
|
packagesToDelete.add(PackageInfo(name = split[0], version = split[1]))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (packagesToDelete.isEmpty()) {
|
||
|
logger.quiet("No packages to delete!")
|
||
|
logger.quiet("Uncomment packages to delete them: ${packagesFile}")
|
||
|
} else {
|
||
|
val allPackagesToBeDeletedText = packagesToDelete.joinToString("\n") { "${it.name}:${it.version}" }
|
||
|
if (ConfirmDeletionDialog.confirm(allPackagesToBeDeletedText)) {
|
||
|
logger.quiet("Deleting ${packagesToDelete.size} packages...")
|
||
|
withSpaceClient {
|
||
|
for (pkg in packagesToDelete) {
|
||
|
projects.packages.repositories.packages.versions.deletePackageVersion(
|
||
|
projectId, repoId, packageName = pkg.name, packageVersion = pkg.version
|
||
|
)
|
||
|
logger.quiet("Deleted package: ${pkg.name}:${pkg.version}")
|
||
|
}
|
||
|
}
|
||
|
packagesFile.copyTo(packagesFile.resolveSibling(packagesFile.nameWithoutExtension + ".deleted.txt"))
|
||
|
packagesFile.delete()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class PackageInfo(
|
||
|
val name: String,
|
||
|
val version: String
|
||
|
)
|