提交 6a548dda 编写于 作者: S superq_sky

Added checking.

上级 5caf9bac
GROUP_ID=com.didi.virtualapk
ARTIFACT_ID=gradle
VERSION=0.9.8-dev
VERSION=0.9.8.1-dev
......@@ -9,6 +9,7 @@ import com.android.build.gradle.internal.variant.VariantFactory
import com.android.builder.core.VariantConfiguration
import com.android.builder.core.VariantType
import com.didi.virtualapk.tasks.AssemblePlugin
import com.didi.virtualapk.utils.Log
import com.didi.virtualapk.utils.Reflect
import org.gradle.api.Action
import org.gradle.api.Plugin
......@@ -56,7 +57,7 @@ public abstract class BasePlugin implements Plugin<Project> {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ('preVariantWork' == method.name) {
checkVariantFactoryInvoked = true
println "Evaluating VirtualApk's configurations..."
Log.i 'Plugin', "Evaluating VirtualApk's configurations..."
boolean isBuildingPlugin = evaluateBuildingPlugin(appPlugin, project)
beforeCreateAndroidTasks(isBuildingPlugin)
}
......@@ -123,7 +124,7 @@ public abstract class BasePlugin implements Plugin<Project> {
}
// pluginTasks.each {
// println "pluginTask: ${it}"
// Log.i 'Plugin', "pluginTask: ${it}"
// }
boolean isBuildingPlugin = false
......@@ -131,7 +132,7 @@ public abstract class BasePlugin implements Plugin<Project> {
targetTasks.every {
String taskName = nameMatcher.find(it, pluginTasks)
if (taskName != null) {
// println "Found task name '${taskName}' by given name '${it}'"
// Log.i 'Plugin', "Found task name '${taskName}' by given name '${it}'"
isBuildingPlugin = true
return false
}
......
......@@ -3,6 +3,7 @@ package com.didi.virtualapk
import com.android.build.gradle.internal.scope.VariantScope
import com.didi.virtualapk.collector.dependence.AarDependenceInfo
import com.didi.virtualapk.collector.dependence.DependenceInfo
import com.didi.virtualapk.utils.CheckList
/**
* VirtualApk extension for plugin projects.
......@@ -38,6 +39,8 @@ public class VAExtention {
/** File of split R.java */
File splitRJavaFile
final CheckList checkList = new CheckList()
public File getBuildDir(VariantScope scope) {
return new File(scope.getGlobalScope().getIntermediatesDir(),
"virtualapk/" + scope.getVariantConfiguration().getDirName())
......
......@@ -11,6 +11,7 @@ import com.didi.virtualapk.hooker.ProguardHooker
import com.didi.virtualapk.hooker.TaskHookerManager
import com.didi.virtualapk.transform.StripClassAndResTransform
import com.didi.virtualapk.utils.FileBinaryCategory
import com.didi.virtualapk.utils.Log
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
import org.gradle.internal.reflect.Instantiator
......@@ -41,6 +42,8 @@ class VAPlugin extends BasePlugin {
*/
private TaskHookerManager taskHookerManager
private StripClassAndResTransform stripClassAndResTransform
@Inject
public VAPlugin(Instantiator instantiator, ToolingModelBuilderRegistry registry) {
super(instantiator, registry)
......@@ -50,10 +53,11 @@ class VAPlugin extends BasePlugin {
protected void beforeCreateAndroidTasks(boolean isBuildingPlugin) {
this.isBuildingPlugin = isBuildingPlugin
if (!isBuildingPlugin) {
println "Skipped all VirtualApk's configurations!"
Log.i 'Plugin', "Skipped all VirtualApk's configurations!"
return
}
android.registerTransform(new StripClassAndResTransform(project))
stripClassAndResTransform = new StripClassAndResTransform(project)
android.registerTransform(stripClassAndResTransform)
android.defaultConfig.buildConfigField("int", "PACKAGE_ID", "0x" + Integer.toHexString(virtualApk.packageId))
}
......@@ -81,6 +85,7 @@ class VAPlugin extends BasePlugin {
return
}
stripClassAndResTransform.onProjectAfterEvaluate()
taskHookerManager = new VATaskHookerManager(project, instantiator)
taskHookerManager.registerTaskHookers()
......
......@@ -2,6 +2,7 @@ package com.didi.virtualapk.hooker
import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.internal.pipeline.TransformTask
import com.didi.virtualapk.utils.Log
import org.apache.commons.io.FilenameUtils
import org.gradle.api.Project
......@@ -18,7 +19,7 @@ class DxTaskHooker extends GradleTaskHooker<TransformTask> {
}
@Override
String getTaskName() {
String getTransformName() {
return "dex"
}
......@@ -31,7 +32,7 @@ class DxTaskHooker extends GradleTaskHooker<TransformTask> {
@Override
void beforeTaskExecute(TransformTask task) {
task.inputs.files.each { input ->
// println "${task.name}: ${input.absoluteFile}"
// Log.i 'DxTaskHooker', "${task.name}: ${input.absoluteFile}"
if(input.directory) {
input.eachFileRecurse { file ->
handleFile(file)
......@@ -46,7 +47,7 @@ class DxTaskHooker extends GradleTaskHooker<TransformTask> {
if (file.directory && file.path.endsWith(virtualApk.packagePath)) {
if (recompileSplitR(file)) {
println "Recompiled R.java in dir: ${file.absoluteFile}"
Log.i 'DxTaskHooker', "Recompiled R.java in dir: ${file.absoluteFile}"
}
} else if (file.file && file.name.endsWith('.jar')) {
......@@ -61,7 +62,7 @@ class DxTaskHooker extends GradleTaskHooker<TransformTask> {
File pkgDir = new File(unzipJarDir, virtualApk.packagePath)
if (pkgDir.exists()) {
if (recompileSplitR(pkgDir)) {
println "Recompiled R.java in jar: ${file.absoluteFile}"
Log.i 'DxTaskHooker', "Recompiled R.java in jar: ${file.absoluteFile}"
File backupDir = new File(virtualApk.getBuildDir(scope), 'origin/classes')
backupDir.deleteDir()
project.copy {
......@@ -105,6 +106,7 @@ class DxTaskHooker extends GradleTaskHooker<TransformTask> {
target: apkVariant.javaCompiler.targetCompatibility,
destdir: new File(baseDir))
mark()
return true
}
......
......@@ -31,6 +31,8 @@ public abstract class GradleTaskHooker<T extends Task> {
this.project = project
this.apkVariant = apkVariant
this.virtualApk = project.virtualApk
virtualApk.checkList.addCheckPoint(apkVariant.name, taskName)
}
public Project getProject() {
......@@ -53,6 +55,10 @@ public abstract class GradleTaskHooker<T extends Task> {
return this.virtualApk
}
public void mark() {
virtualApk.checkList.mark(apkVariant.name, taskName)
}
public void setTaskHookerManager(TaskHookerManager taskHookerManager) {
this.taskHookerManager = taskHookerManager
}
......@@ -66,9 +72,18 @@ public abstract class GradleTaskHooker<T extends Task> {
}
/**
* Return the task name or transform name of the hooked task(transform task)
* Return the transform name of the hooked task(transform task)
*/
public String getTransformName() {
return ""
}
/**
* Return the task name(exclude transform task)
*/
public abstract String getTaskName()
public String getTaskName() {
return "${transformName}For${apkVariant.name.capitalize()}"
}
/**
* Callback function before the hooked task executes
......
......@@ -4,6 +4,7 @@ import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.tasks.MergeSourceSetFolders
import com.android.ide.common.res2.AssetSet
import com.didi.virtualapk.collector.dependence.AarDependenceInfo
import com.didi.virtualapk.utils.Log
import com.didi.virtualapk.utils.Reflect
import org.gradle.api.Project
......@@ -41,7 +42,7 @@ class MergeAssetsHooker extends GradleTaskHooker<MergeSourceSetFolders> {
}
Reflect reflect = Reflect.on(task)
reflect.set('assetSetSupplier', new FixedSupplier(reflect.get('assetSetSupplier'), strippedAssetPaths))
reflect.set('assetSetSupplier', new FixedSupplier(this, reflect.get('assetSetSupplier'), strippedAssetPaths))
}
@Override
......@@ -50,10 +51,12 @@ class MergeAssetsHooker extends GradleTaskHooker<MergeSourceSetFolders> {
static class FixedSupplier implements Supplier<List<AssetSet>> {
MergeAssetsHooker hooker
Supplier<List<AssetSet>> origin
Set<String> strippedAssetPaths
FixedSupplier(Supplier<List<AssetSet>> origin, Set<String> strippedAssetPaths) {
FixedSupplier(MergeAssetsHooker hooker, Supplier<List<AssetSet>> origin, Set<String> strippedAssetPaths) {
this.hooker = hooker
this.origin = origin
this.strippedAssetPaths = strippedAssetPaths
}
......@@ -66,11 +69,12 @@ class MergeAssetsHooker extends GradleTaskHooker<MergeSourceSetFolders> {
boolean test(AssetSet assetSet) {
boolean ret = strippedAssetPaths.contains(assetSet.sourceFiles.get(0).path)
if (ret) {
println "Stripped asset of artifact: ${assetSet} -> ${assetSet.sourceFiles.get(0).path}"
Log.i 'MergeAssetsHooker', "Stripped asset of artifact: ${assetSet} -> ${assetSet.sourceFiles.get(0).path}"
}
return ret
}
})
hooker.mark()
return assetSets
}
}
......
......@@ -5,6 +5,7 @@ import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.internal.pipeline.TransformTask
import com.didi.virtualapk.collector.HostJniLibsCollector
import com.didi.virtualapk.utils.Log
import org.gradle.api.Project
/**
......@@ -24,7 +25,7 @@ class MergeJniLibsHooker extends GradleTaskHooker<TransformTask> {
}
@Override
String getTaskName() {
String getTransformName() {
return "mergeJniLibs"
}
......@@ -39,9 +40,10 @@ class MergeJniLibsHooker extends GradleTaskHooker<TransformTask> {
excludeJniFiles.each {
androidConfig.packagingOptions.exclude("/${it}")
println "Stripped jni file: ${it}"
Log.i 'MergeJniLibsHooker', "Stripped jni file: ${it}"
}
mark()
// Reflect.on(task.transform)
// .set('packagingOptions', new ParsedPackagingOptions(androidConfig.packagingOptions))
}
......
......@@ -4,6 +4,7 @@ import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.internal.scope.TaskOutputHolder
import com.android.build.gradle.tasks.MergeManifests
import com.didi.virtualapk.collector.dependence.DependenceInfo
import com.didi.virtualapk.utils.Log
import com.didi.virtualapk.utils.Reflect
import groovy.xml.QName
import groovy.xml.XmlUtil
......@@ -47,7 +48,7 @@ class MergeManifestsHooker extends GradleTaskHooker<MergeManifests> {
} as Set<String>
Reflect reflect = Reflect.on(task)
ArtifactCollection manifests = new FixedArtifactCollection(reflect.get('manifests'), stripAarNames)
ArtifactCollection manifests = new FixedArtifactCollection(this, reflect.get('manifests'), stripAarNames)
reflect.set('manifests', manifests)
}
......@@ -79,11 +80,13 @@ class MergeManifestsHooker extends GradleTaskHooker<MergeManifests> {
}
private static class FixedArtifactCollection implements ArtifactCollection {
private MergeManifestsHooker hooker
private ArtifactCollection origin
def stripAarNames
FixedArtifactCollection(ArtifactCollection origin, stripAarNames) {
FixedArtifactCollection(MergeManifestsHooker hooker, ArtifactCollection origin, stripAarNames) {
this.hooker = hooker
this.origin = origin
this.stripAarNames = stripAarNames
}
......@@ -123,12 +126,13 @@ class MergeManifestsHooker extends GradleTaskHooker<MergeManifests> {
boolean test(ResolvedArtifactResult result) {
boolean ret = stripAarNames.contains("${result.id.componentIdentifier.displayName}")
if (ret) {
println "Stripped manifest of artifact: ${result} -> ${result.file}"
Log.i 'MergeManifestsHooker', "Stripped manifest of artifact: ${result} -> ${result.file}"
}
return ret
}
})
hooker.mark()
return set
}
......
......@@ -9,6 +9,7 @@ import com.didi.virtualapk.collector.dependence.AarDependenceInfo
import com.didi.virtualapk.collector.dependence.DependenceInfo
import com.didi.virtualapk.collector.dependence.JarDependenceInfo
import com.didi.virtualapk.utils.FileUtil
import com.didi.virtualapk.utils.Log
import org.gradle.api.Project
import java.util.function.Consumer
......@@ -65,7 +66,7 @@ class PrepareDependenciesHooker extends GradleTaskHooker<AppPreBuildTask> {
Dependencies dependencies = new ArtifactDependencyGraph().createDependencies(scope, false, new Consumer<SyncIssue>() {
@Override
void accept(SyncIssue syncIssue) {
println "Error: ${syncIssue}"
Log.i 'PrepareDependenciesHooker', "Error: ${syncIssue}"
}
})
......@@ -113,10 +114,11 @@ class PrepareDependenciesHooker extends GradleTaskHooker<AppPreBuildTask> {
FileUtil.saveFile(hostDir, "${taskName}-stripDependencies", stripDependencies)
FileUtil.saveFile(hostDir, "${taskName}-retainedAarLibs", retainedAarLibs)
FileUtil.saveFile(hostDir, "${taskName}-retainedJarLib", retainedJarLib)
println "Analyzed all dependencis. Get more infomation in dir: ${hostDir.absoluteFile}"
Log.i 'PrepareDependenciesHooker', "Analyzed all dependencis. Get more infomation in dir: ${hostDir.absoluteFile}"
virtualApk.stripDependencies = stripDependencies
virtualApk.retainedAarLibs = retainedAarLibs
mark()
}
}
\ No newline at end of file
......@@ -11,6 +11,7 @@ import com.didi.virtualapk.collector.ResourceCollector
import com.didi.virtualapk.collector.res.ResourceEntry
import com.didi.virtualapk.collector.res.StyleableEntry
import com.didi.virtualapk.utils.FileUtil
import com.didi.virtualapk.utils.Log
import com.google.common.collect.ListMultimap
import com.google.common.io.Files
import org.gradle.api.Project
......@@ -136,6 +137,7 @@ class ProcessResourcesHooker extends GradleTaskHooker<ProcessAndroidResources> {
}
updateRJava(aapt, par.sourceOutputDir)
mark()
}
/**
......@@ -160,18 +162,18 @@ class ProcessResourcesHooker extends GradleTaskHooker<ProcessAndroidResources> {
def rSourceFile = new File(sourceOutputDir, "${virtualApk.packagePath}${File.separator}R.java")
aapt.generateRJava(rSourceFile, apkVariant.applicationId, resourceCollector.allResources, resourceCollector.allStyleables)
println "Updated R.java: ${rSourceFile.absoluteFile}"
Log.i 'ProcessResourcesHooker', "Updated R.java: ${rSourceFile.absoluteFile}"
def splitRSourceFile = new File(vaBuildDir, "source${File.separator}r${File.separator}${virtualApk.packagePath}${File.separator}R.java")
aapt.generateRJava(splitRSourceFile, apkVariant.applicationId, resourceCollector.pluginResources, resourceCollector.pluginStyleables)
println "Updated R.java: ${splitRSourceFile.absoluteFile}"
Log.i 'ProcessResourcesHooker', "Updated R.java: ${splitRSourceFile.absoluteFile}"
virtualApk.splitRJavaFile = splitRSourceFile
virtualApk.retainedAarLibs.each {
def aarPackage = it.package
def rJavaFile = new File(sourceOutputDir, "${aarPackage.replace('.'.charAt(0), File.separatorChar)}${File.separator}R.java")
aapt.generateRJava(rJavaFile, aarPackage, it.aarResources, it.aarStyleables)
println "Updated R.java: ${rJavaFile.absoluteFile}"
Log.i 'ProcessResourcesHooker', "Updated R.java: ${rJavaFile.absoluteFile}"
}
}
......
......@@ -22,7 +22,7 @@ class ProguardHooker extends GradleTaskHooker<TransformTask> {
}
@Override
String getTaskName() {
String getTransformName() {
return "proguard"
}
......@@ -71,6 +71,7 @@ class ProguardHooker extends GradleTaskHooker<TransformTask> {
}
}
}
mark()
}
@Override
......
......@@ -6,6 +6,7 @@ import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.internal.pipeline.TransformTask
import com.android.build.gradle.internal.transforms.ShrinkResourcesTransform
import com.didi.virtualapk.transform.TransformWrapper
import com.didi.virtualapk.utils.Log
import com.didi.virtualapk.utils.Reflect
import org.gradle.api.Project
......@@ -16,7 +17,7 @@ class ShrinkResourcesHooker extends GradleTaskHooker<TransformTask> {
}
@Override
String getTaskName() {
String getTransformName() {
return "shrinkRes"
}
......@@ -26,8 +27,9 @@ class ShrinkResourcesHooker extends GradleTaskHooker<TransformTask> {
Reflect.on(task).set('transform', new TransformWrapper(shrinkResourcesTransform) {
@Override
void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {
println "sourceDir: ${Reflect.on(origin).get('sourceDir')}"
Log.i 'ShrinkResourcesHooker', "sourceDir: ${Reflect.on(origin).get('sourceDir')}"
super.transform(invocation)
mark()
}
})
}
......
......@@ -3,6 +3,7 @@ package com.didi.virtualapk.hooker
import com.android.build.gradle.AppExtension
import com.android.build.gradle.internal.api.ApplicationVariantImpl
import com.android.build.gradle.internal.pipeline.TransformTask
import com.didi.virtualapk.utils.Log
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.execution.TaskExecutionListener
......@@ -45,10 +46,10 @@ public abstract class TaskHookerManager {
@Override
void beforeExecute(Task task) {
// println "beforeExecute ${task.name} tid: ${Thread.currentThread().id} t: ${Thread.currentThread().name}"
// Log.i 'TaskHookerManager', "beforeExecute ${task.name} tid: ${Thread.currentThread().id} t: ${Thread.currentThread().name}"
if (task.project == project) {
if (task in TransformTask) {
taskHookerMap[task.transform.name]?.beforeTaskExecute(task)
taskHookerMap["${task.transform.name}For${task.variantName.capitalize()}".toString()]?.beforeTaskExecute(task)
} else {
taskHookerMap[task.name]?.beforeTaskExecute(task)
}
......@@ -57,10 +58,10 @@ public abstract class TaskHookerManager {
@Override
void afterExecute(Task task, TaskState taskState) {
// println "afterExecute ${task.name} tid: ${Thread.currentThread().id} t: ${Thread.currentThread().name}"
// Log.i 'TaskHookerManager', "afterExecute ${task.name} tid: ${Thread.currentThread().id} t: ${Thread.currentThread().name}"
if (task.project == project) {
if (task in TransformTask) {
taskHookerMap[task.transform.name]?.afterTaskExecute(task)
taskHookerMap["${task.transform.name}For${task.variantName.capitalize()}".toString()]?.afterTaskExecute(task)
} else {
taskHookerMap[task.name]?.afterTaskExecute(task)
}
......
......@@ -8,7 +8,6 @@ import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.internal.ConventionMapping
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
......@@ -19,7 +18,7 @@ import java.util.concurrent.Callable
* Gradle task for assemble plugin apk
* @author zhengtao
*/
public class AssemblePlugin extends DefaultTask{
public class AssemblePlugin extends DefaultTask {
@OutputDirectory
File pluginApkDir
......@@ -33,12 +32,16 @@ public class AssemblePlugin extends DefaultTask{
@Input
File originApkFile
String variantName
/**
* Copy the plugin apk to out/plugin directory and rename to
* the format required for the backend system
*/
@TaskAction
public void outputPluginApk() {
project.virtualApk.checkList.check(variantName)
getProject().copy {
from originApkFile
into pluginApkDir
......@@ -78,6 +81,10 @@ public class AssemblePlugin extends DefaultTask{
new File(project.buildDir, "/outputs/plugin/${variant.name}")
}
map(assemblePluginTask, "variantName") {
variant.name
}
assemblePluginTask.setGroup("build")
assemblePluginTask.setDescription("Build ${variant.name.capitalize()} plugin apk")
assemblePluginTask.dependsOn(variant.assemble.name)
......
package com.didi.virtualapk.transform
import com.android.build.api.transform.*
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.internal.pipeline.TransformManager
import com.didi.virtualapk.VAExtention
import com.didi.virtualapk.collector.HostClassAndResCollector
import com.didi.virtualapk.utils.Log
import groovy.io.FileType
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
......@@ -23,6 +25,12 @@ class StripClassAndResTransform extends Transform {
classAndResCollector = new HostClassAndResCollector()
}
void onProjectAfterEvaluate() {
project.android.applicationVariants.each { ApplicationVariant variant ->
virtualApk.checkList.addCheckPoint(variant.name, name)
}
}
@Override
String getName() {
return 'stripClassAndRes'
......@@ -57,36 +65,38 @@ class StripClassAndResTransform extends Transform {
transformInvocation.inputs.each {
it.directoryInputs.each { directoryInput ->
// println "input dir: ${directoryInput.file.absoluteFile}"
// Log.i 'StripClassAndResTransform', "input dir: ${directoryInput.file.absoluteFile}"
def destDir = transformInvocation.outputProvider.getContentLocation(
directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
// println "output dir: ${destDir.absoluteFile}"
// Log.i 'StripClassAndResTransform', "output dir: ${destDir.absoluteFile}"
directoryInput.file.traverse(type: FileType.FILES) {
def entryName = it.path.substring(directoryInput.file.path.length() + 1)
// println "found file: ${it.absoluteFile}"
// println "entryName: ${entryName}"
// Log.i 'StripClassAndResTransform', "found file: ${it.absoluteFile}"
// Log.i 'StripClassAndResTransform', "entryName: ${entryName}"
if (!stripEntries.contains(entryName)) {
def dest = new File(destDir, entryName)
FileUtils.copyFile(it, dest)
// println "Copied to file: ${dest.absoluteFile}"
// Log.i 'StripClassAndResTransform', "Copied to file: ${dest.absoluteFile}"
} else {
println "Stripped file: ${it.absoluteFile}"
Log.i 'StripClassAndResTransform', "Stripped file: ${it.absoluteFile}"
}
}
}
it.jarInputs.each { jarInput ->
// println "${name} jar: ${jarInput.file.absoluteFile}"
// Log.i 'StripClassAndResTransform', "${name} jar: ${jarInput.file.absoluteFile}"
Set<String> jarEntries = HostClassAndResCollector.unzipJar(jarInput.file)
if (!stripEntries.containsAll(jarEntries)){
def dest = transformInvocation.outputProvider.getContentLocation(jarInput.name,
jarInput.contentTypes, jarInput.scopes, Format.JAR)
FileUtils.copyFile(jarInput.file, dest)
// println "Copied to jar: ${dest.absoluteFile}"
// Log.i 'StripClassAndResTransform', "Copied to jar: ${dest.absoluteFile}"
} else {
println "Stripped jar: ${jarInput.file.absoluteFile}"
Log.i 'StripClassAndResTransform', "Stripped jar: ${jarInput.file.absoluteFile}"
}
}
}
virtualApk.checkList.mark(transformInvocation.context.variantName, name)
}
}
\ No newline at end of file
package com.didi.virtualapk.utils
class CheckList {
Map<String, Boolean> mMap = new LinkedHashMap<>()
void addCheckPoint(String variantName, String name) {
String key = "${variantName}:${name}"
if (mMap.containsKey(key)) {
throw new RuntimeException("[${key}] has already exists.")
}
mMap.put(key, false)
// Log.i('test', "addCheckPoint: ${key}")
}
void mark(String variantName, String name) {
String key = "${variantName}:${name}"
mMap.put(key, true)
// Log.i('test', "mark: ${key}")
}
void check(String variantName) {
boolean check = true
Map matched = mMap.findAll {
// Log.i 'CheckList', "all: ${it.key}: ${it.value}"
it.key.startsWith("${variantName}:")
}
matched.each {
check &= it.value
}
if (check) {
Log.i 'CheckList', "All checked ok."
return
}
Log.i 'CheckList', "Checked WARNING:"
matched.each {
Log.i 'CheckList', "${it.key}: ${it.value}"
}
}
}
\ No newline at end of file
package com.didi.virtualapk.utils
public final class Log {
private Log() {
}
public static int i(String tag, String msg) {
println "[INFO][${tag}] ${msg}"
return 0
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册