Skip to content

Commit

Permalink
【Mis重构】增加对mis publication 循环依赖的检测
Browse files Browse the repository at this point in the history
  • Loading branch information
yangchengdong committed May 31, 2019
1 parent 21cd37b commit 1c37f69
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,7 @@ class MisPlugin implements Plugin<Project> {
@Override
void onPublicationAdded(Project childProject, Publication publication) {
initPublication(childProject, publication)

if (publication.version != null) {
handleMavenJar(childProject, publication)
} else {
handleLocalJar(childProject, publication)
}
publicationManager.hitPublication(publication)
publicationManager.addDependencyGraph(publication)
}
})

Expand All @@ -82,6 +76,11 @@ class MisPlugin implements Plugin<Project> {

androidJarPath = MisUtil.getAndroidJarPath(project, misExtension.compileSdkVersion)

com.eastwood.tools.plugins.mis.core.extension.Dependencies.metaClass.misPublication { String value ->
String[] gav = MisUtil.filterGAV(value)
return 'mis-' + gav[0] + ':' + gav[1] + ':' + gav[2]
}

project.childProjects.each {
Project childProject = it.value
def misScript = childProject.file('mis.gradle')
Expand All @@ -91,6 +90,26 @@ class MisPlugin implements Plugin<Project> {
}
}

List<String> topSort = publicationManager.dependencyGraph.topSort()
Collections.reverse(topSort)
topSort.each {
Publication publication = publicationManager.publicationDependencies.get(it)
if (publication == null) {
return
}

Project childProject = project.findProject(publication.project)

filterPublicationDependencies(publication)

if (publication.version != null) {
handleMavenJar(childProject, publication)
} else {
handleLocalJar(childProject, publication)
}
publicationManager.hitPublication(publication)
}

}
return
}
Expand All @@ -99,13 +118,8 @@ class MisPlugin implements Plugin<Project> {
throw new GradleException("The android or android-library plugin must be applied to the project.")
}

com.eastwood.tools.plugins.mis.core.extension.Dependencies.metaClass.misPublication { String value ->
String[] gav = filterGAV(value)
return getPublication(gav)
}

project.dependencies.metaClass.misPublication { Object value ->
String[] gav = filterGAV(value)
String[] gav = MisUtil.filterGAV(value)
return getPublication(gav)
}

Expand Down Expand Up @@ -138,44 +152,54 @@ class MisPlugin implements Plugin<Project> {
createPublishTask(it)
}
}

}
}

