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
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 |
|
) |