Parcourir la source

init from phab

xielq il y a 4 ans
Parent
commit
3c1ee9ebc7

+ 0 - 0
README.md


+ 90 - 0
pom.xml

@@ -0,0 +1,90 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.uas.plugins</groupId>
+    <artifactId>ops-diff-maven-plugin</artifactId>
+    <version>0.0.1</version>
+    <packaging>maven-plugin</packaging>
+    <description>maven插件,在mvn install时,生成与仓库最新文件的差异包</description>
+    <name>ops-diff-maven-plugin</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.7</maven.compiler.source>
+        <maven.compiler.target>1.7</maven.compiler.target>
+        <maven.version>3.3.9</maven.version>
+        <skipTests>true</skipTests>
+        <maven.plugin.version>3.3</maven.plugin.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>${maven.plugin.version}</version>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- Provided -->
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.2.3</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <version>3.3</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.tmatesoft.svnkit</groupId>
+            <artifactId>svnkit</artifactId>
+            <version>1.8.10</version>
+        </dependency>
+    </dependencies>
+
+    <distributionManagement>
+        <!-- 发布release仓库 -->
+        <repository>
+            <id>platform-release</id>
+            <name>platform-release</name>
+            <url>http://10.10.101.21:8081/artifactory/plugins-release-local</url>
+        </repository>
+        <!-- 发布快照版本 -->
+        <snapshotRepository>
+            <id>platform-snapshots</id>
+            <name>platform-snapshots</name>
+            <url>http://10.10.101.21:8081/artifactory/plugins-snapshot-local</url>
+        </snapshotRepository>
+    </distributionManagement>
+</project>

+ 85 - 0
src/main/java/com/uas/ops/diff/domain/Diff.java

@@ -0,0 +1,85 @@
+package com.uas.ops.diff.domain;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class Diff implements Serializable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private List<String> deletes;
+	private List<String> adds;
+	private List<String> updates;
+
+	public List<String> getDeletes() {
+		return deletes;
+	}
+
+	public void setDeletes(List<String> deletes) {
+		this.deletes = deletes;
+	}
+
+	public List<String> getAdds() {
+		return adds;
+	}
+
+	public void setAdds(List<String> adds) {
+		this.adds = adds;
+	}
+
+	public List<String> getUpdates() {
+		return updates;
+	}
+
+	public void setUpdates(List<String> updates) {
+		this.updates = updates;
+	}
+
+	/**
+	 * 涉及的文件列表
+	 * @return
+	 */
+	public List<String> getFileList() {
+		List<String> list = new ArrayList<String>();
+		list.addAll(this.adds);
+		list.addAll(this.updates);
+		// 不用考虑删除的
+		return list;
+	}
+
+	public Diff() {
+	}
+
+	public Diff(Manifest lastManifest, Manifest newManifest) {
+		assert null != newManifest;
+		this.deletes = new ArrayList<String>();
+		this.adds = new ArrayList<String>();
+		this.updates = new ArrayList<String>();
+		compare(lastManifest, newManifest);
+	}
+
+	private void compare(Manifest lastManifest, Manifest newManifest) {
+		if (null == lastManifest && null != newManifest) {
+			this.adds.add(newManifest.getPath());
+		} else if (null == newManifest && null != lastManifest) {
+			this.deletes.add(lastManifest.getPath());
+		} else if (!lastManifest.getPath().equals(newManifest.getPath())) {
+			this.deletes.add(lastManifest.getPath());
+			this.adds.add(newManifest.getPath());
+		} else if (lastManifest.getLastChanged() < newManifest.getLastChanged()) {
+			if (null != lastManifest.getChildren() || null != newManifest.getChildren()) {
+				Map<String, Manifest> lastMap = lastManifest.toMap();
+				Map<String, Manifest> newMap = newManifest.toMap();
+				Set<String> paths = new HashSet<String>(lastMap.keySet());
+				paths.addAll(newMap.keySet());
+				for (String path : paths) {
+					compare(lastMap.get(path), newMap.get(path));
+				}
+			} else {
+				this.updates.add(newManifest.getPath());
+			}
+		}
+	}
+}

+ 92 - 0
src/main/java/com/uas/ops/diff/domain/Manifest.java