String[] filterGAV(Object value) {
String groupId = null, artifactId = null, version = null
if (value instanceof String) {
String[] values = value.split(":")
if (values.length >= 3) {
groupId = values[0]
artifactId = values[1]
version = values[2]
} else if (values.length == 2) {
groupId = values[0]
artifactId = values[1]
version = null
def filterPublicationDependencies(Publication publication) {
if (publication.dependencies != null) {
if (publication.dependencies.compileOnly != null) {
List<Object> compileOnly = new ArrayList<>()
publication.dependencies.compileOnly.each {
if (it instanceof String && it.startsWith('mis-')) {
String[] gav = MisUtil.filterGAV(it.replace('mis-', ''))
Publication existPublication = publicationManager.getPublicationByKey(gav[0] + '-' + gav[1])
if (existPublication != null) {
if (existPublication.useLocal) {
compileOnly.add(':mis-' + existPublication.groupId + '-' + existPublication.artifactId + ':')
} else {
compileOnly.add(existPublication.groupId + ':' + existPublication.artifactId + ':' + existPublication.version)
}
}
} else {
compileOnly.add(it)
}
}
publication.dependencies.compileOnly = compileOnly
}
if (publication.dependencies.implementation != null) {
List<Object> implementation = new ArrayList<>()
publication.dependencies.implementation.each {
if (it instanceof String && it.startsWith('mis-')) {
String[] gav = MisUtil.filterGAV(it.replace('mis-', ''))
Publication existPublication = publicationManager.getPublicationByKey(gav[0] + '-' + gav[1])
if (existPublication != null) {
if (existPublication.useLocal) {
implementation.add(':mis-' + existPublication.groupId + '-' + existPublication.artifactId + ':')
} else {
implementation.add(existPublication.groupId + ':' + existPublication.artifactId + ':' + existPublication.version)
}
}
} else {
implementation.add(it)
}
}
publication.dependencies.implementation = implementation
}
} else if (value instanceof Map<String, ?>) {
groupId = value.groupId
artifactId = value.artifactId
version = value.version
}

if (version == "") {
version = null
}

if (groupId == null || artifactId == null) {
throw new IllegalArgumentException("'${value}' is illege argument of misPublication(), the following types/formats are supported:" +
"\n - String or CharSequence values, for example 'org.gradle:gradle-core:1.0'." +
"\n - Maps, for example [groupId: 'org.gradle', artifactId: 'gradle-core', version: '1.0'].")
}

return [groupId, artifactId, version]
}

def handleLocalJar(Project project, Publication publication) {
File target = new File(misDir, "mis-${publication.groupId}-${publication.artifactId}.jar")
File target = new File(misDir, 'mis-' + publication.groupId + '-' + publication.artifactId + '.jar')

if (publication.invalid) {
publicationManager.addPublication(publication)
Expand Down Expand Up @@ -212,7 +236,7 @@ class MisPlugin implements Plugin<Project> {
}

def handleMavenJar(Project project, Publication publication) {
File target = new File(misDir, "mis-${publication.groupId}-${publication.artifactId}.jar")
File target = new File(misDir, 'mis-' + publication.groupId + '-' + publication.artifactId + '.jar')
if (publication.invalid) {
publicationManager.addPublication(publication)
if (target.exists()) {
Expand Down Expand Up @@ -280,7 +304,7 @@ class MisPlugin implements Plugin<Project> {
if (publication.sourceSetName.contains('/')) {
misDir = project.file(publication.sourceSetName + '/mis/')
} else {
misDir = project.file("src/${publication.sourceSetName}/mis/")
misDir = project.file('src/' + publication.sourceSetName + '/mis/')
}
misSourceSet.path = misDir.absolutePath
misSourceSet.lastModifiedSourceFile = new HashMap<>()
Expand All @@ -303,9 +327,9 @@ class MisPlugin implements Plugin<Project> {
if (publication.invalid) {
return []
} else if (publication.useLocal) {
return ":mis-${publication.groupId}-${publication.artifactId}:"
return ':mis-' + publication.groupId + '-' + publication.artifactId + ':'
} else {
return "${publication.groupId}:${publication.artifactId}:${publication.version}"
return publication.groupId + ':' + publication.artifactId + ':' + publication.version
}
} else {
return []
Expand All @@ -329,21 +353,21 @@ class MisPlugin implements Plugin<Project> {
}

void createPublishTask(Publication publication) {
def taskName = "compileMis[${publication.artifactId}]Source"
def taskName = 'compileMis[' + publication.artifactId + ']Source'
def compileTask = project.getTasks().findByName(taskName)
if (compileTask == null) {
compileTask = project.getTasks().create(taskName, CompileMisTask.class)
compileTask.publication = publication
compileTask.dependsOn 'clean'
}

def publicationName = "Mis[${publication.artifactId}]"
def publicationName = 'Mis[' + publication.artifactId + ']'
String publishTaskNamePrefix = "publish${publicationName}PublicationTo"
project.tasks.whenTaskAdded {
if (it.name.startsWith(publishTaskNamePrefix)) {
it.dependsOn compileTask
it.doLast {
new File(misDir, "mis-${publication.groupId}-${publication.artifactId}.jar").delete()
new File(misDir, 'mis-' + publication.groupId + '-' + publication.artifactId + '.jar').delete()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package com.eastwood.tools.plugins.mis.core;

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.
* <p>
* 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));
// }
}
Loading

0 comments on commit 1c37f69

Please sign in to comment.