From fe3ca3f7d82436f2eaf1e6212ea278466dc85402 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 5 Jun 2022 03:25:25 +0530 Subject: automation-plugins: convert to full plugins --- build-logic/automation-plugins/build.gradle.kts | 8 +- ...hub.android-password-store.git-hooks.gradle.kts | 12 -- .../src/main/kotlin/crowdin/CrowdinExtension.kt | 20 --- .../src/main/kotlin/crowdin/CrowdinPlugin.kt | 140 --------------------- .../dev/msfjarvis/aps/gradle/GitHooksPlugin.kt | 18 +++ .../aps/gradle/crowdin/CrowdinExtension.kt | 20 +++ .../msfjarvis/aps/gradle/crowdin/CrowdinPlugin.kt | 140 +++++++++++++++++++++ .../dev/msfjarvis/aps/gradle/psl/PSLUpdateTask.kt | 46 +++++++ .../aps/gradle/psl/PublicSuffixListPlugin.kt | 98 +++++++++++++++ .../dev/msfjarvis/aps/gradle/tasks/GitHooks.kt | 46 +++++++ .../src/main/kotlin/psl/PSLUpdateTask.kt | 46 ------- .../src/main/kotlin/psl/PublicSuffixListPlugin.kt | 98 --------------- .../src/main/kotlin/tasks/GitHooks.kt | 46 ------- 13 files changed, 374 insertions(+), 364 deletions(-) delete mode 100644 build-logic/automation-plugins/src/main/kotlin/com.github.android-password-store.git-hooks.gradle.kts delete mode 100644 build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinExtension.kt delete mode 100644 build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinPlugin.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/GitHooksPlugin.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinExtension.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinPlugin.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PSLUpdateTask.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PublicSuffixListPlugin.kt create mode 100644 build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/tasks/GitHooks.kt delete mode 100644 build-logic/automation-plugins/src/main/kotlin/psl/PSLUpdateTask.kt delete mode 100644 build-logic/automation-plugins/src/main/kotlin/psl/PublicSuffixListPlugin.kt delete mode 100644 build-logic/automation-plugins/src/main/kotlin/tasks/GitHooks.kt (limited to 'build-logic') diff --git a/build-logic/automation-plugins/build.gradle.kts b/build-logic/automation-plugins/build.gradle.kts index 83b89079..80b53e10 100644 --- a/build-logic/automation-plugins/build.gradle.kts +++ b/build-logic/automation-plugins/build.gradle.kts @@ -28,11 +28,15 @@ gradlePlugin { plugins { register("crowdin") { id = "com.github.android-password-store.crowdin-plugin" - implementationClass = "crowdin.CrowdinDownloadPlugin" + implementationClass = "dev.msfjarvis.aps.gradle.crowdin.CrowdinDownloadPlugin" } register("psl") { id = "com.github.android-password-store.psl-plugin" - implementationClass = "psl.PublicSuffixListPlugin" + implementationClass = "dev.msfjarvis.aps.gradle.psl.PublicSuffixListPlugin" + } + register("git-hooks") { + id = "com.github.android-password-store.git-hooks" + implementationClass = "dev.msfjarvis.aps.gradle.GitHooksPlugin" } } } diff --git a/build-logic/automation-plugins/src/main/kotlin/com.github.android-password-store.git-hooks.gradle.kts b/build-logic/automation-plugins/src/main/kotlin/com.github.android-password-store.git-hooks.gradle.kts deleted file mode 100644 index 6f661a6a..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/com.github.android-password-store.git-hooks.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -import tasks.GitHooks - -tasks.register("installGitHooks") { - val projectDirectory = layout.projectDirectory - hookScript.set(projectDirectory.file("scripts/pre-push-hook.sh").asFile.readText()) - hookOutput.set(projectDirectory.file(".git/hooks/pre-push").asFile) -} diff --git a/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinExtension.kt b/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinExtension.kt deleted file mode 100644 index 761267b5..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinExtension.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package crowdin - -/** Extension for configuring [CrowdinDownloadPlugin] */ -interface CrowdinExtension { - - /** Configure the project name on Crowdin */ - var projectName: String - - /** - * Don't delete downloaded and extracted translation archives from build directory. - * - * Useful for debugging. - */ - var skipCleanup: Boolean -} diff --git a/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinPlugin.kt b/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinPlugin.kt deleted file mode 100644 index e147b42c..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/crowdin/CrowdinPlugin.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package crowdin - -import de.undercouch.gradle.tasks.download.Download -import java.io.File -import java.util.concurrent.TimeUnit -import javax.xml.parsers.DocumentBuilderFactory -import okhttp3.OkHttpClient -import okhttp3.Request -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.Copy -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.register -import org.w3c.dom.Document - -private const val EXCEPTION_MESSAGE = - """Applying `crowdin-plugin` requires a projectName to be configured via the "crowdin" extension.""" -private const val CROWDIN_BUILD_API_URL = - "https://api.crowdin.com/api/project/%s/export?login=%s&account-key=%s" - -@Suppress("Unused") -class CrowdinDownloadPlugin : Plugin { - - override fun apply(project: Project) { - with(project) { - val buildDirectory = layout.buildDirectory.asFile.get() - val extension = extensions.create("crowdin") - afterEvaluate { - val projectName = extension.projectName - if (projectName.isEmpty()) { - throw GradleException(EXCEPTION_MESSAGE) - } - val buildOnApi = - tasks.register("buildOnApi") { - doLast { - val login = providers.environmentVariable("CROWDIN_LOGIN") - val key = providers.environmentVariable("CROWDIN_PROJECT_KEY") - if (!login.isPresent) { - throw GradleException("CROWDIN_LOGIN environment variable must be set") - } - if (!key.isPresent) { - throw GradleException("CROWDIN_PROJECT_KEY environment variable must be set") - } - val client = - OkHttpClient.Builder() - .connectTimeout(5, TimeUnit.MINUTES) - .writeTimeout(5, TimeUnit.MINUTES) - .readTimeout(5, TimeUnit.MINUTES) - .callTimeout(10, TimeUnit.MINUTES) - .build() - val url = CROWDIN_BUILD_API_URL.format(projectName, login.get(), key.get()) - val request = Request.Builder().url(url).get().build() - client.newCall(request).execute().close() - } - } - val downloadCrowdin = - tasks.register("downloadCrowdin") { - dependsOn(buildOnApi) - src("https://crowdin.com/backend/download/project/$projectName.zip") - dest("$buildDirectory/translations.zip") - overwrite(true) - } - val extractCrowdin = - tasks.register("extractCrowdin") { - dependsOn(downloadCrowdin) - doFirst { File(buildDir, "translations").deleteRecursively() } - from(zipTree("$buildDirectory/translations.zip")) - into("$buildDirectory/translations") - } - val extractStrings = - tasks.register("extractStrings") { - dependsOn(extractCrowdin) - from("$buildDirectory/translations/") - into("${projectDir}/src/") - setFinalizedBy(setOf("removeIncompleteStrings")) - } - tasks.register("removeIncompleteStrings") { - doLast { - val sourceSets = arrayOf("main", "nonFree") - for (sourceSet in sourceSets) { - val fileTreeWalk = projectDir.resolve("src/$sourceSet").walkTopDown() - val valuesDirectories = - fileTreeWalk.filter { it.isDirectory }.filter { it.name.startsWith("values") } - val stringFiles = fileTreeWalk.filter { it.name == "strings.xml" } - val sourceFile = - stringFiles.firstOrNull { it.path.endsWith("values/strings.xml") } - ?: throw GradleException("No root strings.xml found in '$sourceSet' sourceSet") - val sourceDoc = parseDocument(sourceFile) - val baselineStringCount = countStrings(sourceDoc) - val threshold = 0.80 * baselineStringCount - stringFiles.forEach { file -> - if (file != sourceFile) { - val doc = parseDocument(file) - val stringCount = countStrings(doc) - if (stringCount < threshold) { - file.delete() - } - } - } - valuesDirectories.forEach { dir -> - if (dir.listFiles().isNullOrEmpty()) { - dir.delete() - } - } - } - } - } - tasks.register("crowdin") { - dependsOn(extractStrings) - if (!extension.skipCleanup) { - doLast { - File("$buildDirectory/translations").deleteRecursively() - File("$buildDirectory/nonFree-translations").deleteRecursively() - File("$buildDirectory/translations.zip").delete() - } - } - } - } - } - } - - private fun parseDocument(file: File): Document { - val dbFactory = DocumentBuilderFactory.newInstance() - val documentBuilder = dbFactory.newDocumentBuilder() - return documentBuilder.parse(file) - } - - private fun countStrings(document: Document): Int { - // Normalization is beneficial for us - // https://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work - document.documentElement.normalize() - return document.getElementsByTagName("string").length - } -} diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/GitHooksPlugin.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/GitHooksPlugin.kt new file mode 100644 index 00000000..3ddb656b --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/GitHooksPlugin.kt @@ -0,0 +1,18 @@ +package dev.msfjarvis.aps.gradle + +import dev.msfjarvis.aps.gradle.tasks.GitHooks +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.register + +@Suppress("Unused") +class GitHooksPlugin : Plugin { + + override fun apply(project: Project) { + project.tasks.register("installGitHooks") { + val projectDirectory = project.layout.projectDirectory + hookScript.set(projectDirectory.file("scripts/pre-push-hook.sh").asFile.readText()) + hookOutput.set(projectDirectory.file(".git/hooks/pre-push").asFile) + } + } +} diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinExtension.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinExtension.kt new file mode 100644 index 00000000..7d32dc01 --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinExtension.kt @@ -0,0 +1,20 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.gradle.crowdin + +/** Extension for configuring [CrowdinDownloadPlugin] */ +interface CrowdinExtension { + + /** Configure the project name on Crowdin */ + var projectName: String + + /** + * Don't delete downloaded and extracted translation archives from build directory. + * + * Useful for debugging. + */ + var skipCleanup: Boolean +} diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinPlugin.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinPlugin.kt new file mode 100644 index 00000000..62d8e32d --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/crowdin/CrowdinPlugin.kt @@ -0,0 +1,140 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.gradle.crowdin + +import de.undercouch.gradle.tasks.download.Download +import java.io.File +import java.util.concurrent.TimeUnit +import javax.xml.parsers.DocumentBuilderFactory +import okhttp3.OkHttpClient +import okhttp3.Request +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.Copy +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.register +import org.w3c.dom.Document + +private const val EXCEPTION_MESSAGE = + """Applying `crowdin-plugin` requires a projectName to be configured via the "crowdin" extension.""" +private const val CROWDIN_BUILD_API_URL = + "https://api.crowdin.com/api/project/%s/export?login=%s&account-key=%s" + +@Suppress("Unused") +class CrowdinDownloadPlugin : Plugin { + + override fun apply(project: Project) { + with(project) { + val buildDirectory = layout.buildDirectory.asFile.get() + val extension = extensions.create("crowdin") + afterEvaluate { + val projectName = extension.projectName + if (projectName.isEmpty()) { + throw GradleException(EXCEPTION_MESSAGE) + } + val buildOnApi = + tasks.register("buildOnApi") { + doLast { + val login = providers.environmentVariable("CROWDIN_LOGIN") + val key = providers.environmentVariable("CROWDIN_PROJECT_KEY") + if (!login.isPresent) { + throw GradleException("CROWDIN_LOGIN environment variable must be set") + } + if (!key.isPresent) { + throw GradleException("CROWDIN_PROJECT_KEY environment variable must be set") + } + val client = + OkHttpClient.Builder() + .connectTimeout(5, TimeUnit.MINUTES) + .writeTimeout(5, TimeUnit.MINUTES) + .readTimeout(5, TimeUnit.MINUTES) + .callTimeout(10, TimeUnit.MINUTES) + .build() + val url = CROWDIN_BUILD_API_URL.format(projectName, login.get(), key.get()) + val request = Request.Builder().url(url).get().build() + client.newCall(request).execute().close() + } + } + val downloadCrowdin = + tasks.register("downloadCrowdin") { + dependsOn(buildOnApi) + src("https://crowdin.com/backend/download/project/$projectName.zip") + dest("$buildDirectory/translations.zip") + overwrite(true) + } + val extractCrowdin = + tasks.register("extractCrowdin") { + dependsOn(downloadCrowdin) + doFirst { File(buildDir, "translations").deleteRecursively() } + from(zipTree("$buildDirectory/translations.zip")) + into("$buildDirectory/translations") + } + val extractStrings = + tasks.register("extractStrings") { + dependsOn(extractCrowdin) + from("$buildDirectory/translations/") + into("${projectDir}/src/") + setFinalizedBy(setOf("removeIncompleteStrings")) + } + tasks.register("removeIncompleteStrings") { + doLast { + val sourceSets = arrayOf("main", "nonFree") + for (sourceSet in sourceSets) { + val fileTreeWalk = projectDir.resolve("src/$sourceSet").walkTopDown() + val valuesDirectories = + fileTreeWalk.filter { it.isDirectory }.filter { it.name.startsWith("values") } + val stringFiles = fileTreeWalk.filter { it.name == "strings.xml" } + val sourceFile = + stringFiles.firstOrNull { it.path.endsWith("values/strings.xml") } + ?: throw GradleException("No root strings.xml found in '$sourceSet' sourceSet") + val sourceDoc = parseDocument(sourceFile) + val baselineStringCount = countStrings(sourceDoc) + val threshold = 0.80 * baselineStringCount + stringFiles.forEach { file -> + if (file != sourceFile) { + val doc = parseDocument(file) + val stringCount = countStrings(doc) + if (stringCount < threshold) { + file.delete() + } + } + } + valuesDirectories.forEach { dir -> + if (dir.listFiles().isNullOrEmpty()) { + dir.delete() + } + } + } + } + } + tasks.register("crowdin") { + dependsOn(extractStrings) + if (!extension.skipCleanup) { + doLast { + File("$buildDirectory/translations").deleteRecursively() + File("$buildDirectory/nonFree-translations").deleteRecursively() + File("$buildDirectory/translations.zip").delete() + } + } + } + } + } + } + + private fun parseDocument(file: File): Document { + val dbFactory = DocumentBuilderFactory.newInstance() + val documentBuilder = dbFactory.newDocumentBuilder() + return documentBuilder.parse(file) + } + + private fun countStrings(document: Document): Int { + // Normalization is beneficial for us + // https://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work + document.documentElement.normalize() + return document.getElementsByTagName("string").length + } +} diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PSLUpdateTask.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PSLUpdateTask.kt new file mode 100644 index 00000000..7e137b2f --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PSLUpdateTask.kt @@ -0,0 +1,46 @@ +/* + * Copyright © 2014-2022 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.gradle.psl + +import okio.buffer +import okio.sink +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +@CacheableTask +abstract class PSLUpdateTask : DefaultTask() { + @get:Input abstract val pslData: Property + @get:OutputFile abstract val outputFile: RegularFileProperty + + @TaskAction + fun updatePSL() { + writeListToDisk(outputFile.get(), pslData.get()) + } + + private fun writeListToDisk(destination: RegularFile, data: PublicSuffixListData) { + val fileSink = destination.asFile.sink() + + fileSink.buffer().use { sink -> + sink.writeInt(data.totalRuleBytes) + + for (domain in data.sortedRules) { + sink.write(domain).writeByte('\n'.toInt()) + } + + sink.writeInt(data.totalExceptionRuleBytes) + + for (domain in data.sortedExceptionRules) { + sink.write(domain).writeByte('\n'.toInt()) + } + } + } +} diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PublicSuffixListPlugin.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PublicSuffixListPlugin.kt new file mode 100644 index 00000000..775ec722 --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/psl/PublicSuffixListPlugin.kt @@ -0,0 +1,98 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package dev.msfjarvis.aps.gradle.psl + +import java.io.Serializable +import java.util.TreeSet +import okhttp3.OkHttpClient +import okhttp3.Request +import okio.ByteString +import okio.ByteString.Companion.encodeUtf8 +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.register + +/** + * Gradle plugin to update the public suffix list used by the `lib-publicsuffixlist` component. + * + * Base on PublicSuffixListGenerator from OkHttp: + * https://github.com/square/okhttp/blob/master/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.java + */ +@Suppress("Unused") +class PublicSuffixListPlugin : Plugin { + override fun apply(project: Project) { + project.tasks.register("updatePSL") { + val list = fetchPublicSuffixList() + pslData.set(list) + outputFile.set(project.layout.projectDirectory.file("src/main/assets/publicsuffixes")) + } + } + + private fun fetchPublicSuffixList(): PublicSuffixListData { + val client = OkHttpClient.Builder().build() + + val request = + Request.Builder().url("https://publicsuffix.org/list/public_suffix_list.dat").build() + + client.newCall(request).execute().use { response -> + val source = requireNotNull(response.body).source() + + val data = PublicSuffixListData() + + while (!source.exhausted()) { + val line = source.readUtf8LineStrict() + + if (line.trim { it <= ' ' }.isEmpty() || line.startsWith("//")) { + continue + } + + if (line.contains(WILDCARD_CHAR)) { + assertWildcardRule(line) + } + + var rule = line.encodeUtf8() + + if (rule.startsWith(EXCEPTION_RULE_MARKER)) { + rule = rule.substring(1) + // We use '\n' for end of value. + data.totalExceptionRuleBytes += rule.size + 1 + data.sortedExceptionRules.add(rule) + } else { + data.totalRuleBytes += rule.size + 1 // We use '\n' for end of value. + data.sortedRules.add(rule) + } + } + + return data + } + } + + @Suppress("TooGenericExceptionThrown", "ThrowsCount") + private fun assertWildcardRule(rule: String) { + if (rule.indexOf(WILDCARD_CHAR) != 0) { + throw RuntimeException("Wildcard is not not in leftmost position") + } + + if (rule.indexOf(WILDCARD_CHAR, 1) != -1) { + throw RuntimeException("Rule contains multiple wildcards") + } + + if (rule.length == 1) { + throw RuntimeException("Rule wildcards the first level") + } + } + + companion object { + private const val WILDCARD_CHAR = "*" + private val EXCEPTION_RULE_MARKER = "!".encodeUtf8() + } +} + +data class PublicSuffixListData( + var totalRuleBytes: Int = 0, + var totalExceptionRuleBytes: Int = 0, + val sortedRules: TreeSet = TreeSet(), + val sortedExceptionRules: TreeSet = TreeSet() +) : Serializable diff --git a/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/tasks/GitHooks.kt b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/tasks/GitHooks.kt new file mode 100644 index 00000000..1eb8540f --- /dev/null +++ b/build-logic/automation-plugins/src/main/kotlin/dev/msfjarvis/aps/gradle/tasks/GitHooks.kt @@ -0,0 +1,46 @@ +/* + * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.gradle.tasks + +import java.io.File +import java.nio.file.Files +import java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE +import java.nio.file.attribute.PosixFilePermission.GROUP_READ +import java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE +import java.nio.file.attribute.PosixFilePermission.OTHERS_READ +import java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE +import java.nio.file.attribute.PosixFilePermission.OWNER_READ +import java.nio.file.attribute.PosixFilePermission.OWNER_WRITE +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +@CacheableTask +abstract class GitHooks : DefaultTask() { + @get:Input abstract val hookScript: Property + + @get:OutputFile abstract val hookOutput: Property + + @TaskAction + fun install() { + hookOutput.get().writeText(hookScript.get()) + Files.setPosixFilePermissions( + hookOutput.get().toPath(), + setOf( + OWNER_READ, + OWNER_WRITE, + OWNER_EXECUTE, + GROUP_READ, + GROUP_EXECUTE, + OTHERS_READ, + OTHERS_EXECUTE, + ) + ) + } +} diff --git a/build-logic/automation-plugins/src/main/kotlin/psl/PSLUpdateTask.kt b/build-logic/automation-plugins/src/main/kotlin/psl/PSLUpdateTask.kt deleted file mode 100644 index e8fdc498..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/psl/PSLUpdateTask.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2014-2022 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package psl - -import okio.buffer -import okio.sink -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -@CacheableTask -abstract class PSLUpdateTask : DefaultTask() { - @get:Input abstract val pslData: Property - @get:OutputFile abstract val outputFile: RegularFileProperty - - @TaskAction - fun updatePSL() { - writeListToDisk(outputFile.get(), pslData.get()) - } - - private fun writeListToDisk(destination: RegularFile, data: PublicSuffixListData) { - val fileSink = destination.asFile.sink() - - fileSink.buffer().use { sink -> - sink.writeInt(data.totalRuleBytes) - - for (domain in data.sortedRules) { - sink.write(domain).writeByte('\n'.toInt()) - } - - sink.writeInt(data.totalExceptionRuleBytes) - - for (domain in data.sortedExceptionRules) { - sink.write(domain).writeByte('\n'.toInt()) - } - } - } -} diff --git a/build-logic/automation-plugins/src/main/kotlin/psl/PublicSuffixListPlugin.kt b/build-logic/automation-plugins/src/main/kotlin/psl/PublicSuffixListPlugin.kt deleted file mode 100644 index 9d4c3f63..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/psl/PublicSuffixListPlugin.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package psl - -import java.io.Serializable -import java.util.TreeSet -import okhttp3.OkHttpClient -import okhttp3.Request -import okio.ByteString -import okio.ByteString.Companion.encodeUtf8 -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.kotlin.dsl.register - -/** - * Gradle plugin to update the public suffix list used by the `lib-publicsuffixlist` component. - * - * Base on PublicSuffixListGenerator from OkHttp: - * https://github.com/square/okhttp/blob/master/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.java - */ -@Suppress("Unused") -class PublicSuffixListPlugin : Plugin { - override fun apply(project: Project) { - project.tasks.register("updatePSL") { - val list = fetchPublicSuffixList() - pslData.set(list) - outputFile.set(project.layout.projectDirectory.file("src/main/assets/publicsuffixes")) - } - } - - private fun fetchPublicSuffixList(): PublicSuffixListData { - val client = OkHttpClient.Builder().build() - - val request = - Request.Builder().url("https://publicsuffix.org/list/public_suffix_list.dat").build() - - client.newCall(request).execute().use { response -> - val source = requireNotNull(response.body).source() - - val data = PublicSuffixListData() - - while (!source.exhausted()) { - val line = source.readUtf8LineStrict() - - if (line.trim { it <= ' ' }.isEmpty() || line.startsWith("//")) { - continue - } - - if (line.contains(WILDCARD_CHAR)) { - assertWildcardRule(line) - } - - var rule = line.encodeUtf8() - - if (rule.startsWith(EXCEPTION_RULE_MARKER)) { - rule = rule.substring(1) - // We use '\n' for end of value. - data.totalExceptionRuleBytes += rule.size + 1 - data.sortedExceptionRules.add(rule) - } else { - data.totalRuleBytes += rule.size + 1 // We use '\n' for end of value. - data.sortedRules.add(rule) - } - } - - return data - } - } - - @Suppress("TooGenericExceptionThrown", "ThrowsCount") - private fun assertWildcardRule(rule: String) { - if (rule.indexOf(WILDCARD_CHAR) != 0) { - throw RuntimeException("Wildcard is not not in leftmost position") - } - - if (rule.indexOf(WILDCARD_CHAR, 1) != -1) { - throw RuntimeException("Rule contains multiple wildcards") - } - - if (rule.length == 1) { - throw RuntimeException("Rule wildcards the first level") - } - } - - companion object { - private const val WILDCARD_CHAR = "*" - private val EXCEPTION_RULE_MARKER = "!".encodeUtf8() - } -} - -data class PublicSuffixListData( - var totalRuleBytes: Int = 0, - var totalExceptionRuleBytes: Int = 0, - val sortedRules: TreeSet = TreeSet(), - val sortedExceptionRules: TreeSet = TreeSet() -) : Serializable diff --git a/build-logic/automation-plugins/src/main/kotlin/tasks/GitHooks.kt b/build-logic/automation-plugins/src/main/kotlin/tasks/GitHooks.kt deleted file mode 100644 index ec045227..00000000 --- a/build-logic/automation-plugins/src/main/kotlin/tasks/GitHooks.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package tasks - -import java.io.File -import java.nio.file.Files -import java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE -import java.nio.file.attribute.PosixFilePermission.GROUP_READ -import java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE -import java.nio.file.attribute.PosixFilePermission.OTHERS_READ -import java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE -import java.nio.file.attribute.PosixFilePermission.OWNER_READ -import java.nio.file.attribute.PosixFilePermission.OWNER_WRITE -import org.gradle.api.DefaultTask -import org.gradle.api.provider.Property -import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -@CacheableTask -abstract class GitHooks : DefaultTask() { - @get:Input abstract val hookScript: Property - - @get:OutputFile abstract val hookOutput: Property - - @TaskAction - fun install() { - hookOutput.get().writeText(hookScript.get()) - Files.setPosixFilePermissions( - hookOutput.get().toPath(), - setOf( - OWNER_READ, - OWNER_WRITE, - OWNER_EXECUTE, - GROUP_READ, - GROUP_EXECUTE, - OTHERS_READ, - OTHERS_EXECUTE, - ) - ) - } -} -- cgit v1.2.3