mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Moved IDE tasks in custom plugins
This commit is contained in:
+2
-170
@@ -15,10 +15,10 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.googlejavaformat.java.Formatter
|
||||
import com.google.googlejavaformat.java.JavaFormatterOptions
|
||||
import com.itsaky.androidide.Versions
|
||||
import com.itsaky.androidide.plugins.AndroidIDEPlugin
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
@@ -67,7 +67,6 @@ buildscript {
|
||||
dependencies {
|
||||
classpath classpaths.agp
|
||||
classpath classpaths.kotlin_gradle_plugin
|
||||
classpath classpaths.google_java_format
|
||||
classpath classpaths.oss_licenses
|
||||
classpath google.guava_jre
|
||||
}
|
||||
@@ -75,14 +74,7 @@ buildscript {
|
||||
|
||||
subprojects {
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
afterEvaluate {
|
||||
tasks.register ("checkTranslations", task -> {
|
||||
doLast {
|
||||
checkTranslations (project)
|
||||
}
|
||||
})
|
||||
}
|
||||
apply plugin: AndroidIDEPlugin
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -116,172 +108,12 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTranslations (Project project) {
|
||||
def php = new File ("/usr/bin/php")
|
||||
if (!php.exists ()) {
|
||||
project.logger.lifecycle ("'${php.absolutePath}' not found. Skipping translation check.")
|
||||
return
|
||||
}
|
||||
|
||||
def resDir = project.file ("src/main/res")
|
||||
def strings = new File (resDir, "values/strings.xml")
|
||||
def reportDir = new File (project.rootProject.buildDir, "translation-reports")
|
||||
reportDir.delete ()
|
||||
|
||||
if (!resDir.exists () || !strings.exists ()) {
|
||||
project.logger.info ("Default strings.xml file does not exist for project '${project.name}'")
|
||||
return
|
||||
}
|
||||
|
||||
def translationDirs = resDir.listFiles ((FileFilter) (file -> {
|
||||
return file.isDirectory () && file.getName ().startsWith ("values-")
|
||||
}))
|
||||
|
||||
for (def dir : translationDirs) {
|
||||
final var translation = new File (dir, "strings.xml")
|
||||
if (!translation.exists ()) {
|
||||
project.logger.info ("No translation file specifed for '${dir.name}'. Skipping..")
|
||||
return
|
||||
}
|
||||
|
||||
def out = new File (reportDir, "${project.path.replace (':', '/')}/${dir.name}.txt")
|
||||
if (!out.parentFile.exists ()) {
|
||||
out.parentFile.mkdirs ()
|
||||
}
|
||||
|
||||
if (out.exists ()) {
|
||||
out.delete ()
|
||||
}
|
||||
|
||||
out.createNewFile ()
|
||||
|
||||
def result = exec {
|
||||
ignoreExitValue true
|
||||
standardOutput new FileOutputStream (out)
|
||||
commandLine "${php.absolutePath}",
|
||||
"${project.rootProject.file (".tools/strings-check.php")}",
|
||||
"${strings.absolutePath}",
|
||||
"${translation.absolutePath}"
|
||||
}
|
||||
|
||||
if (result.getExitValue () == 0) {
|
||||
out.delete ()
|
||||
} else {
|
||||
project.logger.lifecycle ("Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean (type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
Collection<String> walkForSources (Path dir) {
|
||||
try {
|
||||
|
||||
if (!Files.exists (dir)) {
|
||||
return Collections.emptySet ()
|
||||
}
|
||||
|
||||
return Files.walk (dir)
|
||||
.filter (path -> !Files.isDirectory (path))
|
||||
.filter (path -> Files.isReadable (path) && Files.isWritable (path))
|
||||
.map (path -> path.toFile ())
|
||||
.map (file -> file.absolutePath)
|
||||
.filter (path -> path.endsWith (".java"))
|
||||
.filter (path -> !path.endsWith ("_template.java"))
|
||||
.collect (Collectors.toSet ())
|
||||
} catch (Throwable error) {
|
||||
getLogger ().error ("Could not walk directory for java sources: ${dir.toString ()}", error)
|
||||
return Collections.emptySet ()
|
||||
}
|
||||
}
|
||||
|
||||
boolean doJavaFormat (Formatter formatter, String path) {
|
||||
try {
|
||||
final def file = Paths.get (path)
|
||||
final def content = Files.readAllBytes (file)
|
||||
final def utf8Decoded = new String (content, StandardCharsets.UTF_8.name ())
|
||||
final def formatted = formatter.formatSource (utf8Decoded)
|
||||
if (utf8Decoded == formatted) {
|
||||
getLogger ().info ("{}: UP-TO-DATE", file)
|
||||
return true
|
||||
}
|
||||
|
||||
byte[] utf8Encoded = formatted.getBytes (StandardCharsets.UTF_8.name ())
|
||||
Files.write (file, utf8Encoded)
|
||||
println ("${path}: Formatted successfully!")
|
||||
return true
|
||||
} catch (Throwable th) {
|
||||
getLogger ().error ("Failed to format ${path}", th)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
task formatJavaSources () {
|
||||
doLast {
|
||||
def jarName = "google-java-format-1.15.0-all-deps"
|
||||
def jar = rootProject.file (".tools/${jarName}.jar")
|
||||
|
||||
if (!jar.exists ()) {
|
||||
getLogger ().info ("google-java-format JAR file not found. Skipping format task...")
|
||||
return
|
||||
}
|
||||
|
||||
boolean formattingChanges = false
|
||||
rootProject.subprojects.forEach (sub -> {
|
||||
def sources = walkForSources (sub.file ("src/main/java").toPath ())
|
||||
sources.addAll (walkForSources (sub.file ("src/test/java").toPath ()))
|
||||
|
||||
final def formatter = new Formatter (
|
||||
JavaFormatterOptions
|
||||
.builder ()
|
||||
.style (JavaFormatterOptions.Style.GOOGLE)
|
||||
.formatJavadoc (true)
|
||||
.build ()
|
||||
)
|
||||
|
||||
for (def path : sources) {
|
||||
if (doJavaFormat (formatter, path)) {
|
||||
formattingChanges = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!formattingChanges) {
|
||||
getLogger ().info ("No formatting changes.")
|
||||
return
|
||||
}
|
||||
|
||||
// ---------------- Stage Changes -------------------
|
||||
def out = new ByteArrayOutputStream ()
|
||||
def exit = rootProject.exec {
|
||||
ignoreExitValue true
|
||||
standardOutput out
|
||||
errorOutput standardOutput
|
||||
commandLine "git", "add", "."
|
||||
}
|
||||
|
||||
if (exit.exitValue != 0) {
|
||||
getLogger ().error ("Unable to stage changes. Process terminated with exit code ${exit.exitValue}")
|
||||
getLogger ().error (out.toString ())
|
||||
return
|
||||
}
|
||||
|
||||
// ----------------- Commit Changes --------------------
|
||||
out = new ByteArrayOutputStream ()
|
||||
exit = rootProject.exec {
|
||||
ignoreExitValue true
|
||||
standardOutput out
|
||||
errorOutput standardOutput
|
||||
commandLine "git", "commit", "-m", "[Gradle] Format java source code"
|
||||
}
|
||||
|
||||
if (exit.exitValue == 0) {
|
||||
getLogger ().info ("Changes committed successfully.")
|
||||
} else {
|
||||
getLogger ().error ("Failed to commit changes. Process terminated with exit code ${exit.exitValue}")
|
||||
getLogger ().error (out.toString ())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,13 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
google()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
}
|
||||
implementation(gradleApi())
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("com.google.googlejavaformat:google-java-format:1.15.0")
|
||||
}
|
||||
|
||||
@@ -25,19 +25,19 @@ package com.itsaky.androidide
|
||||
object Versions {
|
||||
|
||||
/** The compile SDK version. */
|
||||
val compileSdk = 32
|
||||
const val compileSdk = 32
|
||||
|
||||
/** The build tools version. */
|
||||
val buildTools = "31.0.0"
|
||||
const val buildTools = "31.0.0"
|
||||
|
||||
/** The minimum SDK version. */
|
||||
val minSdk = 26
|
||||
const val minSdk = 26
|
||||
|
||||
/** The target SDK version. */
|
||||
val targetSdk = 28
|
||||
const val targetSdk = 28
|
||||
|
||||
/** The version code. */
|
||||
val versionCode = 212
|
||||
const val versionCode = 212
|
||||
|
||||
/**
|
||||
* The version name for the IDE. When in CI build, includes the [releaseVersionName], branch name
|
||||
@@ -53,5 +53,5 @@ object Versions {
|
||||
}
|
||||
|
||||
/** The release version name. */
|
||||
val releaseVersionName = "2.1.2-beta"
|
||||
const val releaseVersionName = "2.1.2-beta"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.plugins
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* Manages plugins applied on the IDE's project modules.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class AndroidIDEPlugin : Plugin<Project> {
|
||||
|
||||
companion object {
|
||||
private const val APP_PLUGIN = "com.android.application"
|
||||
private const val LIB_PLUGIN = "com.android.library"
|
||||
}
|
||||
|
||||
override fun apply(target: Project) {
|
||||
target.afterEvaluate {
|
||||
if (target.plugins.hasPlugin(APP_PLUGIN) || target.plugins.hasPlugin(LIB_PLUGIN)) {
|
||||
|
||||
// apply the translation checker plugin
|
||||
target.apply { plugin(TranslationCheckerPlugin::class.java) }
|
||||
}
|
||||
|
||||
// apply the Google Java Format plugin
|
||||
target.apply { plugin(GoogleJavaFormatPlugin::class.java) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.plugins
|
||||
|
||||
import com.google.googlejavaformat.java.Formatter
|
||||
import com.google.googlejavaformat.java.JavaFormatterOptions
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.Collections
|
||||
import java.util.stream.Collectors
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
|
||||
/**
|
||||
* Plugin for formatting the Java source files using google-java-format.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class GoogleJavaFormatPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(target: Project) {
|
||||
target.tasks.register("formatJavaSources") {
|
||||
doLast {
|
||||
val jarName = "google-java-format-1.15.0-all-deps"
|
||||
val jar = target.rootProject.file(".tools/${jarName}.jar")
|
||||
|
||||
if (!jar.exists()) {
|
||||
logger.info("google-java-format JAR file not found. Skipping format task...")
|
||||
return@doLast
|
||||
}
|
||||
|
||||
var formattingChanges = false
|
||||
target.rootProject.subprojects.forEach { sub ->
|
||||
val sources = walkForSources(sub.file("src/main/java").toPath(), logger).toMutableSet()
|
||||
sources.addAll(walkForSources(sub.file("src/test/java").toPath(), logger))
|
||||
|
||||
val formatter =
|
||||
Formatter(
|
||||
JavaFormatterOptions.builder()
|
||||
.style(JavaFormatterOptions.Style.GOOGLE)
|
||||
.formatJavadoc(true)
|
||||
.build()
|
||||
)
|
||||
|
||||
for (path in sources) {
|
||||
if (doJavaFormat(formatter, path, logger)) {
|
||||
formattingChanges = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!formattingChanges) {
|
||||
logger.info("No formatting changes.")
|
||||
return@doLast
|
||||
}
|
||||
|
||||
// ---------------- Stage Changes -------------------
|
||||
var out = ByteArrayOutputStream()
|
||||
var exit =
|
||||
target.rootProject.exec {
|
||||
isIgnoreExitValue = true
|
||||
standardOutput = out
|
||||
errorOutput = standardOutput
|
||||
commandLine = listOf("git", "add", ".")
|
||||
}
|
||||
|
||||
if (exit.exitValue != 0) {
|
||||
logger.error(
|
||||
"Unable to stage changes. Process terminated with exit code ${exit.exitValue}"
|
||||
)
|
||||
logger.error(out.toString())
|
||||
return@doLast
|
||||
}
|
||||
|
||||
// ----------------- Commit Changes --------------------
|
||||
out = ByteArrayOutputStream()
|
||||
exit =
|
||||
target.rootProject.exec {
|
||||
isIgnoreExitValue = true
|
||||
standardOutput = out
|
||||
errorOutput = standardOutput
|
||||
commandLine = listOf("git", "commit", "-m", "[Gradle] Format java source code")
|
||||
}
|
||||
|
||||
if (exit.exitValue == 0) {
|
||||
logger.info("Changes committed successfully.")
|
||||
} else {
|
||||
logger.error(
|
||||
"Failed to commit changes. Process terminated with exit code ${exit.exitValue}"
|
||||
)
|
||||
logger.error(out.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doJavaFormat(formatter: Formatter, path: String, logger: Logger): Boolean {
|
||||
try {
|
||||
val file = Paths.get(path)
|
||||
val content = Files.readAllBytes(file)
|
||||
val utf8Decoded = String(content, StandardCharsets.UTF_8)
|
||||
val formatted = formatter.formatSource(utf8Decoded)
|
||||
if (utf8Decoded == formatted) {
|
||||
logger.info("{}: UP-TO-DATE", file)
|
||||
return true
|
||||
}
|
||||
|
||||
val utf8Encoded = formatted.toByteArray(StandardCharsets.UTF_8)
|
||||
Files.write(file, utf8Encoded)
|
||||
println("${path}: Formatted successfully!")
|
||||
return true
|
||||
} catch (th: Throwable) {
|
||||
logger.error("Failed to format $path", th)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun walkForSources(dir: Path, logger: Logger): Collection<String> {
|
||||
try {
|
||||
if (!Files.exists(dir)) {
|
||||
return Collections.emptySet()
|
||||
}
|
||||
|
||||
return Files.walk(dir)
|
||||
.filter { !Files.isDirectory(it) && Files.isReadable(it) && Files.isWritable(it) }
|
||||
.map { it.toFile().absolutePath }
|
||||
.filter { it.endsWith(".java") && !it.endsWith("_template.java") }
|
||||
.collect(Collectors.toSet())
|
||||
} catch (error: Throwable) {
|
||||
logger.error("Could not walk directory for java sources: ${dir.toString ()}", error)
|
||||
return Collections.emptySet()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.plugins
|
||||
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.process.ExecResult
|
||||
|
||||
/**
|
||||
* Plugin for generating a translation report for a module.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class TranslationCheckerPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(target: Project) {
|
||||
target.afterEvaluate {
|
||||
tasks.register("checkTranslations") { doLast { checkTranslations(target) } }
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkTranslations(project: Project) {
|
||||
val php = File("/usr/bin/php")
|
||||
if (!php.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
val resDir = project.file("src/main/res")
|
||||
val strings = File(resDir, "values/strings.xml")
|
||||
val reportDir = File(project.rootProject.buildDir, "translation-reports")
|
||||
reportDir.delete()
|
||||
|
||||
if (!resDir.exists() || !strings.exists()) {
|
||||
project.logger.info("Default strings.xml file does not exist for project '${project.name}'")
|
||||
return
|
||||
}
|
||||
|
||||
val translationDirs =
|
||||
resDir.listFiles { file -> file.isDirectory && file.name.startsWith("values-") }
|
||||
?: emptyArray()
|
||||
|
||||
for (dir in translationDirs) {
|
||||
val translation = File(dir, "strings.xml")
|
||||
if (!translation.exists()) {
|
||||
project.logger.info("No translation file specifed for '${dir.name}'. Skipping..")
|
||||
return
|
||||
}
|
||||
|
||||
val out = File(reportDir, "${project.path.replace (':', '/')}/${dir.name}.txt")
|
||||
if (!out.parentFile.exists()) {
|
||||
out.parentFile.mkdirs()
|
||||
}
|
||||
|
||||
if (out.exists()) {
|
||||
out.delete()
|
||||
}
|
||||
|
||||
out.createNewFile()
|
||||
|
||||
val result = doCheckTranslations(project, out, php, strings, translation)
|
||||
|
||||
if (result.exitValue == 0) {
|
||||
out.delete()
|
||||
} else {
|
||||
project.logger.lifecycle(
|
||||
"Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCheckTranslations(
|
||||
project: Project,
|
||||
out: File,
|
||||
php: File,
|
||||
strings: File,
|
||||
translation: File
|
||||
): ExecResult {
|
||||
val result =
|
||||
project.rootProject.exec {
|
||||
isIgnoreExitValue = true
|
||||
standardOutput = FileOutputStream(out)
|
||||
commandLine =
|
||||
listOf(
|
||||
php.absolutePath,
|
||||
"${project.rootProject.file(".tools/strings-check.php")}",
|
||||
strings.absolutePath,
|
||||
translation.absolutePath
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user