add pins code
This commit is contained in:
180
component-plugin/src/main/groovy/com/plugin/pins/Digraph.java
Normal file
180
component-plugin/src/main/groovy/com/plugin/pins/Digraph.java
Normal file
@@ -0,0 +1,180 @@
|
||||
package com.plugin.pins;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* An example class for directed graphs. The vertex type can be specified.
|
||||
* There are no edge costs/weights.
|
||||
*
|
||||
* Written for CS211, Nov 2006.
|
||||
*
|
||||
* @author Paul Chew
|
||||
*/
|
||||
public class Digraph<V> {
|
||||
|
||||
/**
|
||||
* The implementation here is basically an adjacency list, but instead
|
||||
* of an array of lists, a Map is used to map each vertex to its list of
|
||||
* adjacent vertices.
|
||||
*/
|
||||
private Map<V,List<V>> neighbors = new HashMap<V,List<V>>();
|
||||
|
||||
/**
|
||||
* String representation of dependencyGraph.
|
||||
*/
|
||||
public String toString () {
|
||||
StringBuffer s = new StringBuffer();
|
||||
for (V v: neighbors.keySet()) s.append("\n " + v + " -> " + neighbors.get(v));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vertex to the dependencyGraph. Nothing happens if vertex is already in dependencyGraph.
|
||||
*/
|
||||
public void add (V vertex) {
|
||||
if (neighbors.containsKey(vertex)) return;
|
||||
neighbors.put(vertex, new ArrayList<V>());
|
||||
}
|
||||
|
||||
/**
|
||||
* True iff dependencyGraph contains vertex.
|
||||
*/
|
||||
public boolean contains (V vertex) {
|
||||
return neighbors.containsKey(vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an edge to the dependencyGraph; if either vertex does not exist, it's added.
|
||||
* This implementation allows the creation of multi-edges and self-loops.
|
||||
*/
|
||||
public void add (V from, V to) {
|
||||
this.add(from); this.add(to);
|
||||
neighbors.get(from).add(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an edge from the dependencyGraph. Nothing happens if no such edge.
|
||||
* @throws IllegalArgumentException if either vertex doesn't exist.
|
||||
*/
|
||||
public void remove (V from, V to) {
|
||||
if (!(this.contains(from) && this.contains(to)))
|
||||
throw new IllegalArgumentException("Nonexistent vertex");
|
||||
neighbors.get(from).remove(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report (as a Map) the out-degree of each vertex.
|
||||
*/
|
||||
public Map<V,Integer> outDegree () {
|
||||
Map<V,Integer> result = new HashMap<V,Integer>();
|
||||
for (V v: neighbors.keySet()) result.put(v, neighbors.get(v).size());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report (as a Map) the in-degree of each vertex.
|
||||
*/
|
||||
public Map<V,Integer> inDegree () {
|
||||
Map<V,Integer> result = new HashMap<V,Integer>();
|
||||
for (V v: neighbors.keySet()) result.put(v, 0); // All in-degrees are 0
|
||||
for (V from: neighbors.keySet()) {
|
||||
for (V to: neighbors.get(from)) {
|
||||
result.put(to, result.get(to) + 1); // Increment in-degree
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report (as a List) the topological sort of the vertices; null for no such sort.
|
||||
*/
|
||||
public List<V> topSort () {
|
||||
Map<V, Integer> degree = inDegree();
|
||||
// Determine all vertices with zero in-degree
|
||||
Stack<V> zeroVerts = new Stack<V>(); // Stack as good as any here
|
||||
for (V v: degree.keySet()) {
|
||||
if (degree.get(v) == 0) zeroVerts.push(v);
|
||||
}
|
||||
// Determine the topological order
|
||||
List<V> result = new ArrayList<V>();
|
||||
while (!zeroVerts.isEmpty()) {
|
||||
V v = zeroVerts.pop(); // Choose a vertex with zero in-degree
|
||||
result.add(v); // Vertex v is next in topol order
|
||||
// "Remove" vertex v by updating its neighbors
|
||||
for (V neighbor: neighbors.get(v)) {
|
||||
degree.put(neighbor, degree.get(neighbor) - 1);
|
||||
// Remember any vertices that now have zero in-degree
|
||||
if (degree.get(neighbor) == 0) zeroVerts.push(neighbor);
|
||||
}
|
||||
}
|
||||
// Check that we have used the entire dependencyGraph (if not, there was a cycle)
|
||||
if (result.size() != neighbors.size()) return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* True iff dependencyGraph is a dag (directed acyclic dependencyGraph).
|
||||
*/
|
||||
public boolean isDag () {
|
||||
return topSort() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report (as a Map) the bfs distance to each vertex from the start vertex.
|
||||
* The distance is an Integer; the value null is used to represent infinity
|
||||
* (implying that the corresponding node cannot be reached).
|
||||
*/
|
||||
public Map bfsDistance (V start) {
|
||||
Map<V,Integer> distance = new HashMap<V,Integer>();
|
||||
// Initially, all distance are infinity, except start node
|
||||
for (V v: neighbors.keySet()) distance.put(v, null);
|
||||
distance.put(start, 0);
|
||||
// Process nodes in queue order
|
||||
Queue<V> queue = new LinkedList<V>();
|
||||
queue.offer(start); // Place start node in queue
|
||||
while (!queue.isEmpty()) {
|
||||
V v = queue.remove();
|
||||
int vDist = distance.get(v);
|
||||
// Update neighbors
|
||||
for (V neighbor: neighbors.get(v)) {
|
||||
if (distance.get(neighbor) != null) continue; // Ignore if already done
|
||||
distance.put(neighbor, vDist + 1);
|
||||
queue.offer(neighbor);
|
||||
}
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Main program (for testing).
|
||||
// */
|
||||
// public static void main (String[] args) {
|
||||
// // Create a Graph with Integer nodes
|
||||
// Digraph<Integer> graph = new Digraph<Integer>();
|
||||
// graph.add(0, 1); graph.add(0, 2); graph.add(0, 3);
|
||||
// graph.add(1, 2); graph.add(1, 3); graph.add(2, 3);
|
||||
// graph.add(2, 4); graph.add(4, 5); graph.add(5, 6); // Tetrahedron with tail
|
||||
// System.out.println("The current dependencyGraph: " + graph);
|
||||
// System.out.println("In-degrees: " + graph.inDegree());
|
||||
// System.out.println("Out-degrees: " + graph.outDegree());
|
||||
// System.out.println("A topological sort of the vertices: " + graph.topSort());
|
||||
// System.out.println("The dependencyGraph " + (graph.isDag()?"is":"is not") + " a dag");
|
||||
// System.out.println("BFS distances starting from " + 0 + ": " + graph.bfsDistance(0));
|
||||
// System.out.println("BFS distances starting from " + 1 + ": " + graph.bfsDistance(1));
|
||||
// System.out.println("BFS distances starting from " + 2 + ": " + graph.bfsDistance(2));
|
||||
// graph.add(4, 1); // Create a cycle
|
||||
// System.out.println("Cycle created");
|
||||
// System.out.println("The current dependencyGraph: " + graph);
|
||||
// System.out.println("In-degrees: " + graph.inDegree());
|
||||
// System.out.println("Out-degrees: " + graph.outDegree());
|
||||
// System.out.println("A topological sort of the vertices: " + graph.topSort());
|
||||
// System.out.println("The dependencyGraph " + (graph.isDag()?"is":"is not") + " a dag");
|
||||
// System.out.println("BFS distances starting from " + 2 + ": " + graph.bfsDistance(2));
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.plugin.pins
|
||||
|
||||
|
||||
class MicroModule {
|
||||
|
||||
String name
|
||||
File microModuleDir
|
||||
|
||||
boolean appliedScript
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.plugin.pins
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
|
||||
class MicroModuleInfo {
|
||||
|
||||
Project project
|
||||
MicroModule mainMicroModule
|
||||
Map<String, MicroModule> includeMicroModules
|
||||
Map<String, String> exportMicroModules
|
||||
|
||||
Digraph<String> dependencyGraph
|
||||
|
||||
MicroModuleInfo(Project project) {
|
||||
this.project = project
|
||||
this.includeMicroModules = new HashMap<>()
|
||||
this.exportMicroModules = new HashMap<>()
|
||||
dependencyGraph = new Digraph<String>()
|
||||
|
||||
MicroModule microModule = Utils.buildMicroModule(project, ':main')
|
||||
if (microModule != null) {
|
||||
setMainMicroModule(microModule)
|
||||
}
|
||||
}
|
||||
|
||||
void setMainMicroModule(MicroModule microModule) {
|
||||
if (microModule == null) {
|
||||
throw new GradleException("main MicroModule cannot be null.")
|
||||
}
|
||||
this.mainMicroModule = microModule
|
||||
addIncludeMicroModule(microModule)
|
||||
}
|
||||
|
||||
void addIncludeMicroModule(MicroModule microModule) {
|
||||
includeMicroModules.put(microModule.name, microModule)
|
||||
}
|
||||
|
||||
void addExportMicroModule(String name) {
|
||||
MicroModule microModule = Utils.buildMicroModule(project, name)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${name}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
exportMicroModules.put(name, null)
|
||||
}
|
||||
|
||||
MicroModule getMicroModule(String name) {
|
||||
return includeMicroModules.get(name)
|
||||
}
|
||||
|
||||
void setMicroModuleDependency(String target, String dependency) {
|
||||
MicroModule dependencyMicroModule = getMicroModule(dependency)
|
||||
if(dependencyMicroModule == null) {
|
||||
if(Utils.buildMicroModule(project, dependency) != null) {
|
||||
throw new GradleException("MicroModule '${target}' dependency MicroModle '${dependency}', but its not included.")
|
||||
} else {
|
||||
throw new GradleException("MicroModule with path '${path}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
}
|
||||
|
||||
dependencyGraph.add(target, dependency)
|
||||
if(!dependencyGraph.isDag()) {
|
||||
throw new GradleException("Circular dependency between MicroModule '${target}' and '${dependency}'.")
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasDependency(String target, String dependency) {
|
||||
Map<String, Integer> bfsDistance = dependencyGraph.bfsDistance(target)
|
||||
for(String key: bfsDistance.keySet()) {
|
||||
if(key == dependency) {
|
||||
return bfsDistance.get(key) != null
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,608 @@
|
||||
package com.plugin.pins
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import com.android.builder.model.ProductFlavor
|
||||
import com.android.manifmerger.ManifestMerger2
|
||||
import com.android.manifmerger.MergingReport
|
||||
import com.android.manifmerger.XmlDocument
|
||||
import com.android.utils.ILogger
|
||||
import com.plugin.pins.check.CodeChecker
|
||||
import com.plugin.pins.extension.DefaultMicroModuleExtension
|
||||
import com.plugin.pins.extension.OnMicroModuleListener
|
||||
import org.gradle.BuildListener
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.invocation.Gradle
|
||||
|
||||
class MicroModulePlugin implements Plugin<Project> {
|
||||
|
||||
private final static String NORMAL = 'normal'
|
||||
private final static String ASSEMBLE_OR_GENERATE = 'assemble_or_generate'
|
||||
|
||||
private final static String APPLY_NORMAL_MICRO_MODULE_SCRIPT = 'apply_normal_micro_module_script'
|
||||
private final static String APPLY_INCLUDE_MICRO_MODULE_SCRIPT = 'apply_include_micro_module_script'
|
||||
private final static String APPLY_EXPORT_MICRO_MODULE_SCRIPT = 'apply_export_micro_module_script'
|
||||
|
||||
private final static BuildListener buildListener = new BuildListener() {
|
||||
|
||||
@Override
|
||||
void buildStarted(Gradle gradle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void settingsEvaluated(Settings settings) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void projectsLoaded(Gradle gradle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void projectsEvaluated(Gradle gradle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void buildFinished(BuildResult buildResult) {
|
||||
// generate microModules.xml for MicroModule IDEA plugin.
|
||||
def ideaFile = new File(buildResult.gradle.rootProject.rootDir, '.idea')
|
||||
if (!ideaFile.exists()) return
|
||||
|
||||
def microModuleInfo = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<modules>\n'
|
||||
buildResult.gradle.rootProject.allprojects.each {
|
||||
MicroModulePlugin microModulePlugin = it.plugins.findPlugin('micro-module')
|
||||
if (microModulePlugin == null) return
|
||||
|
||||
def displayName = it.displayName
|
||||
microModuleInfo += ' <module name=\"' + displayName.substring(displayName.indexOf("'") + 1, displayName.lastIndexOf("'")) + '\" path=\"' + it.projectDir.getCanonicalPath() + '\">\n'
|
||||
microModulePlugin.microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
microModuleInfo += ' <microModule name=\"' + microModule.name + '\" path=\"' + microModule.microModuleDir.getCanonicalPath() + '\" />\n'
|
||||
}
|
||||
microModuleInfo += ' </module>\n'
|
||||
}
|
||||
microModuleInfo += '</modules>'
|
||||
|
||||
def microModules = new File(ideaFile, 'microModules.xml')
|
||||
microModules.write(microModuleInfo, 'utf-8')
|
||||
}
|
||||
}
|
||||
|
||||
Project project
|
||||
|
||||
String startTaskState = NORMAL
|
||||
|
||||
MicroModuleInfo microModuleInfo
|
||||
ProductFlavorInfo productFlavorInfo
|
||||
|
||||
MicroModule currentMicroModule
|
||||
String applyScriptState
|
||||
|
||||
boolean appliedLibraryPlugin
|
||||
|
||||
boolean clearedOriginSourceSets
|
||||
|
||||
void apply(Project project) {
|
||||
this.project = project
|
||||
this.microModuleInfo = new MicroModuleInfo(project)
|
||||
|
||||
project.gradle.removeListener(buildListener)
|
||||
project.gradle.addBuildListener(buildListener)
|
||||
|
||||
if (project.gradle.getStartParameter().taskNames.size() == 0) {
|
||||
startTaskState = NORMAL
|
||||
} else {
|
||||
startTaskState = ASSEMBLE_OR_GENERATE
|
||||
}
|
||||
|
||||
if (startTaskState != NORMAL) {
|
||||
project.getConfigurations().whenObjectAdded {
|
||||
Configuration configuration = it
|
||||
configuration.dependencies.whenObjectAdded {
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
configuration.dependencies.remove(it)
|
||||
return
|
||||
} else if (applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
|| applyScriptState == APPLY_EXPORT_MICRO_MODULE_SCRIPT) {
|
||||
return
|
||||
} else if (currentMicroModule == null && startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
return
|
||||
} else if (it.group != null && it.group.startsWith('com.android.tools')) {
|
||||
return
|
||||
}
|
||||
|
||||
configuration.dependencies.remove(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefaultMicroModuleExtension microModuleExtension = project.extensions.create(MicroModuleExtension, 'microModule', DefaultMicroModuleExtension, project)
|
||||
microModuleExtension.onMicroModuleListener = new OnMicroModuleListener() {
|
||||
|
||||
@Override
|
||||
void addIncludeMicroModule(MicroModule microModule, boolean mainMicroModule) {
|
||||
if (mainMicroModule) {
|
||||
microModuleInfo.setMainMicroModule(microModule)
|
||||
} else {
|
||||
microModuleInfo.addIncludeMicroModule(microModule)
|
||||
}
|
||||
|
||||
if(!clearedOriginSourceSets) {
|
||||
productFlavorInfo = new ProductFlavorInfo(project)
|
||||
clearedOriginSourceSets = true
|
||||
clearOriginSourceSet()
|
||||
|
||||
if(microModuleInfo.mainMicroModule != null) {
|
||||
addMicroModuleSourceSet(microModuleInfo.mainMicroModule)
|
||||
}
|
||||
}
|
||||
|
||||
addMicroModuleSourceSet(microModule)
|
||||
}
|
||||
|
||||
@Override
|
||||
void addExportMicroModule(String... microModulePaths) {
|
||||
microModulePaths.each {
|
||||
microModuleInfo.addExportMicroModule(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
project.dependencies.metaClass.microModule { String path ->
|
||||
if (currentMicroModule == null || applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
microModuleInfo.setMicroModuleDependency(currentMicroModule.name, path)
|
||||
return []
|
||||
}
|
||||
|
||||
MicroModule microModule = microModuleInfo.getMicroModule(path)
|
||||
|
||||
def result = []
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
project.plugins.all {
|
||||
Class extensionClass
|
||||
if (it instanceof AppPlugin) {
|
||||
extensionClass = AppExtension
|
||||
} else if (it instanceof LibraryPlugin) {
|
||||
extensionClass = LibraryExtension
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
project.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
|
||||
@Override
|
||||
void execute(TestedExtension testedExtension) {
|
||||
boolean isLibrary
|
||||
DomainObjectSet<BaseVariant> baseVariants
|
||||
if (testedExtension instanceof AppExtension) {
|
||||
AppExtension appExtension = (AppExtension) testedExtension
|
||||
baseVariants = appExtension.applicationVariants
|
||||
} else {
|
||||
LibraryExtension libraryExtension = (LibraryExtension) testedExtension
|
||||
baseVariants = libraryExtension.libraryVariants
|
||||
isLibrary = true
|
||||
}
|
||||
|
||||
baseVariants.all { BaseVariant variant ->
|
||||
if (microModuleExtension.codeCheckEnabled) {
|
||||
def taskNamePrefix = isLibrary ? 'package' : 'merge'
|
||||
List<String> sourceFolders = new ArrayList<>()
|
||||
sourceFolders.add('main')
|
||||
sourceFolders.add(variant.buildType.name)
|
||||
if (variant.productFlavors.size() > 0) {
|
||||
sourceFolders.add(variant.name)
|
||||
sourceFolders.add(variant.flavorName)
|
||||
for (ProductFlavor productFlavor : variant.productFlavors) {
|
||||
sourceFolders.add(productFlavor.name)
|
||||
}
|
||||
checkMicroModuleBoundary(taskNamePrefix, variant.buildType.name, variant.flavorName, sourceFolders)
|
||||
} else {
|
||||
checkMicroModuleBoundary(taskNamePrefix, variant.buildType.name, null, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
microModuleExtension.onMicroModuleListener = null
|
||||
if (microModuleInfo.mainMicroModule == null) {
|
||||
throw new GradleException("the main MicroModule could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
appliedLibraryPlugin = project.pluginManager.hasPlugin('com.android.library')
|
||||
|
||||
productFlavorInfo = new ProductFlavorInfo(project)
|
||||
|
||||
applyScriptState = APPLY_INCLUDE_MICRO_MODULE_SCRIPT
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
microModuleInfo.dependencyGraph.add(microModule.name)
|
||||
applyMicroModuleScript(microModule)
|
||||
}
|
||||
|
||||
clearOriginSourceSet()
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
applyScriptState = APPLY_EXPORT_MICRO_MODULE_SCRIPT
|
||||
boolean hasExportMainMicroModule = false
|
||||
boolean isEmpty = microModuleInfo.exportMicroModules.isEmpty()
|
||||
List<String> dependencySort = microModuleInfo.dependencyGraph.topSort()
|
||||
dependencySort.each {
|
||||
if (isEmpty || microModuleInfo.exportMicroModules.containsKey(it)) {
|
||||
MicroModule microModule = microModuleInfo.getMicroModule(it)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${it}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
if (microModule == microModuleInfo.mainMicroModule) {
|
||||
hasExportMainMicroModule = true
|
||||
}
|
||||
|
||||
if (microModule.appliedScript) return
|
||||
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExportMainMicroModule) {
|
||||
throw new GradleException("the main MicroModule '${microModuleInfo.mainMicroModule.name}' is not in the export list.")
|
||||
}
|
||||
} else {
|
||||
applyScriptState = APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
}
|
||||
}
|
||||
currentMicroModule = null
|
||||
|
||||
generateAndroidManifest()
|
||||
|
||||
project.tasks.preBuild.doFirst {
|
||||
clearOriginSourceSet()
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
if (microModule.appliedScript) {
|
||||
addMicroModuleSourceSet(microModule)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
addMicroModuleSourceSet(it.value)
|
||||
}
|
||||
}
|
||||
generateAndroidManifest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def generateAndroidManifest() {
|
||||
if ((startTaskState == ASSEMBLE_OR_GENERATE || !microModuleInfo.exportMicroModules.isEmpty()) && isMainSourceSetEmpty()) {
|
||||
setMainSourceSetManifest()
|
||||
return
|
||||
}
|
||||
mergeAndroidManifest('main')
|
||||
|
||||
productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(it)
|
||||
|
||||
def productFlavor = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(productFlavor + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def androidTest = 'androidTest'
|
||||
mergeAndroidManifest(androidTest)
|
||||
mergeAndroidManifest(androidTest + 'Debug')
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(androidTest + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(androidTest + Utils.upperCase(it))
|
||||
mergeAndroidManifest(androidTest + Utils.upperCase(it) + 'Debug')
|
||||
}
|
||||
}
|
||||
|
||||
def mergeAndroidManifest(String variantName) {
|
||||
File mainManifestFile = new File(microModuleInfo.mainMicroModule.microModuleDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (!mainManifestFile.exists()) return
|
||||
ManifestMerger2.MergeType mergeType = ManifestMerger2.MergeType.APPLICATION
|
||||
XmlDocument.Type documentType = XmlDocument.Type.MAIN
|
||||
def logger = new ILogger() {
|
||||
@Override
|
||||
void error(Throwable t, String msgFormat, Object... args) {
|
||||
println(msgFormat)
|
||||
}
|
||||
|
||||
@Override
|
||||
void warning(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void info(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void verbose(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
}
|
||||
ManifestMerger2.Invoker invoker = new ManifestMerger2.Invoker(mainManifestFile, logger, mergeType, documentType)
|
||||
invoker.withFeatures(ManifestMerger2.Invoker.Feature.NO_PLACEHOLDER_REPLACEMENT)
|
||||
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE && !microModule.appliedScript) return
|
||||
if (microModule.name == microModuleInfo.mainMicroModule.name) return
|
||||
def microManifestFile = new File(microModule.microModuleDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (microManifestFile.exists()) {
|
||||
invoker.addLibraryManifest(microManifestFile)
|
||||
}
|
||||
}
|
||||
|
||||
def mergingReport = invoker.merge()
|
||||
if (!mergingReport.result.success) {
|
||||
mergingReport.log(logger)
|
||||
throw new GradleException(mergingReport.reportString)
|
||||
}
|
||||
def moduleAndroidManifest = mergingReport.getMergedDocument(MergingReport.MergedManifestKind.MERGED)
|
||||
moduleAndroidManifest = new String(moduleAndroidManifest.getBytes('UTF-8'))
|
||||
|
||||
def saveDir = new File(project.projectDir, "build/microModule/merge-manifest/${variantName}")
|
||||
saveDir.mkdirs()
|
||||
def AndroidManifestFile = new File(saveDir, 'AndroidManifest.xml')
|
||||
AndroidManifestFile.createNewFile()
|
||||
AndroidManifestFile.write(moduleAndroidManifest)
|
||||
|
||||
def extensionContainer = project.getExtensions()
|
||||
BaseExtension android = extensionContainer.getByName('android')
|
||||
def obj = android.sourceSets.findByName(variantName)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.manifest.srcFile project.projectDir.absolutePath + "/build/microModule/merge-manifest/${variantName}/AndroidManifest.xml"
|
||||
}
|
||||
|
||||
def addMicroModuleSourceSet(MicroModule microModule) {
|
||||
addVariantSourceSet(microModule, 'main')
|
||||
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, flavorName + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
addVariantSourceSet(microModule, testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, testType + Utils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(microModule, testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(microModule, testType + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + Utils.upperCase(it)
|
||||
addVariantSourceSet(microModule, productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, productFlavorName + Utils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(microModule, productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def clearOriginSourceSet() {
|
||||
clearModuleSourceSet('main')
|
||||
|
||||
// buildTypes
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
clearModuleSourceSet(it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(flavorName + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
clearModuleSourceSet(testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(testType + Utils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(testType + Utils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + Utils.upperCase(it)
|
||||
clearModuleSourceSet(productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(productFlavorName + Utils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def isMainSourceSetEmpty() {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
return true
|
||||
}
|
||||
return obj.java.srcDirs.size() == 0;
|
||||
}
|
||||
|
||||
def setMainSourceSetManifest() {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create('main')
|
||||
}
|
||||
File mainManifestFile = new File(microModuleInfo.mainMicroModule.microModuleDir, '/src/main/AndroidManifest.xml')
|
||||
obj.manifest.srcFile mainManifestFile
|
||||
}
|
||||
|
||||
def addVariantSourceSet(MicroModule microModule, def type) {
|
||||
def absolutePath = microModule.microModuleDir.absolutePath
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create(type)
|
||||
}
|
||||
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/java")
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/kotlin")
|
||||
obj.res.srcDir(absolutePath + "/src/${type}/res")
|
||||
obj.jni.srcDir(absolutePath + "/src/${type}/jni")
|
||||
obj.jniLibs.srcDir(absolutePath + "/src/${type}/jniLibs")
|
||||
obj.aidl.srcDir(absolutePath + "/src/${type}/aidl")
|
||||
obj.assets.srcDir(absolutePath + "/src/${type}/assets")
|
||||
obj.shaders.srcDir(absolutePath + "/src/${type}/shaders")
|
||||
obj.resources.srcDir(absolutePath + "/src/${type}/resources")
|
||||
obj.renderscript.srcDir(absolutePath + "/src/${type}/rs")
|
||||
}
|
||||
|
||||
def clearModuleSourceSet(def type) {
|
||||
def srcDirs = []
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.java.srcDirs = srcDirs
|
||||
obj.res.srcDirs = srcDirs
|
||||
obj.jni.srcDirs = srcDirs
|
||||
obj.jniLibs.srcDirs = srcDirs
|
||||
obj.aidl.srcDirs = srcDirs
|
||||
obj.assets.srcDirs = srcDirs
|
||||
obj.shaders.srcDirs = srcDirs
|
||||
obj.resources.srcDirs = srcDirs
|
||||
obj.renderscript.srcDirs = srcDirs
|
||||
}
|
||||
|
||||
void applyMicroModuleScript(MicroModule microModule) {
|
||||
def microModuleBuild = new File(microModule.microModuleDir, 'build.gradle')
|
||||
if (microModuleBuild.exists()) {
|
||||
MicroModule tempMicroModule = currentMicroModule
|
||||
currentMicroModule = microModule
|
||||
project.apply from: microModuleBuild.absolutePath
|
||||
currentMicroModule = tempMicroModule
|
||||
}
|
||||
}
|
||||
|
||||
def checkMicroModuleBoundary(String taskPrefix, String buildType, String flavorName, List<String> sourceFolders) {
|
||||
CodeChecker codeChecker
|
||||
|
||||
def buildTypeFirstUp = Utils.upperCase(buildType)
|
||||
def productFlavorFirstUp = flavorName != null ? Utils.upperCase(flavorName) : ""
|
||||
|
||||
def mergeResourcesTaskName = taskPrefix + productFlavorFirstUp + buildTypeFirstUp + 'Resources'
|
||||
def packageResourcesTask = project.tasks.findByName(mergeResourcesTaskName)
|
||||
if (packageResourcesTask != null) {
|
||||
codeChecker = new CodeChecker(project, microModuleInfo, productFlavorInfo, buildType, flavorName)
|
||||
packageResourcesTask.doLast {
|
||||
codeChecker.checkResources(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
|
||||
def compileJavaTaskName = "compile${productFlavorFirstUp}${buildTypeFirstUp}JavaWithJavac"
|
||||
def compileJavaTask = project.tasks.findByName(compileJavaTaskName)
|
||||
if (compileJavaTask != null) {
|
||||
compileJavaTask.doLast {
|
||||
if (codeChecker == null) {
|
||||
codeChecker = new CodeChecker(project, microModuleInfo, productFlavorInfo, buildType, flavorName)
|
||||
}
|
||||
codeChecker.checkClasses(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.plugin.pins
|
||||
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import org.gradle.api.Project
|
||||
|
||||
class ProductFlavorInfo {
|
||||
|
||||
List<String> flavorDimensions
|
||||
List<String> productFlavors
|
||||
List<String> buildTypes
|
||||
List<String> combinedProductFlavors
|
||||
Map<String, List<String>> combinedProductFlavorsMap
|
||||
boolean singleDimension
|
||||
|
||||
private List<List<String>> flavorGroups
|
||||
|
||||
ProductFlavorInfo(Project project) {
|
||||
BaseExtension extension = (BaseExtension) project.extensions.getByName("android")
|
||||
buildTypes = new ArrayList<>()
|
||||
if(extension.buildTypes != null) {
|
||||
extension.buildTypes.each {
|
||||
buildTypes.add(it.name)
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions = extension.flavorDimensionList
|
||||
if (flavorDimensions == null) {
|
||||
flavorDimensions = new ArrayList<>()
|
||||
}
|
||||
|
||||
productFlavors = new ArrayList<>()
|
||||
flavorGroups = new ArrayList<>()
|
||||
for (int i = 0; i < flavorDimensions.size(); i++) {
|
||||
flavorGroups.add(new ArrayList<>())
|
||||
}
|
||||
extension.productFlavors.each {
|
||||
productFlavors.add(it.name)
|
||||
def position = flavorDimensions.indexOf(it.dimension)
|
||||
flavorGroups.get(position).add(it.name)
|
||||
}
|
||||
List<List<String>> flavorGroupTemp = new ArrayList<>()
|
||||
flavorGroups.each {
|
||||
if (it.size() != 0) {
|
||||
flavorGroupTemp.add(it)
|
||||
}
|
||||
}
|
||||
flavorGroups = flavorGroupTemp
|
||||
|
||||
calculateFlavorCombination()
|
||||
if (combinedProductFlavors.size() == extension.productFlavors.size()) {
|
||||
singleDimension = true
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateFlavorCombination() {
|
||||
combinedProductFlavors = new ArrayList<>()
|
||||
combinedProductFlavorsMap = new HashMap<>()
|
||||
|
||||
if (flavorGroups.size() == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
List<Integer> combination = new ArrayList<Integer>()
|
||||
int n = flavorGroups.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
combination.add(0);
|
||||
}
|
||||
int i = 0;
|
||||
boolean isContinue = true;
|
||||
while (isContinue) {
|
||||
List<String> items = new ArrayList<>()
|
||||
String item = flavorGroups.get(0).get(combination.get(0))
|
||||
items.add(item)
|
||||
String combined = item
|
||||
for (int j = 1; j < n; j++) {
|
||||
item = flavorGroups.get(j).get(combination.get(j))
|
||||
combined += Utils.upperCase(item)
|
||||
items.add(item)
|
||||
}
|
||||
combinedProductFlavors.add(combined)
|
||||
combinedProductFlavorsMap.put(combined, items)
|
||||
i++;
|
||||
combination.set(n - 1, i);
|
||||
for (int j = n - 1; j >= 0; j--) {
|
||||
if (combination.get(j) >= flavorGroups.get(j).size()) {
|
||||
combination.set(j, 0);
|
||||
i = 0;
|
||||
if (j - 1 >= 0) {
|
||||
combination.set(j - 1, combination.get(j - 1) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
isContinue = false;
|
||||
for (Integer integer : combination) {
|
||||
if (integer != 0) {
|
||||
isContinue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.plugin.pins
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.w3c.dom.Element
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
class Utils {
|
||||
|
||||
static String upperCase(String str) {
|
||||
char[] ch = str.toCharArray()
|
||||
if (ch[0] >= 'a' && ch[0] <= 'z') {
|
||||
ch[0] -= 32
|
||||
}
|
||||
return String.valueOf(ch)
|
||||
}
|
||||
|
||||
static String getAndroidManifestPackageName(File androidManifest) {
|
||||
def builderFactory = DocumentBuilderFactory.newInstance()
|
||||
builderFactory.setNamespaceAware(true)
|
||||
Element manifestXml = builderFactory.newDocumentBuilder().parse(androidManifest).documentElement
|
||||
return manifestXml.getAttribute("package")
|
||||
}
|
||||
|
||||
static MicroModule buildMicroModule(Project project, String microModulePath) {
|
||||
String[] pathElements = removeTrailingColon(microModulePath).split(":")
|
||||
int pathElementsLen = pathElements.size()
|
||||
File parentMicroModuleDir = project.projectDir
|
||||
for (int j = 0; j < pathElementsLen; j++) {
|
||||
parentMicroModuleDir = new File(parentMicroModuleDir, pathElements[j])
|
||||
}
|
||||
File microModuleDir = parentMicroModuleDir.canonicalFile
|
||||
String microModuleName = microModuleDir.absolutePath.replace(project.projectDir.absolutePath, "")
|
||||
if (File.separator == "\\") {
|
||||
microModuleName = microModuleName.replaceAll("\\\\", ":")
|
||||
} else {
|
||||
microModuleName = microModuleName.replaceAll("/", ":")
|
||||
}
|
||||
if (!microModuleDir.exists()) {
|
||||
return null
|
||||
}
|
||||
MicroModule microModule = new MicroModule()
|
||||
microModule.name = microModuleName
|
||||
microModule.microModuleDir = microModuleDir
|
||||
return microModule
|
||||
}
|
||||
|
||||
private static String removeTrailingColon(String microModulePath) {
|
||||
return microModulePath.startsWith(":") ? microModulePath.substring(1) : microModulePath
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.plugin.pins.check
|
||||
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.NodeList
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.OutputKeys
|
||||
import javax.xml.transform.Transformer
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
class CheckManifest {
|
||||
|
||||
Document document
|
||||
Element rootElement
|
||||
|
||||
String packageName
|
||||
Map<String, MicroModuleFile> lastModifiedResourcesMap
|
||||
Map<String, MicroModuleFile> lastModifiedClassesMap
|
||||
|
||||
void load(File sourceFile) {
|
||||
if (!sourceFile.exists()) return
|
||||
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance()
|
||||
document = builderFactory.newDocumentBuilder().parse(sourceFile)
|
||||
rootElement = document.documentElement
|
||||
packageName = rootElement.getAttribute("package")
|
||||
}
|
||||
|
||||
void setResourcesLastModified(long lastModified) {
|
||||
resourcesLastModified = lastModified
|
||||
}
|
||||
|
||||
Map<String, MicroModuleFile> getResourcesMap() {
|
||||
if (lastModifiedResourcesMap != null) return lastModifiedResourcesMap
|
||||
|
||||
lastModifiedResourcesMap = new HashMap<>()
|
||||
if (rootElement == null) return lastModifiedResourcesMap
|
||||
|
||||
NodeList resourcesNodeList = rootElement.getElementsByTagName("resources")
|
||||
if (resourcesNodeList.length == 0) {
|
||||
return lastModifiedResourcesMap
|
||||
}
|
||||
Element resourcesElement = (Element) resourcesNodeList.item(0)
|
||||
NodeList fileNodeList = resourcesElement.getElementsByTagName("file")
|
||||
for (int i = 0; i < fileNodeList.getLength(); i++) {
|
||||
Element fileElement = (Element) fileNodeList.item(i)
|
||||
MicroModuleFile microModuleFile = new MicroModuleFile()
|
||||
microModuleFile.name = fileElement.getAttribute("name")
|
||||
microModuleFile.microModuleName = fileElement.getAttribute("microModuleName")
|
||||
microModuleFile.path = fileElement.getAttribute("path")
|
||||
microModuleFile.lastModified = fileElement.getAttribute("lastModified").toLong()
|
||||
lastModifiedResourcesMap.put(microModuleFile.path, microModuleFile)
|
||||
}
|
||||
return lastModifiedResourcesMap
|
||||
}
|
||||
|
||||
Map<String, MicroModuleFile> getClassesMap() {
|
||||
if (lastModifiedClassesMap != null) return lastModifiedClassesMap
|
||||
|
||||
lastModifiedClassesMap = new HashMap<>()
|
||||
if (rootElement == null) return lastModifiedClassesMap
|
||||
|
||||
NodeList classesNodeList = rootElement.getElementsByTagName("classes")
|
||||
if (classesNodeList.length == 0) {
|
||||
return lastModifiedClassesMap
|
||||
}
|
||||
Element classesElement = (Element) classesNodeList.item(0)
|
||||
NodeList fileNodeList = classesElement.getElementsByTagName("file")
|
||||
for (int i = 0; i < fileNodeList.getLength(); i++) {
|
||||
Element fileElement = (Element) fileNodeList.item(i)
|
||||
MicroModuleFile microModuleFile = new MicroModuleFile()
|
||||
microModuleFile.name = fileElement.getAttribute("name")
|
||||
microModuleFile.microModuleName = fileElement.getAttribute("microModuleName")
|
||||
microModuleFile.path = fileElement.getAttribute("path")
|
||||
microModuleFile.lastModified = fileElement.getAttribute("lastModified").toLong()
|
||||
lastModifiedClassesMap.put(microModuleFile.path, microModuleFile)
|
||||
}
|
||||
return lastModifiedClassesMap
|
||||
}
|
||||
|
||||
void save(File destFile) {
|
||||
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance()
|
||||
Document documentTemp = builderFactory.newDocumentBuilder().newDocument()
|
||||
Element microModuleXmlTemp = documentTemp.createElement("micro-module")
|
||||
microModuleXmlTemp.setAttribute("package", packageName)
|
||||
// resources
|
||||
Element resourcesElement = documentTemp.createElement("resources")
|
||||
microModuleXmlTemp.appendChild(resourcesElement)
|
||||
if (lastModifiedResourcesMap != null) {
|
||||
lastModifiedResourcesMap.each {
|
||||
MicroModuleFile resourceFile = it.value
|
||||
Element fileElement = documentTemp.createElement("file")
|
||||
fileElement.setAttribute("name", resourceFile.name)
|
||||
fileElement.setAttribute("path", resourceFile.path)
|
||||
fileElement.setAttribute("lastModified", resourceFile.lastModified.toString())
|
||||
fileElement.setAttribute("microModuleName", resourceFile.microModuleName)
|
||||
resourcesElement.appendChild(fileElement)
|
||||
}
|
||||
}
|
||||
|
||||
// classes
|
||||
if (lastModifiedClassesMap != null) {
|
||||
Element classesElement = documentTemp.createElement("classes")
|
||||
microModuleXmlTemp.appendChild(classesElement)
|
||||
lastModifiedClassesMap.each {
|
||||
MicroModuleFile resourceFile = it.value
|
||||
Element fileElement = documentTemp.createElement("file")
|
||||
fileElement.setAttribute("name", resourceFile.name)
|
||||
fileElement.setAttribute("path", resourceFile.path)
|
||||
fileElement.setAttribute("lastModified", resourceFile.lastModified.toString())
|
||||
fileElement.setAttribute("microModuleName", resourceFile.microModuleName)
|
||||
classesElement.appendChild(fileElement)
|
||||
}
|
||||
microModuleXmlTemp.appendChild(classesElement)
|
||||
} else if (rootElement != null) {
|
||||
NodeList classesNodeList = rootElement.getElementsByTagName("classes")
|
||||
if (classesNodeList.length == 1) {
|
||||
Element classesElement = (Element) classesNodeList.item(0)
|
||||
microModuleXmlTemp.appendChild(documentTemp.importNode(classesElement, true))
|
||||
}
|
||||
}
|
||||
// save
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer()
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes")
|
||||
transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "yes")
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
|
||||
transformer.transform(new DOMSource(microModuleXmlTemp), new StreamResult(destFile))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
package com.plugin.pins.check
|
||||
|
||||
import com.plugin.pins.MicroModule
|
||||
import com.plugin.pins.MicroModuleInfo
|
||||
import com.plugin.pins.ProductFlavorInfo
|
||||
import org.gradle.api.GradleScriptException
|
||||
import org.gradle.api.Project
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.NodeList
|
||||
|
||||
class CodeChecker {
|
||||
|
||||
Project project
|
||||
MicroModuleInfo microModuleInfo
|
||||
ProductFlavorInfo productFlavorInfo
|
||||
|
||||
String buildType
|
||||
String productFlavor
|
||||
|
||||
CheckManifest checkManifest
|
||||
ResourceMerged resourceMerged
|
||||
|
||||
String errorMessage = ""
|
||||
String lineSeparator = System.getProperty("line.separator")
|
||||
|
||||
Map<String, List<String>> microModulePackageNameMap
|
||||
|
||||
CodeChecker(Project project, MicroModuleInfo microModuleInfo, ProductFlavorInfo productFlavorInfo, String buildType, String productFlavor) {
|
||||
this.project = project
|
||||
this.microModuleInfo = microModuleInfo
|
||||
this.productFlavorInfo = productFlavorInfo
|
||||
this.buildType = buildType
|
||||
this.productFlavor = productFlavor
|
||||
this.checkManifest = getModuleCheckManifest()
|
||||
}
|
||||
|
||||
void checkResources(String mergeResourcesTaskName, List<String> sourceFolders) {
|
||||
resourceMerged = new ResourceMerged()
|
||||
if (!resourceMerged.load(project.projectDir, mergeResourcesTaskName)) {
|
||||
return
|
||||
}
|
||||
|
||||
List<NodeList> resourceNodeLists = resourceMerged.getResourcesNodeList(sourceFolders)
|
||||
List<File> modifiedResourcesList = getModifiedResourcesList(resourceNodeLists)
|
||||
if (modifiedResourcesList.size() == 0) {
|
||||
return
|
||||
}
|
||||
handleModifiedResources(modifiedResourcesList)
|
||||
if (errorMessage != "") {
|
||||
throw new GradleScriptException(errorMessage, null)
|
||||
}
|
||||
|
||||
def manifest = new File(microModuleInfo.mainMicroModule.microModuleDir, "src/main/AndroidManifest.xml")
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
checkManifest.packageName = packageName
|
||||
saveModuleCheckManifest()
|
||||
}
|
||||
|
||||
List<File> getModifiedResourcesList(List<NodeList> resourcesNodeList) {
|
||||
Map<String, MicroModuleFile> lastModifiedResourcesMap = checkManifest.getResourcesMap()
|
||||
List<File> modifiedResourcesList = new ArrayList<>()
|
||||
if (resourcesNodeList == null || resourcesNodeList.length == 0) return modifiedResourcesList
|
||||
|
||||
resourcesNodeList.each {
|
||||
for (int i = 0; i < it.getLength(); i++) {
|
||||
Element resourcesElement = (Element) it.item(i)
|
||||
NodeList fileNodeList = resourcesElement.getElementsByTagName("file")
|
||||
for (int j = 0; j < fileNodeList.getLength(); j++) {
|
||||
Element fileElement = (Element) fileNodeList.item(j)
|
||||
String filePath = fileElement.getAttribute("path")
|
||||
if (filePath != null && filePath.endsWith(".xml")) {
|
||||
File file = project.file(filePath)
|
||||
MicroModuleFile resourceFile = lastModifiedResourcesMap.get(filePath)
|
||||
def currentModified = file.lastModified()
|
||||
if (resourceFile == null || resourceFile.lastModified.longValue() < currentModified) {
|
||||
modifiedResourcesList.add(file)
|
||||
|
||||
if (resourceFile == null) {
|
||||
resourceFile = new MicroModuleFile()
|
||||
resourceFile.name = file.name
|
||||
resourceFile.path = filePath
|
||||
resourceFile.microModuleName = getMicroModuleName(filePath)
|
||||
lastModifiedResourcesMap.put(filePath, resourceFile)
|
||||
}
|
||||
resourceFile.lastModified = currentModified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modifiedResourcesList
|
||||
}
|
||||
|
||||
void handleModifiedResources(List<File> modifiedResourcesList) {
|
||||
Map<String, String> resourcesMap = resourceMerged.getResourcesMap()
|
||||
def resourcesPattern = /@(dimen|drawable|color|string|style|id|mipmap|layout)\/[A-Za-z0-9_]+/
|
||||
modifiedResourcesList.each {
|
||||
String text = it.text
|
||||
List<String> textLines = text.readLines()
|
||||
def matcher = (text =~ resourcesPattern)
|
||||
def absolutePath = it.absolutePath
|
||||
def microModuleName = getMicroModuleName(absolutePath)
|
||||
while (matcher.find()) {
|
||||
def find = matcher.group()
|
||||
def name = find.substring(find.indexOf("/") + 1)
|
||||
def from = resourcesMap.get(name)
|
||||
if (from != null && microModuleName != from && !microModuleInfo.hasDependency(microModuleName, from)) {
|
||||
List<Number> lines = textLines.findIndexValues { it.contains(find) }
|
||||
lines.each {
|
||||
def lineIndex = it.intValue()
|
||||
def lineContext = textLines.get(lineIndex).trim()
|
||||
if (lineContext.startsWith("<!--")) {
|
||||
return
|
||||
}
|
||||
|
||||
def message = absolutePath + ':' + (lineIndex + 1)
|
||||
if (!errorMessage.contains(message)) {
|
||||
message += lineSeparator
|
||||
message += "- cannot use [" + find + "] which from MicroModule '${from}'."
|
||||
message += lineSeparator
|
||||
errorMessage += message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkClasses(String mergeResourcesTaskName, List<String> sourceFolders) {
|
||||
if(resourceMerged == null) {
|
||||
resourceMerged = new ResourceMerged()
|
||||
if (!resourceMerged.load(project.projectDir, mergeResourcesTaskName)) {
|
||||
return
|
||||
}
|
||||
resourceMerged.getResourcesNodeList(sourceFolders)
|
||||
}
|
||||
|
||||
List<File> modifiedClassesList = getModifiedClassesList(sourceFolders)
|
||||
if (modifiedClassesList.size() == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (resourceMerged == null) {
|
||||
resourceMerged = new ResourceMerged()
|
||||
if (!resourceMerged.load(project.projectDir, mergeResourcesTaskName)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
handleModifiedClasses(modifiedClassesList)
|
||||
if (errorMessage != "") {
|
||||
throw new GradleScriptException(errorMessage, null)
|
||||
}
|
||||
saveModuleCheckManifest()
|
||||
}
|
||||
|
||||
List<File> getModifiedClassesList(List<String> sourceFolders) {
|
||||
Map<String, MicroModuleFile> lastModifiedClassesMap = checkManifest.getClassesMap()
|
||||
List<File> modifiedClassesList = new ArrayList<>()
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
sourceFolders.each {
|
||||
File javaDir = new File(microModule.microModuleDir, "/src/${it}/java")
|
||||
if (javaDir.exists()) {
|
||||
getModifiedJavaFile(javaDir, modifiedClassesList, lastModifiedClassesMap)
|
||||
}
|
||||
File kotlinDir = new File(microModule.microModuleDir, "/src/${it}/kotlin")
|
||||
if (kotlinDir.exists()) {
|
||||
getModifiedJavaFile(kotlinDir, modifiedClassesList, lastModifiedClassesMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
return modifiedClassesList
|
||||
}
|
||||
|
||||
void getModifiedJavaFile(File directory, List<File> modifiedClassesList, Map<String, MicroModuleFile> lastModifiedClassesMap) {
|
||||
directory.listFiles().each {
|
||||
if (it.isDirectory()) {
|
||||
getModifiedJavaFile(it, modifiedClassesList, lastModifiedClassesMap)
|
||||
} else {
|
||||
def currentModified = it.lastModified()
|
||||
MicroModuleFile resourceFile = lastModifiedClassesMap.get(it.absolutePath)
|
||||
if (resourceFile == null || resourceFile.lastModified.longValue() < currentModified) {
|
||||
modifiedClassesList.add(it)
|
||||
|
||||
if (resourceFile == null) {
|
||||
resourceFile = new MicroModuleFile()
|
||||
resourceFile.name = it.name
|
||||
resourceFile.path = it.absolutePath
|
||||
resourceFile.microModuleName = getMicroModuleName(it.absolutePath)
|
||||
lastModifiedClassesMap.put(it.absolutePath, resourceFile)
|
||||
}
|
||||
resourceFile.lastModified = it.lastModified()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleModifiedClasses(List<File> modifiedClassesList) {
|
||||
Map<String, String> resourcesMap = resourceMerged.getResourcesMap()
|
||||
Map<String, String> classesMap = new HashMap<>()
|
||||
checkManifest.getClassesMap().each {
|
||||
MicroModuleFile resourceFile = it.value
|
||||
def name = getClassFullName(resourceFile.path)
|
||||
classesMap.put(name, resourceFile.microModuleName)
|
||||
}
|
||||
|
||||
initMicroModulePackageName()
|
||||
|
||||
def resourcesPattern = /R.(dimen|drawable|color|string|style|id|mipmap|layout).[A-Za-z0-9_]+|import\s[A-Za-z0-9_.]+/
|
||||
modifiedClassesList.each {
|
||||
String text = it.text
|
||||
List<String> textLines = text.readLines()
|
||||
def matcher = (text =~ resourcesPattern)
|
||||
def absolutePath = it.absolutePath
|
||||
def microModuleName = getMicroModuleName(absolutePath)
|
||||
while (matcher.find()) {
|
||||
matcher
|
||||
def find = matcher.group()
|
||||
def from, name
|
||||
if (find.startsWith("R")) {
|
||||
name = find.substring(find.lastIndexOf(".") + 1)
|
||||
from = resourcesMap.get(name)
|
||||
} else if (find.startsWith("import")) {
|
||||
name = find.substring(find.lastIndexOf(" ") + 1, find.length())
|
||||
if(name.endsWith('.R')) {
|
||||
continue
|
||||
}
|
||||
from = classesMap.get(name)
|
||||
}
|
||||
|
||||
if (from != null && microModuleName != from && !microModuleInfo.hasDependency(microModuleName, from)) {
|
||||
List<Number> lines = textLines.findIndexValues { it.contains(find) }
|
||||
lines.each {
|
||||
def lineIndex = it.intValue()
|
||||
def lineContext = textLines.get(lineIndex).trim()
|
||||
if (lineContext.startsWith("//") || lineContext.startsWith("/*")) {
|
||||
return
|
||||
}
|
||||
|
||||
def message = absolutePath + ':' + (lineIndex + 1)
|
||||
if (!errorMessage.contains(message)) {
|
||||
message += lineSeparator
|
||||
message += "- cannot use [" + find + "] which from MicroModule '${from}'."
|
||||
message += lineSeparator
|
||||
errorMessage += message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getClassFullName(String path) {
|
||||
String microModulePath = path.replace(project.projectDir.absolutePath, "")
|
||||
if (microModulePath.startsWith(File.separator)) {
|
||||
microModulePath = microModulePath.substring(microModulePath.indexOf(File.separator) + 1)
|
||||
}
|
||||
String scrPath = microModulePath.substring(microModulePath.indexOf(File.separator) + 1)
|
||||
String variantPath = scrPath.substring(scrPath.indexOf(File.separator) + 1)
|
||||
String javaPath = variantPath.substring(variantPath.indexOf(File.separator) + 1)
|
||||
String classPath = javaPath.substring(javaPath.indexOf(File.separator) + 1)
|
||||
return classPath.substring(0, classPath.lastIndexOf(".")).replace(File.separator, ".")
|
||||
}
|
||||
|
||||
String getMicroModuleName(String absolutePath) {
|
||||
String moduleName = absolutePath.replace(project.projectDir.absolutePath, "")
|
||||
moduleName = moduleName.substring(0, moduleName.indexOf(ResourceMerged.SRC))
|
||||
if (File.separator == "\\") {
|
||||
moduleName = moduleName.replaceAll("\\\\", ":")
|
||||
} else {
|
||||
moduleName = moduleName.replaceAll("/", ":")
|
||||
}
|
||||
return moduleName
|
||||
}
|
||||
|
||||
private CheckManifest getModuleCheckManifest() {
|
||||
CheckManifest checkManifest = new CheckManifest()
|
||||
StringBuilder stringBuilder = new StringBuilder('build/microModule/code-check/')
|
||||
if (productFlavor != null) {
|
||||
stringBuilder.append(productFlavor)
|
||||
stringBuilder.append('/')
|
||||
}
|
||||
stringBuilder.append(buildType)
|
||||
new File(project.projectDir, stringBuilder.toString()).mkdirs()
|
||||
stringBuilder.append('/check-manifest.xml')
|
||||
File manifest = new File(project.projectDir, stringBuilder.toString())
|
||||
checkManifest.load(manifest)
|
||||
return checkManifest
|
||||
}
|
||||
|
||||
private CheckManifest saveModuleCheckManifest() {
|
||||
if (checkManifest == null) {
|
||||
checkManifest = new CheckManifest()
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder('build/microModule/code-check/')
|
||||
if (productFlavor != null) {
|
||||
stringBuilder.append(productFlavor)
|
||||
stringBuilder.append('/')
|
||||
}
|
||||
stringBuilder.append(buildType)
|
||||
new File(project.projectDir, stringBuilder.toString()).mkdirs()
|
||||
stringBuilder.append('/check-manifest.xml')
|
||||
File manifest = new File(project.projectDir, stringBuilder.toString())
|
||||
return checkManifest.save(manifest)
|
||||
}
|
||||
|
||||
private String initMicroModulePackageName() {
|
||||
microModulePackageNameMap = new HashMap<>()
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
boolean find = false
|
||||
List<String> flavorList = productFlavorInfo.combinedProductFlavorsMap.get(productFlavor)
|
||||
if (flavorList != null && !flavorList.isEmpty()) {
|
||||
for (String flavor : flavorList) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/${flavor}/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
List<String> microModuleList = microModulePackageNameMap.get(packageName)
|
||||
if (microModuleList == null) {
|
||||
microModuleList = new ArrayList<>()
|
||||
microModulePackageNameMap.put(packageName, microModuleList)
|
||||
}
|
||||
microModuleList.add(microModule.name)
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!find) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/${buildType}/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
List<String> microModuleList = microModulePackageNameMap.get(packageName)
|
||||
if (microModuleList == null) {
|
||||
microModuleList = new ArrayList<>()
|
||||
microModulePackageNameMap.put(packageName, microModuleList)
|
||||
}
|
||||
microModuleList.add(microModule.name)
|
||||
find = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!find) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/main/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
List<String> microModuleList = microModulePackageNameMap.get(packageName)
|
||||
if (microModuleList == null) {
|
||||
microModuleList = new ArrayList<>()
|
||||
microModulePackageNameMap.put(packageName, microModuleList)
|
||||
}
|
||||
microModuleList.add(microModule.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.plugin.pins.check
|
||||
|
||||
class MicroModuleFile {
|
||||
String path
|
||||
String name
|
||||
Long lastModified
|
||||
String microModuleName
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.plugin.pins.check
|
||||
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.NodeList
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
class ResourceMerged {
|
||||
|
||||
static String SRC = File.separator + "src" + File.separator
|
||||
|
||||
String projectPath
|
||||
File resourcesMergerFile
|
||||
|
||||
List<NodeList> resourceNodeLists
|
||||
Map<String, String> resourcesMap
|
||||
|
||||
boolean load(File projectDir, String mergeResourcesTaskName) {
|
||||
projectPath = projectDir.absolutePath
|
||||
String mergedPath = "build/intermediates/incremental/${mergeResourcesTaskName}/merger.xml"
|
||||
resourcesMergerFile = new File(projectDir, mergedPath)
|
||||
return resourcesMergerFile.exists()
|
||||
}
|
||||
|
||||
List<NodeList> getResourcesNodeList(List<String> sourceFolders) {
|
||||
if (resourceNodeLists == null) {
|
||||
resourceNodeLists = new ArrayList<>()
|
||||
} else {
|
||||
return resourceNodeLists
|
||||
}
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()
|
||||
DocumentBuilder builder = factory.newDocumentBuilder()
|
||||
|
||||
FileInputStream inputStream = new FileInputStream(resourcesMergerFile)
|
||||
Document doc = builder.parse(inputStream)
|
||||
Element rootElement = doc.getDocumentElement()
|
||||
|
||||
NodeList dataSetNodeList = rootElement.getElementsByTagName("dataSet")
|
||||
for (int i = 0; i < dataSetNodeList.getLength(); i++) {
|
||||
Element dataSetElement = (Element) dataSetNodeList.item(i)
|
||||
def config = dataSetElement.getAttribute("config")
|
||||
if (sourceFolders.contains(config)) {
|
||||
resourceNodeLists.add(dataSetElement.getElementsByTagName("source"))
|
||||
}
|
||||
}
|
||||
return resourceNodeLists
|
||||
}
|
||||
|
||||
Map<String, String> getResourcesMap() {
|
||||
if (resourcesMap != null) return resourcesMap
|
||||
|
||||
Map<String, String> resourcesMap = new HashMap<String, String>()
|
||||
if (resourceNodeLists == null || resourceNodeLists.length == 0) {
|
||||
return resourcesMap
|
||||
}
|
||||
|
||||
resourceNodeLists.each {
|
||||
int length = it.length
|
||||
for (int i = 0; i < length; i++) {
|
||||
Element resourcesElement = (Element) it.item(i)
|
||||
String path = resourcesElement.getAttribute("path")
|
||||
String moduleName = path.replace(projectPath, "")
|
||||
if (moduleName.startsWith(File.separator + "build")) continue
|
||||
|
||||
moduleName = moduleName.substring(0, moduleName.indexOf(SRC))
|
||||
if (File.separator == "\\") {
|
||||
moduleName = moduleName.replaceAll("\\\\", ":")
|
||||
} else {
|
||||
moduleName = moduleName.replaceAll("/", ":")
|
||||
}
|
||||
NodeList fileNodeList = resourcesElement.getElementsByTagName("file")
|
||||
def fileNodeLength = fileNodeList.getLength()
|
||||
if (fileNodeLength <= 0) {
|
||||
continue
|
||||
}
|
||||
for (int j = 0; j < fileNodeLength; j++) {
|
||||
Element fileElement = (Element) fileNodeList.item(j)
|
||||
String name = fileElement.getAttribute("name")
|
||||
if (name == "") {
|
||||
NodeList nodeList = fileElement.getChildNodes()
|
||||
def nodeLength = nodeList.getLength()
|
||||
if (nodeLength <= 0) {
|
||||
continue
|
||||
}
|
||||
for (int k = 0; k < nodeLength; k++) {
|
||||
Element childElement = (Element) nodeList.item(k)
|
||||
name = childElement.getAttribute("name")
|
||||
resourcesMap.put(name, moduleName)
|
||||
}
|
||||
} else {
|
||||
resourcesMap.put(name, moduleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resourcesMap
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.plugin.pins.extension
|
||||
|
||||
import com.plugin.pins.MicroModule
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
|
||||
class DefaultMicroModuleExtension implements MicroModuleExtension {
|
||||
|
||||
Project project
|
||||
OnMicroModuleListener onMicroModuleListener
|
||||
|
||||
boolean codeCheckEnabled = true
|
||||
|
||||
DefaultMicroModuleExtension(Project project) {
|
||||
this.project = project
|
||||
}
|
||||
|
||||
@Override
|
||||
void codeCheckEnabled(boolean enabled) {
|
||||
this.codeCheckEnabled = enabled
|
||||
}
|
||||
|
||||
@Override
|
||||
void export(String... microModulePaths) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
onMicroModuleListener.addExportMicroModule(microModulePaths)
|
||||
}
|
||||
|
||||
@Override
|
||||
void include(String... microModulePaths) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
int size = microModulePaths.size()
|
||||
for (int i = 0; i < size; i++) {
|
||||
MicroModule microModule = Utils.buildMicroModule(project, microModulePaths[i])
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${microModulePaths[i]}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
onMicroModuleListener.addIncludeMicroModule(microModule, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void includeMain(String microModulePath) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
MicroModule microModule = Utils.buildMicroModule(project, microModulePath)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${microModulePath}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
onMicroModuleListener.addIncludeMicroModule(microModule, true)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.plugin.pins.extension
|
||||
|
||||
interface MicroModuleExtension {
|
||||
|
||||
void codeCheckEnabled(boolean disable)
|
||||
|
||||
void export(String... microModulePaths)
|
||||
|
||||
void includeMain(String microModulePath)
|
||||
|
||||
void include(String... microModulePaths)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.plugin.pins.extension
|
||||
|
||||
import com.plugin.pins.MicroModule
|
||||
|
||||
|
||||
interface OnMicroModuleListener {
|
||||
|
||||
void addIncludeMicroModule(MicroModule microModule, boolean mainMicroModule)
|
||||
|
||||
void addExportMicroModule(String... microModulePaths)
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
//include ':component-plugin'
|
||||
|
||||
//调试插件
|
||||
//includeBuild './component-plugin'
|
||||
includeBuild './component-plugin'
|
||||
//
|
||||
include ':app'
|
||||
include ':debugModule'
|
||||
|
||||
Reference in New Issue
Block a user