@@ -0,0 +1,92 @@
+package com.uas.ops.diff.domain;
+
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Manifest implements Serializable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private String path;
+	private String version;
+	private long lastChanged;
+	private List<Manifest> children;
+
+	public Manifest() {
+	}
+
+	public Manifest(String path, String version, long lastChanged) {
+		super();
+		this.path = path;
+		this.version = version;
+		this.lastChanged = lastChanged;
+	}
+
+	public String getPath() {
+		return path;
+	}
+
+	public void setPath(String path) {
+		this.path = path;
+	}
+
+	public String getVersion() {
+		return version;
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+	/**
+	 * 上次更新时间
+	 */
+	public long getLastChanged() {
+		return lastChanged;
+	}
+
+	public void setLastChanged(long lastChanged) {
+		this.lastChanged = lastChanged;
+	}
+
+	public List<Manifest> getChildren() {
+		return children;
+	}
+
+	public void setChildren(List<Manifest> children) {
+		this.children = children;
+	}
+
+	public void println(PrintStream stream) {
+		println(stream, 0);
+	}
+
+	public void println(PrintStream stream, int i) {
+		stream.println("L" + i + ": " + path + "=" + version);
+		if (null != children) {
+			for (Manifest child : children)
+				child.println(stream, i+1);
+		}
+	}
+
+	public Map<String, Manifest> toMap() {
+		Map<String, Manifest> map = new HashMap<String, Manifest>();
+		if (null != children) {
+			for (Manifest child : children) {
+				if (map.containsKey(child.getPath())) {
+					if (map.get(child.getPath()).getVersion().compareTo(child.getVersion()) >= 0) {
+						continue;
+					}
+				}
+				map.put(child.getPath(), child);
+			}
+		}
+		return map;
+	}
+
+}

+ 47 - 0
src/main/java/com/uas/plugins/maven/ops/diff/plugin/DeployMojo.java

@@ -0,0 +1,47 @@
+package com.uas.plugins.maven.ops.diff.plugin;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.plugins.maven.ops.diff.provider.DiffService;
+import com.uas.plugins.maven.ops.diff.provider.ManifestService;
+import com.uas.plugins.maven.ops.diff.util.ObjectUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+
+import java.io.File;
+
+@Mojo(name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, threadSafe = true)
+public class DeployMojo extends MyAbstractMojo {
+
+	private ManifestService manifestService;
+
+	private DiffService diffService;
+
+	@Override
+	public void execute() throws MojoExecutionException, MojoFailureException {
+        manifestService = new ManifestService(this.repository, artifact.getGroupId(), artifact.getArtifactId());
+        diffService = new DiffService(this.repository, artifact.getGroupId(), artifact.getArtifactId());
+
+        File lastManifestFile = getLastManifestFile();
+        File newManifestFile = getManifestFile();
+        File newDiffFile = getDiffFile();
+        if (null != newManifestFile && newManifestFile.exists() && null != newDiffFile && newDiffFile.exists()) {
+            String fromVersion = "0";
+            try {
+                if (lastManifestFile.exists()) {
+                    Manifest lastManifest = ObjectUtils.read(lastManifestFile);
+                    fromVersion = lastManifest.getVersion();
+                }
+                Manifest newManifest = ObjectUtils.read(newManifestFile);
+                String toVersion = newManifest.getVersion();
+                manifestService.uploadManifest(newManifestFile);
+                diffService.uploadDiff(fromVersion, toVersion, newDiffFile);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+	}
+
+}

+ 72 - 0
src/main/java/com/uas/plugins/maven/ops/diff/plugin/DiffMojo.java

@@ -0,0 +1,72 @@
+package com.uas.plugins.maven.ops.diff.plugin;
+
+import com.uas.ops.diff.domain.Diff;
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.plugins.maven.ops.diff.provider.ManifestService;
+import com.uas.plugins.maven.ops.diff.util.ObjectUtils;
+import com.uas.plugins.maven.ops.diff.util.ZipUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+@Mojo(name = "diff", defaultPhase = LifecyclePhase.INSTALL, threadSafe = true)
+public class DiffMojo extends MyAbstractMojo {
+
+	private ManifestService manifestService;
+
+	@Override
+	public void execute() throws MojoExecutionException, MojoFailureException {
+		if (this.skip) {
+			getLog().info("Skipping create diff");
+		} else {
+            File newManifestFile = getManifestFile();
+            if (null != newManifestFile && newManifestFile.exists()) {
+                manifestService = new ManifestService(this.repository, artifact.getGroupId(), artifact.getArtifactId());
+                try {
+                    String lastVersion = manifestService.getLastVersion();
+                    Manifest newManifest = ObjectUtils.read(newManifestFile);
+                    if (!newManifest.getVersion().equals(lastVersion)) {
+                        if (null != lastVersion && !lastVersion.isEmpty()) {
+                            File lastManifestFile = getLastManifestFile();
+                            manifestService.downloadManifest(lastVersion, lastManifestFile);
+                            Manifest lastManifest = ObjectUtils.read(lastManifestFile);
+                            Diff diff = new Diff(lastManifest, newManifest);
+                            createDiffFile(diff);
+                        } else {
+                            ZipUtils.zip(new File(targetdir, buildName), getDiffFile());
+                        }
+                        getLog().info("Diff [" + getDiffFile().getAbsolutePath() + "] created");
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+		}
+	}
+
+	private void createDiffFile(Diff diff) throws IOException{
+        if (!diffTarget.exists()) {
+            diffTarget.mkdirs();
+        }
+        File sourceDir = new File(targetdir, buildName);
+        for (String path:diff.getFileList()) {
+            getLog().info("DIFF FILE: " + path);
+            File file = new File(sourceDir, path);
+            if (file.exists()) {
+                File targetFile = new File(diffTarget, path);
+                if (file.isDirectory()) {
+                    targetFile.mkdirs();
+                    FileUtils.copyDirectory(file, targetFile.getParentFile());
+                } else {
+                    FileUtils.copyFile(file, targetFile);
+                }
+            }
+        }
+        ZipUtils.zip(diffTarget, getDiffFile());
+    }
+}

+ 127 - 0
src/main/java/com/uas/plugins/maven/ops/diff/plugin/ManifestMojo.java

@@ -0,0 +1,127 @@
+package com.uas.plugins.maven.ops.diff.plugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.plugins.maven.ops.diff.util.ObjectUtils;
+import com.uas.plugins.maven.ops.diff.util.SvnUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.util.MatchPatterns;
+import org.tmatesoft.svn.core.wc2.SvnStatus;
+
+/**
+ * 创建版本信息清单
+ * 
+ * @author yingp
+ *
+ */
+@Mojo(name = "manifest", defaultPhase = LifecyclePhase.INSTALL, threadSafe = true)
+public class ManifestMojo extends MyAbstractMojo {
+
+	@Parameter(property = "packagingIncludes", alias = "includes")
+	private ArrayList<String> packagingIncludes;
+
+	@Parameter(property = "packagingExcludes", alias = "excludes")
+	private ArrayList<String> packagingExcludes;
+
+    @Parameter(property = "sourceDir", defaultValue = "src/main/java")
+    private String sourceDir;
+
+    @Parameter(property = "resourceDir", defaultValue = "src/main/resources")
+    private String resourceDir;
+
+    @Parameter(property = "webappSourceDir", defaultValue = "src/main/websrc")
+    private String webappSourceDir;
+
+	private MatchPatterns includesPatterns;
+
+	private MatchPatterns excludesPatterns;
+
+	@Override
+	public void execute() throws MojoExecutionException, MojoFailureException {
+		if (this.skip) {
+			getLog().info("Skipping create manifest");
+		} else {
+			if (null == packagingIncludes || packagingIncludes.isEmpty()) {
+				packagingIncludes = new ArrayList<String>(Collections.singletonList("**"));
+			}
+			if (null == packagingExcludes) {
+				packagingExcludes = new ArrayList<String>();
+			}
+			this.includesPatterns = MatchPatterns.from(packagingIncludes);
+			this.excludesPatterns = MatchPatterns.from(packagingExcludes);
+			try {
+				File manifestFile = getManifestFile();
+				if (isSubversion()) {
+					Manifest manifest = getManifest(basedir, SvnUtils.getTargetStatus(basedir));
+					ObjectUtils.write(manifest, manifestFile);
+					getLog().info("Manifest [" + manifestFile.getAbsolutePath() + "] created");
+				} else if(isGit()) {
+
+                } else {
+					getLog().warn("UnSupported version control type, Skipping create manifest");
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	private Manifest getManifest(File file, Map<File, SvnStatus> statusMap) throws IOException {
+		SvnStatus status = statusMap.get(file);
+		Manifest manifest = null;
+		if (null != status && includesPatterns.matches(status.getRepositoryRelativePath(), true)
+				&& !excludesPatterns.matches(status.getRepositoryRelativePath(), true)) {
+			manifest = new Manifest(parseRepositoryPath(status.getRepositoryRelativePath()), String.valueOf(status.getChangedRevision()), status.getChangedDate().getTime());
+			if (file.isDirectory()) {
+				List<Manifest> children = new ArrayList<Manifest>();
+				for (File f : file.listFiles()) {
+					Manifest child = getManifest(f, statusMap);
+					if (null != child)
+						children.add(child);
+				}
+				manifest.setChildren(children);
+			}
+		}
+		return manifest;
+	}
+
+    private String parseRepositoryPath(String path) {
+        if (path.contains("/")) {
+            // remove repositoryBasePath
+            String subpath = path.substring(path.indexOf("/") + 1);
+            // replace {sourceDir} into {targetDir}/{buildName}/WEB-INF/classes
+            if (subpath.equals(sourceDir) || subpath.matches(sourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(sourceDir, "WEB-INF/classes");
+            }
+            // replace {resourceDir} into {targetDir}/{buildName}/WEB-INF
+            if (subpath.equals(resourceDir) || subpath.matches(resourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(resourceDir, "WEB-INF/classes");
+            }
+            // replace {webappSourceDir} into {targetDir}/{buildName}
+            if (subpath.equals(webappSourceDir)) {
+                subpath = subpath.replaceFirst(webappSourceDir, "");
+            } else if (subpath.matches(webappSourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(webappSourceDir + "/", "");
+            }
+            // .java build to .class
+            if (subpath.endsWith(".java")) {
+                subpath = subpath.substring(0, subpath.lastIndexOf(".java")) + ".class";
+            }
+            path = "/" + subpath;
+        } else {
+            path = "/";
+        }
+        return path;
+    }
+
+}

+ 84 - 0
src/main/java/com/uas/plugins/maven/ops/diff/plugin/MyAbstractMojo.java

@@ -0,0 +1,84 @@
+package com.uas.plugins.maven.ops.diff.plugin;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugins.annotations.Parameter;
+
+import java.io.File;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public abstract class MyAbstractMojo extends AbstractMojo {
+
+    @Parameter(defaultValue="${project.artifact}", required=true, readonly=true)
+    protected Artifact artifact;
+
+    /**
+     * ops-diff-service接口地址
+     */
+    @Parameter(property = "repository", defaultValue = "http://localhost:23000/v1")
+    protected String repository;
+
+    /**
+     * 清单文件
+     */
+    @Parameter(property = "manifestName", defaultValue = ".manifest")
+    protected String manifestName;
+
+    /**
+     * 差异文件
+     */
+    @Parameter(property = "diffName", defaultValue = ".diff")
+    protected String diffName;
+
+    /**
+     * 默认跳过不执行
+     */
+    @Parameter(property = "maven.diff.skip", defaultValue = "true")
+    protected boolean skip;
+
+    @Parameter(defaultValue = "${basedir}", required = true, readonly = true)
+    protected File basedir;
+
+    @Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
+    protected File targetdir;
+
+    @Parameter(defaultValue = "${project.build.directory}/diff", required = true)
+    protected File diffTarget;
+
+    @Parameter(defaultValue = "${project.build.finalName}", required = true, readonly = true)
+    protected String buildName;
+
+    protected File getManifestFile() {
+        if (null != manifestName) {
+            return new File(targetdir, manifestName);
+        }
+        return null;
+    }
+
+    protected  boolean isSubversion() {
+        File svnCtl = new File(basedir, ".svn");
+        return svnCtl.exists();
+    }
+
+    protected  boolean isGit() {
+        File gitCtl = new File(basedir, ".git");
+        return gitCtl.exists();
+    }
+
+    protected File getLastManifestFile() {
+        if (null != manifestName) {
+            return new File(targetdir, manifestName + ".last");
+        }
+        return null;
+    }
+
+    protected File getDiffFile() {
+        if (null != diffName) {
+            return new File(targetdir, diffName);
+        }
+        return null;
+    }
+
+}

+ 36 - 0
src/main/java/com/uas/plugins/maven/ops/diff/provider/DiffService.java

@@ -0,0 +1,36 @@
+package com.uas.plugins.maven.ops.diff.provider;
+
+import com.uas.plugins.maven.ops.diff.util.HttpUtils;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class DiffService {
+
+    private final String diffApi;
+    private final String groupId;
+    private final String artifactId;
+
+    public DiffService(String repositoryUrl, String groupId, String artifactId) {
+        this.diffApi = repositoryUrl + "/diff";
+        this.groupId = groupId;
+        this.artifactId = artifactId;
+    }
+
+    public void uploadDiff(String fromVersion, String toVersion, File sourceFile) throws Exception {
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("groupId", this.groupId);
+        data.put("artifactId", this.artifactId);
+        data.put("fromVersion", fromVersion);
+        data.put("toVersion", toVersion);
+        HttpUtils.ResponseWrap resp = HttpUtils.upload(this.diffApi, data, sourceFile);
+        if (!resp.isSuccess()) {
+            throw new Exception(resp.getContent());
+        }
+    }
+
+}

+ 58 - 0
src/main/java/com/uas/plugins/maven/ops/diff/provider/ManifestService.java

@@ -0,0 +1,58 @@
+package com.uas.plugins.maven.ops.diff.provider;
+
+import com.uas.plugins.maven.ops.diff.util.HttpUtils;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class ManifestService {
+
+    private final String versionApi;
+    private final String manifestApi;
+    private final String groupId;
+    private final String artifactId;
+
+    public ManifestService(String repositoryUrl, String groupId, String artifactId) {
+        this.versionApi = repositoryUrl + "/version";
+        this.manifestApi = repositoryUrl + "/manifest";
+        this.groupId = groupId;
+        this.artifactId = artifactId;
+    }
+
+    public String getLastVersion() throws Exception {
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("groupId", this.groupId);
+        data.put("artifactId", this.artifactId);
+        HttpUtils.ResponseWrap resp = HttpUtils.get(this.versionApi, data);
+        if (resp.isSuccess()) {
+            return resp.getContent();
+        }
+        throw new Exception(resp.getContent());
+    }
+
+    public void downloadManifest(String version, File targetFile) throws Exception {
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("groupId", this.groupId);
+        data.put("artifactId", this.artifactId);
+        data.put("version", version);
+        HttpUtils.ResponseWrap resp = HttpUtils.download(this.manifestApi, data, targetFile);
+        if (!resp.isSuccess()) {
+            throw new Exception(resp.getContent());
+        }
+    }
+
+    public void uploadManifest(File sourceFile) throws Exception {
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("groupId", this.groupId);
+        data.put("artifactId", this.artifactId);
+        HttpUtils.ResponseWrap resp = HttpUtils.upload(this.manifestApi, data, sourceFile);
+        if (!resp.isSuccess()) {
+            throw new Exception(resp.getContent());
+        }
+    }
+
+}

+ 271 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/HttpUtils.java

@@ -0,0 +1,271 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class HttpUtils {
+
+    private static final Charset defaultCharset = Charset.forName("UTF-8");
+
+    private static HttpURLConnection getDefaultHttpURLConnection(URL url) throws IOException{
+        HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
+        urlConn.setDoOutput(true);
+        urlConn.setDoInput(true);
+        urlConn.setUseCaches(false);
+        urlConn.setInstanceFollowRedirects(true);
+        return urlConn;
+    }
+
+    private static HttpsURLConnection getDefaultHttpsURLConnection(URL url) throws Exception{
+        HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom());
+        SSLContext.setDefault(ctx);
+        urlConn.setDoOutput(true);
+        urlConn.setDoInput(true);
+        urlConn.setUseCaches(false);
+        urlConn.setInstanceFollowRedirects(true);
+        urlConn.setHostnameVerifier(new HostnameVerifier() {
+
+            @Override
+            public boolean verify(String hostname, SSLSession session) {
+                return true;
+            }
+        });
+        return urlConn;
+    }
+
+    private static HttpURLConnection getDefaultURLConnection(String requestUrl) throws Exception{
+        URL url = new URL(requestUrl);
+        if(requestUrl.startsWith("https")) {
+            return getDefaultHttpsURLConnection(url);
+        }
+        return getDefaultHttpURLConnection(url);
+    }
+
+    /**
+     * HTTP GET请求
+     * @param getUrl
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap get(String getUrl) {
+        HttpURLConnection urlConn = null;
+        try {
+            urlConn = getDefaultURLConnection(getUrl);
+            urlConn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
+            urlConn.setRequestMethod("GET");
+            return new ResponseWrap(urlConn);
+        } catch (Exception e) {
+            return new ResponseWrap(false, e.getMessage());
+        } finally {
+            if (urlConn != null) {
+                urlConn.disconnect();
+            }
+        }
+    }
+
+    /**
+     * HTTP GET请求
+     * @param getUrl
+     * @param data
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap get(String getUrl, Map<String, Object> data) {
+        return get(getUrl + (getUrl.contains("?") ? "&" : "?") + getFormData(data));
+    }
+
+    /**
+     * 文件下载
+     * @param downloadUrl
+     * @param targetFile
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap download(String downloadUrl, File targetFile) {
+        HttpURLConnection urlConn = null;
+        try {
+            urlConn = getDefaultURLConnection(downloadUrl);
+            urlConn.setRequestMethod("GET");
+            return new ResponseWrap(urlConn, targetFile);
+        } catch (Exception e) {
+            return new ResponseWrap(false, e.getMessage());
+        } finally {
+            if (urlConn != null) {
+                urlConn.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 文件下载
+     * @param getUrl
+     * @param data
+     * @param targetFile
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap download(String getUrl, Map<String, Object> data, File targetFile) {
+        return download(getUrl + (getUrl.contains("?") ? "&" : "?") + getFormData(data), targetFile);
+    }
+
+    /**
+     * HTTP POST请求
+     * @param postUrl
+     * @param formData
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap post(String postUrl, Map<String, Object> formData) {
+        HttpURLConnection urlConn = null;
+        try {
+            urlConn = getDefaultURLConnection(postUrl);
+            urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
+            urlConn.setRequestMethod("POST");
+            StreamUtils.copy(getFormData(formData), defaultCharset, urlConn.getOutputStream());
+            return new ResponseWrap(urlConn);
+        } catch (Exception e) {
+            return new ResponseWrap(false, e.getMessage());
+        } finally {
+            if (null != urlConn) {
+                urlConn.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 文件上传
+     * @param postUrl
+     * @param formData
+     * @param sourceFile
+     * @return
+     * @throws Exception
+     */
+    public static ResponseWrap upload(String postUrl, Map<String, Object> formData, File sourceFile) {
+        HttpURLConnection urlConn = null;
+        DataOutputStream out = null;
+        FileInputStream in = null;
+        String end = "\r\n";
+        String twoHyphens = "--";
+        String boundary = "*****";
+        try {
+            in = new FileInputStream(sourceFile);
+            urlConn = getDefaultURLConnection(postUrl);
+            urlConn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
+            urlConn.setRequestMethod("POST");
+            out = new DataOutputStream(urlConn.getOutputStream());
+            if (null != formData) {
+                for(String field:formData.keySet()) {
+                    out.writeBytes(twoHyphens + boundary + end);
+                    out.writeBytes("Content-Disposition: form-data; name=\"" + field + "\"" + end);
+                    out.writeBytes(end);
+                    out.writeBytes(String.valueOf(formData.get(field)));
+                    out.writeBytes(end);
+                }
+            }
+            out.writeBytes(twoHyphens + boundary + end);
+            out.writeBytes("Content-Disposition: form-data; Content-Type:application/octet-stream; name=\"file\";filename=\"" + sourceFile.getName() + "\"" + end);
+            out.writeBytes(end);
+            StreamUtils.copy(in, out);
+            out.writeBytes(end);
+            out.writeBytes(twoHyphens + boundary + twoHyphens + end);
+            out.flush();
+            return new ResponseWrap(urlConn);
+        } catch (Exception e) {
+            return new ResponseWrap(false, e.getMessage());
+        } finally {
+            if (null != urlConn) {
+                urlConn.disconnect();
+            }
+            IOUtils.closeQuietly(in, out);
+        }
+    }
+
+    private static String getFormData(Map<String, Object> data) {
+        StringBuffer sb = new StringBuffer();
+        for (String key : data.keySet())
+            if (data.get(key) != null) {
+                try {
+                    sb.append(key).append('=').append(URLEncoder.encode(data.get(key).toString(), "UTF-8")).append('&');
+                } catch (Exception e) {
+
+                }
+            }
+        return sb.substring(0, sb.length() - 1).toString();
+    }
+
+    public static class ResponseWrap {
+        private boolean success;
+        private String content;
+
+        public ResponseWrap(boolean success, String content) {
+            super();
+            this.success = success;
+            this.content = content;
+        }
+
+        public ResponseWrap(HttpURLConnection urlConn) throws IOException{
+            super();
+            this.success = urlConn.getResponseCode() == 200;
+            this.content = StreamUtils.copyToString((this.success ? urlConn.getInputStream() : urlConn.getErrorStream()), defaultCharset);
+        }
+
+        public ResponseWrap(HttpURLConnection urlConn, File targetFile) throws IOException{
+            super();
+            this.success = urlConn.getResponseCode() == 200;
+            if (this.success) {
+                if (!targetFile.getParentFile().exists()) {
+                    targetFile.getParentFile().mkdirs();
+                }
+                StreamUtils.copy(urlConn.getInputStream(), new FileOutputStream(targetFile));
+            } else {
+                this.content = StreamUtils.copyToString(urlConn.getErrorStream(), defaultCharset);
+            }
+        }
+
+        public boolean isSuccess() {
+            return success;
+        }
+
+        public void setSuccess(boolean success) {
+            this.success = success;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(String content) {
+            this.content = content;
+        }
+    }
+
+    private static class DefaultTrustManager implements X509TrustManager {
+
+        @Override
+        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            return null;
+        }
+
+    }
+}

+ 22 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/IOUtils.java

@@ -0,0 +1,22 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class IOUtils {
+
+    public static void closeQuietly(Closeable... closeables) {
+        if(null != closeables)
+            for(Closeable closeable:closeables)
+                try {
+                    if(closeable != null) {
+                        closeable.close();
+                    }
+                } catch (IOException var2) {
+                }
+    }
+
+}

+ 44 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/ObjectUtils.java

@@ -0,0 +1,44 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public class ObjectUtils {
+
+	/**
+	 * 写对象
+	 * 
+	 * @param obj
+	 * @param file
+	 * @throws Exception
+	 */
+	public static void write(Object obj, File file) throws Exception {
+		if (file.getParentFile().exists() || file.getParentFile().mkdirs()) {
+			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
+			os.writeObject(obj);
+			os.close();
+		}
+	}
+
+	/**
+	 * 读对象
+	 * 
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	public static <T> T read(File file) throws Exception {
+		if (file.exists()) {
+			ObjectInputStream is = new ObjectInputStream(new FileInputStream(file));
+			@SuppressWarnings("unchecked")
+			T obj = (T) is.readObject();
+			is.close();
+			return obj;
+		}
+		return null;
+	}
+
+}

+ 52 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/StreamUtils.java

@@ -0,0 +1,52 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class StreamUtils {
+
+    public static int copy(InputStream in, OutputStream out) throws IOException {
+        assert null != in;
+        assert  null != out;
+        int byteCount = 0;
+        byte[] buffer = new byte[4096];
+
+        int bytesRead1;
+        for(boolean bytesRead = true; (bytesRead1 = in.read(buffer)) != -1; byteCount += bytesRead1) {
+            out.write(buffer, 0, bytesRead1);
+        }
+
+        out.flush();
+        return byteCount;
+    }
+
+    public static String copyToString(InputStream in, Charset charset) throws IOException {
+        assert null != in;
+        StringBuilder out = new StringBuilder();
+        InputStreamReader reader = new InputStreamReader(in, charset);
+        char[] buffer = new char[4096];
+        boolean bytesRead = true;
+
+        int bytesRead1;
+        while((bytesRead1 = reader.read(buffer)) != -1) {
+            out.append(buffer, 0, bytesRead1);
+        }
+
+        return out.toString();
+    }
+
+    public static void copy(String in, Charset charset, OutputStream out) throws IOException {
+        if (null != in) {
+            assert null != charset;
+            assert null != out;
+            OutputStreamWriter writer = new OutputStreamWriter(out, charset);
+            writer.write(in);
+            writer.flush();
+            writer.close();
+        }
+    }
+
+}

+ 39 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/SvnUtils.java

@@ -0,0 +1,39 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver;
+import org.tmatesoft.svn.core.wc2.SvnGetStatus;
+import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
+import org.tmatesoft.svn.core.wc2.SvnStatus;
+import org.tmatesoft.svn.core.wc2.SvnTarget;
+
+public class SvnUtils {
+
+	public static Map<File, SvnStatus> getTargetStatus(File target) throws SVNException {
+		final Map<File, SvnStatus> statuses = new HashMap<File, SvnStatus>();
+		SvnOperationFactory operationFactory = new SvnOperationFactory();
+		SvnGetStatus statusOperation = operationFactory.createGetStatus();
+		statusOperation.setSingleTarget(SvnTarget.fromFile(target));
+		statusOperation.setDepth(SVNDepth.INFINITY);
+		statusOperation.setRevision(SVNRevision.WORKING);
+		statusOperation.setReportAll(true);
+		statusOperation.setReceiver(new ISvnObjectReceiver<SvnStatus>() {
+
+			@Override
+			public void receive(SvnTarget target, SvnStatus status) throws SVNException {
+				if (status.isVersioned())
+					statuses.put(status.getPath(), status);
+			}
+
+		});
+		statusOperation.run();
+		return statuses;
+	}
+
+}

+ 63 - 0
src/main/java/com/uas/plugins/maven/ops/diff/util/ZipUtils.java

@@ -0,0 +1,63 @@
+package com.uas.plugins.maven.ops.diff.util;
+
+import java.io.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Created by Pro1 on 2017/6/13.
+ */
+public class ZipUtils {
+
+    public static void unzip(byte[] zipData, String targetPath) throws IOException{
+        ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zipData));
+        ZipEntry entry;
+        File file;
+        BufferedOutputStream out = null;
+        while((entry = in.getNextEntry())!=null && !entry.isDirectory()){
+            file = new File(targetPath, entry.getName());
+            if (!file.getParentFile().exists()) {
+               file.getParentFile().mkdirs();
+            }
+            out = new BufferedOutputStream(new FileOutputStream(file));
+            StreamUtils.copy(in, out);
+            out.flush();
+        }
+        in.closeEntry();
+        IOUtils.closeQuietly(in, out);
+    }
+
+    public static void zip(File source, File zipFile) throws IOException{
+        if (source.exists()) {
+            FileOutputStream fileOut = new FileOutputStream(zipFile);
+            ZipOutputStream zipOut = new ZipOutputStream(fileOut);
+            try {
+                addEntry(null, source, zipOut);
+                // 如果希望保留sourcePath文件夹,使用addEntry("", source, zipOut);
+            } finally {
+                IOUtils.closeQuietly(zipOut, fileOut);
+            }
+        }
+    }
+
+    private static void addEntry(String entryPath, File source, ZipOutputStream zipOut) throws IOException {
+        String entry = null == entryPath ? "" : (entryPath + source.getName());
+        if (source.isDirectory()) {
+            entry = entry.isEmpty() ? entry : (entry + File.separator);
+            for (File file : source.listFiles()) {
+                addEntry(entry, file, zipOut);
+            }
+        } else {
+            FileInputStream fileIn = new FileInputStream(source);
+            try {
+                zipOut.putNextEntry(new ZipEntry(entry));
+                StreamUtils.copy(fileIn, zipOut);
+                zipOut.closeEntry();
+            } finally {
+                IOUtils.closeQuietly(fileIn);
+            }
+        }
+    }
+
+}

+ 30 - 0
src/test/java/com/uas/plugins/test/DiffTest.java

@@ -0,0 +1,30 @@
+package com.uas.plugins.test;
+
+import com.uas.ops.diff.domain.Diff;
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.plugins.maven.ops.diff.util.ObjectUtils;
+import com.uas.plugins.maven.ops.diff.util.SvnUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+/**
+ * Created by Pro1 on 2017/6/30.
+ */
+public class DiffTest {
+
+    public static void main(String[] args) throws Exception{
+        File manifestFile16517 = new File("C:\\Users\\Pro1\\Downloads\\CgpkyFlDeoyAZRi-ABgoQpjZVrM.manife");
+        File manifestFile16781 = new File("C:\\Users\\Pro1\\Downloads\\CgpkyFlV_GCAeH2CABg6y9hM6dI.manife");
+        Manifest manifest16517 = ObjectUtils.read(manifestFile16517);
+//        manifest16517.println(new PrintStream(new FileOutputStream(new File(manifestFile16517.getAbsolutePath() + ".txt"))));
+        Manifest manifest16781 = ObjectUtils.read(manifestFile16781);
+//        manifest16781.println(new PrintStream(new FileOutputStream(new File(manifestFile16781.getAbsolutePath() + ".txt"))));
+        Diff diff = new Diff(manifest16517, manifest16781);
+        for(String path : diff.getFileList()) {
+            System.out.println(path);
+        }
+    }
+
+}

+ 26 - 0
src/test/java/com/uas/plugins/test/HttpTest.java

@@ -0,0 +1,26 @@
+package com.uas.plugins.test;
+
+import com.uas.plugins.maven.ops.diff.provider.DiffService;
+import com.uas.plugins.maven.ops.diff.provider.ManifestService;
+
+import java.io.File;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class HttpTest {
+
+    static String repository = "http://localhost:23000/v1";
+    static String groupId = "com.uas.erp";
+    static String artifactId = "uas";
+    static File manifestFile = new File("C:\\Source\\1.0.0\\target\\.manifest");
+    static File diffFile = new File("C:\\Source\\1.0.0\\target\\.diff");
+
+    public static void main(String[] args) throws Exception{
+//        ManifestService manifestService = new ManifestService(repository, groupId, artifactId);
+//        manifestService.uploadManifest(manifestFile);
+        DiffService diffService = new DiffService(repository, groupId, artifactId);
+        diffService.uploadDiff("0", "15817", diffFile);
+    }
+
+}

+ 89 - 0
src/test/java/com/uas/plugins/test/ManifestTest.java

@@ -0,0 +1,89 @@
+package com.uas.plugins.test;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.plugins.maven.ops.diff.util.ObjectUtils;
+import com.uas.plugins.maven.ops.diff.util.SvnUtils;
+import org.codehaus.plexus.util.MatchPatterns;
+import org.tmatesoft.svn.core.wc2.SvnStatus;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class ManifestTest {
+
+    static final File basedir = new File("C:\\Source\\1.0.0");
+
+    static MatchPatterns includesPatterns = MatchPatterns.from(new String[]{ "**" });
+
+    static MatchPatterns excludesPatterns = MatchPatterns.from(new String[]{"**/.classpath", "**/.project", "**/.settings", "**/build", "**/pom.xml"});
+
+    static String sourceDir = "src";
+
+    static String resourceDir = "resources";
+
+    static String webappSourceDir = "WebContent";
+
+    public static void main(String[] args) throws Exception{
+        Manifest manifest = getManifest(basedir, SvnUtils.getTargetStatus(basedir));
+        File manifestFile = new File(basedir, "target\\.manifest");
+        ObjectUtils.write(manifest, manifestFile);
+        manifest.println(new PrintStream(new FileOutputStream(new File(manifestFile.getAbsolutePath() + ".txt"))));
+    }
+
+    private static Manifest getManifest(File file, Map<File, SvnStatus> statusMap) throws IOException {
+        SvnStatus status = statusMap.get(file);
+        Manifest manifest = null;
+        if (null != status && includesPatterns.matches(status.getRepositoryRelativePath(), true)
+                && !excludesPatterns.matches(status.getRepositoryRelativePath(), true)) {
+            manifest = new Manifest(parseRepositoryPath(status.getRepositoryRelativePath()), String.valueOf(status.getChangedRevision()), status.getChangedDate().getTime());
+            if (file.isDirectory()) {
+                List<Manifest> children = new ArrayList<Manifest>();
+                for (File f : file.listFiles()) {
+                    Manifest child = getManifest(f, statusMap);
+                    if (null != child)
+                        children.add(child);
+                }
+                manifest.setChildren(children);
+            }
+        }
+        return manifest;
+    }
+
+    private static String parseRepositoryPath(String path) {
+        if (path.contains("/")) {
+            // remove repositoryBasePath
+            String subpath = path.substring(path.indexOf("/") + 1);
+            // replace {sourceDir} into {targetDir}/{buildName}/WEB-INF/classes
+            if (subpath.equals(sourceDir) || subpath.matches(sourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(sourceDir, "WEB-INF/classes");
+            }
+            // replace {resourceDir} into {targetDir}/{buildName}/WEB-INF
+            if (subpath.equals(resourceDir) || subpath.matches(resourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(resourceDir, "WEB-INF/classes");
+            }
+            // replace {webappSourceDir} into {targetDir}/{buildName}
+            if (subpath.equals(webappSourceDir)) {
+                subpath = subpath.replaceFirst(webappSourceDir, "");
+            } else if (subpath.matches(webappSourceDir + "/.*")) {
+                subpath = subpath.replaceFirst(webappSourceDir + "/", "");
+            }
+            // .java build to .class
+            if (subpath.endsWith(".java")) {
+                subpath = subpath.substring(0, subpath.lastIndexOf(".java")) + ".class";
+            }
+            path = "/" + subpath;
+        } else {
+            path = "/";
+        }
+        return path;
+    }
+
+}