SVN自动生成升级文件夹产出物整理

14 篇文章 0 订阅
14 篇文章 0 订阅

SVN自动生成升级文件夹产出物整理

因为每天都要往现场发两三次包,一个一个的挪文件实在费事,因此写了这个工具来减少无所谓的时间浪费。

自从开始写,到现在,大致经历了四个版本,现在总结的是V4.0,后续可能还会有新的变化,到时候再更新一下

文件路径帮助类FilePathUtil

这个类主要是用来统一Linux和Windows下文件路径的问题

这个地方其实还是没有处理的让自己满意,因为在核心类SVNMain中还是多次出现了对路径的特殊处理,后边可能还是要再优化

package com.svn.util;

/**
 * 文件路径切换。主要是为了兼容windows和Linux两种系统
 * 
 * @author lihh
 *
 */
public class FilePathUtil {
	public static final String FILE_SEPARATOR = System.getProperty("file.separator");
	// public static final String FILE_SEPARATOR = File.separator;

	public static String getRealFilePath(String path) {
		return path.replace("/", FILE_SEPARATOR).replace("\\", FILE_SEPARATOR);
	}

	public static String getHttpURLPath(String path) {
		return path.replace("\\", "/");
	}

	/**
	 * 判断系统类型
	 * 
	 * @return
	 */
	public static boolean isWinOs() {
		return System.getProperty("os.name").toLowerCase().startsWith("win");
	}
}

总结

这个类让我学习到的是

String.format

这个平常用的少了,都是直接用+来处理。这里没有用到很高级的东西,主要连接字符串的另外一种形式

操作系统类型的判断
System.getProperty("os.name").toLowerCase()
作系统文件路径分割符号的获取
System.getProperty("file.separator")

或者

File.separator

命令执行类CmdUtil

该类用来在Linux或者Windows下执行命令

package com.svn.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 执行命令帮助类
 * 
 * @author lihh
 *
 */
public class CmdUtil {

	/**
	 * 组装命令字符串
	 * @return
	 */
	private static String getCmdStr() {
		boolean isWinOs = FilePathUtil.isWinOs();
		String panfu = PropertyUtil.getProjectPath().substring(0, 2);
		
		return String.format("%s cd %s&&svn diff -r %s --summarize", 
						isWinOs ? "cmd /c " + panfu +"&&" : "",
						FilePathUtil.getRealFilePath(PropertyUtil.getProjectPath()),
						PropertyUtil.getVersion());
	}

	/**
	 * 执行命令
	 * 
	 * @param cmd
	 * @return
	 */
	public static String[] runCmd() {
		Runtime runtime = Runtime.getRuntime();
		Process process = null;
		BufferedReader reader = null;
		StringBuffer content = new StringBuffer();
		try {
			String cmd = getCmdStr();
			if (FilePathUtil.isWinOs()) {
				System.out.println(" 开始执行Windows命令:" + cmd);
				process = runtime.exec(cmd);
			} else {
				System.out.println(" 开始执行Linux命令:" + cmd);
				String[] cmdA = { "/bin/sh", "-c", cmd };
				process = runtime.exec(cmdA);
			}
			reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			process.waitFor();// 等待子进程完成再往下执行。
			String line = null;
			while ((line = reader.readLine()) != null) {
				content.append(line + "\r\n");
			}
			//如果命令执行错误,那么输出错误信息
			if(content.toString().equals("")) {
				reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
				while ((line = reader.readLine()) != null) {
					content.append(line + "\r\n");
				}
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			reader = null;
		}

		int i = process.exitValue();// 接收执行完毕的返回值
		process.destroy();// 销毁子进程
		process = null;
		return new String[]{String.valueOf(i),content.toString()};
	}
}

总结

这个类中的内容之前的工作学习中用到的都比较少,很多都是参考网络上的资料来写的。
Runtime和Process可以查阅API

Runtime

Runtime代表着Java运行时的环境,每个Java程序运行时都会自动创建一个Runtime,我们可以通过Runtime.getRuntime来获取Java运行时环境
Runtime的大致用处有

  • 统计系统的内存、cpu等信息
  • 运行命令。在Windows中,相当于在cmd中运行;在Linux中则相当于在终端中运行。
Process

通过Runtime.getRuntime().exec(“命令”)可以获得一个进程,这个进程用Process来表示,Process实例可以用来控制进程并获得相关信息。
需要注意的是,在Windows和Linux下命令的执行方式是不同的,需要自己去处理这些细节
####获取命令的输出
Process的实例中包含了执行成功和失败后的输出

process.getInputStream//获取程序执行成功后的输出
process.getErrorStream//获取程序执行错误后的输出
process.exitValue()//获取程序运行的返回值,0执行成功,其它执行失败
process.destory()//销毁子进程

##文件操作类
这个比较简单了。主要是文件及文件夹的创建

package com.svn.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

public class FileUtil {

	/***
	 * 复制单个文件*
	 * 
	 * @param oldPath
	 *            String 原文件路径 如:c:/fqf.txt*
	 * @param newPath
	 *            String 复制后路径 如:f:/fqf.txt*@return boolean
	 */
	private static void mkDir(File file) {
		if (file.getParentFile().exists()) {
			file.mkdir();
		} else {
			mkDir(file.getParentFile());
			file.mkdir();
		}
	}

	public static void copyFile(String oldPath, String newPath) {
		try {
			oldPath = FilePathUtil.getRealFilePath(oldPath);
			newPath = FilePathUtil.getRealFilePath(newPath);
			String[] arr1 = newPath.split("\\.");
			//注意这里:为多操作系统做判断.windows是\\
			String[] arr2 = arr1[0].split(FilePathUtil.isWinOs() ? File.separator+File.separator : File.separator);
//			String fileName = arr2[arr2.length - 1] + "." + arr1[1];
//			System.out.println(fileName);
			String filePath = "";
			for (int i = 0; i <= arr2.length - 2; i++) {
				filePath += arr2[i] + File.separator;
			}
//			System.out.println(filePath);

			File file = new File(filePath);
			mkDir(file);
			// int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { // 文件存在时
				InputStream inStream = new FileInputStream(oldPath); // 读入原文件
				@SuppressWarnings("resource")
				FileOutputStream fs = new FileOutputStream(newPath);
				byte[] buffer = new byte[1444];
				// int length;
				while ((byteread = inStream.read(buffer)) != -1) {
					// bytesum += byteread; // 字节数 文件大小
					// System.out.println(bytesum);
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
			}
		} catch (Exception e) {
			System.out.println("复制单个文件操作出错");
			e.printStackTrace();
		}
	}
}

properties文件的读取

同样比较简单

package com.svn.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

/**
 * @Desc:properties文件获取工具类 Created by lihhz on 2017/7/4.
 */
public class PropertyUtil {
	private static InputStream in;
	private static Properties props;

	/**
	 * 加载conf.properties
	 */
	synchronized private static void loadProps() {
		props = new Properties();
		try {
			in = PropertyUtil.class.getClassLoader().getResourceAsStream("conf.properties");
			props.load(new InputStreamReader(in, "utf-8"));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != in) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取conf属性值
	 * 
	 * @param key
	 * @return
	 */
	public static String getProperty(String key) {
		if (null == props) {
			loadProps();
		}
		return props.getProperty(key);
	}

	public static String getProjectPath() {
		return getProperty("proectPath");
	}
	public static String getTargetPath() {
		return getProperty("targetPath");
	}
	public static String getVersion() {
		return getProperty("version");
	}
}

使用jdk解析xml

这里解析的是eclipse生成的.classpath文件,这个文件中包含着classes的来源及输出信息,用来控制svn生成文件的去向

package com.svn.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * 解析.classpath文件
 * 
 * @author lihh
 *
 */
public class ResolveClasspath {

	/**
	 * 解析出classpath中与项目有关的路径和输出路径
	 * @return
	 */
	public static List<Map<String, String>> getInfo() {
		Element root = null;
		DocumentBuilder docBuilder = null;
		DocumentBuilderFactory docBuilderFactory = null;
		List<Map<String, String>> list = new ArrayList<Map<String, String>>();
		try {
			File classpath = getClasspath();
			docBuilderFactory = DocumentBuilderFactory.newInstance();
			docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(classpath);
			root = doc.getDocumentElement();
			NodeList nodeList = root.getChildNodes();
			for (int i = 0; i < nodeList.getLength(); i++) {
				Node classpathentryNode = nodeList.item(i);
				if (classpathentryNode.getNodeName().equals("classpathentry")) {
					// 避免#text
					NamedNodeMap map = classpathentryNode.getAttributes();
					if (map != null) {
						Map<String, String> m = new HashMap<String, String>();
						Node item = map.getNamedItem("path");
						if (item.getNodeValue().startsWith("src")) {
							m.put(item.getNodeName(), item.getNodeValue());
							Node output = map.getNamedItem("output");
							m.put(output.getNodeName(), output.getNodeValue());
							list.add(m);
						}
					}
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return list;
	}

	public static void main(String[] args) {
		List<Map<String, String>> list = getInfo();
		for (Map<String, String> map : list) {
			System.out.println(map);
		}
	}

	/**
	 * 找.classpath文件
	 * @return
	 * @throws FileNotFoundException
	 */
	private static File getClasspath() throws FileNotFoundException {
		String proRootPath = FilePathUtil.getRealFilePath(PropertyUtil.getProjectPath());
		File proDir = new File(proRootPath);
		if (!proDir.isDirectory()) {
			// 不是文件夹,来个报错
			return null;
		}
		String classpathPath = FilePathUtil.getRealFilePath(proDir.getAbsolutePath() + "/.classpath");
		File classpath = new File(classpathPath);
		if (!classpath.exists()) {
			throw new FileNotFoundException("没有找到.classpath文件,程序退出");
		}
		return classpath;
	}
}

核心类

这个类要做优化,因为还有很多对路径的特殊处理。优化的思路是:将所有的路径都转为Linux中的正斜杠路径表示法,然后统一处理。

package com.svn.util;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SvnMain {

	/**
	 * 核心方法
	 * @param content
	 */
	private static void packFiles(String content) {
		// 原始
		final String PROJECT_PATH = PropertyUtil.getProjectPath(), TARGET_PAHT = PropertyUtil.getTargetPath();

		System.out.println("-----开始组装文件-----");
		String[] contents = content.split("\r\n");
		for (int i = 0; i < contents.length; i++) {
			String line = contents[i];
			System.out.println(line);
			if (line == null || line.equals("")) {
				continue;
			}
			//注意这里:为多操作系统做判断.windows是\\
			String regex = FilePathUtil.isWinOs() ? "src\\\\([\\\\a-zA-Z0-9_\\-\\.]+)" : "src/([/a-zA-Z0-9_\\-\\.]+)";
			Matcher matcher = Pattern.compile(regex).matcher(line);
			while (matcher.find()) {
				String relativePath = matcher.group(0);
				if (relativePath.contains(".") && !relativePath.equals(".")) {//只处理文件
					System.out.println(String.format("%s.开始处理文件:%s", i, relativePath));
					String oldPath = PROJECT_PATH + FilePathUtil.FILE_SEPARATOR + relativePath;
					List<Map<String, String>> classpathList = ResolveClasspath.getInfo();
					boolean isInClasspath = false;
					for (Map<String, String> map : classpathList) {
						final String path = map.get("path"), output = map.get("output");
						String temp = FilePathUtil.isWinOs() ? relativePath.replace("\\", "/") : relativePath;
						if (temp.startsWith(path)) {
							isInClasspath = true;
							if(FilePathUtil.isWinOs()){
								relativePath = relativePath.replace(path.replace("/","\\"),"");
							}else{
								relativePath = relativePath.replace(path,"");
							}
							final String from = PROJECT_PATH + FilePathUtil.FILE_SEPARATOR + output + relativePath;
							System.out.println("  将从路径:"+from+"拷贝文件!");
							if(oldPath.endsWith(".java")) {
								FileUtil.copyFile(from.split("\\.")[0] + ".class",
										TARGET_PAHT+"/WEB-INF/classes/" + relativePath.split("\\.")[0] + ".class");
								// 对内部类的支持
								//TODO:测试这个/在Linux和Windows下是否相同
								File parentDir = new File(from.split("\\.")[0] + ".class").getParentFile();
								File[] fileList = parentDir.listFiles();
								if(fileList != null) {
									for (File file : fileList) {
										String fileName = file.getName();
										String className = relativePath.substring(relativePath.lastIndexOf(FilePathUtil.isWinOs()?"\\":"/")+1).split("\\.")[0];
										if(fileName.startsWith(className)) {
											System.out.println();
										}
										if(fileName.startsWith(className+"$")) {
											FileUtil.copyFile(file.getAbsolutePath(),
													TARGET_PAHT+"/WEB-INF/classes/" + relativePath.split("\\.")[0].replace(className,fileName));
										}
									}
								}
							}else {//处理web文件
								FileUtil.copyFile(from,TARGET_PAHT+"/WEB-INF/classes" + relativePath);
							}
						} else {
							continue;
						}
					}
					if(!isInClasspath) {
						//不是class,是webapp。照搬即可
						String temp = FilePathUtil.isWinOs()?"src\\main\\webapp\\":"src/main/webapp/";
						FileUtil.copyFile(oldPath, TARGET_PAHT + File.separator + relativePath.replace(temp, ""));
					}
				} else {
					//TODO:这里处理的是文件夹,先不管。因为空文件夹不必处理
					System.out.println("  文件夹暂不处理");
				}
			}
		}
		System.out.println("-----组装文件结束-----");
	}

	public static void main(String[] args) throws InterruptedException {
		String[] ret = CmdUtil.runCmd();
		// 0:执行完成;否则执行失败
		if (ret[0].equals("0")) {
			packFiles(ret[1]);
		} else {
			System.out.println("命令执行失败!失败原因:" + ret[1]);
			System.exit(0);
		}
	}
}

配置文件

主要是用来存储项目的来源,输出路径以及版本信息。

###注意路径统一使用正斜杠表示

#################################################################
#					Windows下路径表示方法								#
#################################################################
##项目路径(包含项目名)
proectPath=E:/data/workspace/cpams
##js css 等
targetPath=C:/Users/Administrator/Desktop/cpams
#开始版本:结束版本
version=37240:37244
#################################################################

#################################################################
#					Linux下路径表示方法								#
#################################################################
##项目路径(包含项目名)
#proectPath=/media/lihh/新加卷/data/workspace/cpams
##js css 等
#targetPath=/home/lihh/Desktop/cpams
#开始版本:结束版本
#version=37240:37244
#################################################################


#################################################################
#					弃用的配置										#
#################################################################
##要复制的classes文件夹的路径
#classPath=/media/lihh/新加卷/data/workspace/cpams/target/classes
##svn diff -r 37047:37051 --summarize
##svn st
#cmd=cd /media/lihh/新加卷/data/workspace/cpams&&svn st
##classes conf中的properties
#disRootPath=/home/lihh/Desktop/cpams/WEB-INF/classes

2018/4/25更新
使用svnkit来代替svn.exe,需要引入svnkit的jar

Scanner的hasNext恒为false

这里遇到一个问题就是Scanner,尽管是在不同的类中new Scanner和close,但是依然影响了Scanner的使用,目前看来,只能在最后一个scanner后关闭,否则靠后的class中的hasNext会一直是false。

package com.svn.util;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver;
import org.tmatesoft.svn.core.wc2.SvnLog;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import org.tmatesoft.svn.core.wc2.SvnRevisionRange;
import org.tmatesoft.svn.core.wc2.SvnTarget;
/**
 * 使用svnkit将对比内容导出为string
 * @author lihhz
 *
 */
public class SvnUtil {

	/**
	 * 使用svnkit将对比内容导出为string
	 * @return
	 * @throws SVNException 
	 * @throws IOException 
	 * @throws Exception
	 */
	@SuppressWarnings("deprecation")
	public static String getChangeStr() throws SVNException, IOException{

		@SuppressWarnings("resource")
		Scanner scanner = new Scanner(System.in);
		int index = 1;
		//用户信息
		String account = PropertyUtil.getUserAccount(),pass=PropertyUtil.getPassword();
		if(account == null || account.equals("")){
			System.out.println("没有找到用户信息!");
			System.out.println(index++ + ".请输入用户名");
			if(scanner.hasNext()){
				account=scanner.next();
				PropertyUtil.WriteProperties("userAccount", account);
			}
			System.out.println(index++ + ".请输入密码:");
			if(scanner.hasNext()){
				pass=scanner.next();
				PropertyUtil.WriteProperties("password", pass);
			}
		}
		//版本信息
		Long bVersion ,eVersion;
		while(true){
			System.out.println(index++ + ".请输入起始版本号(导出时,不包括该版本代码):");
			while(true){
				if(scanner.hasNextLong()){
					bVersion=scanner.nextLong();
					break;
				}else{
					System.out.println("起始版本号无效,请重新输入!");
				}
			}
			System.out.println(index++ + ".请输入结束版本号:");
			while(true){
				if(scanner.hasNextLong()){
					eVersion=scanner.nextLong();
					break;
				}else{
					System.out.println("结束版本号无效,请重新输入!");
				}
			}
			if(bVersion <= eVersion){
				break;
			}else{
				System.out.println("错误:结束版本号大于起始版本号");
			}
		}
		//这里不能有close,否则后边的Scanner就用不了了
//		scanner.close();
		
		final StringBuffer sb = new StringBuffer();

		// 实例化客户端管理类
		final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
		svnOperationFactory.setAuthenticationManager(new BasicAuthenticationManager(account,pass));// svn用户名密码
		
		final SvnLog log = svnOperationFactory.createLog();
		log.addRange(SvnRevisionRange.create(SVNRevision.create(bVersion), SVNRevision.create(eVersion)));
		log.setDiscoverChangedPaths(true);
		log.setSingleTarget(SvnTarget.fromURL(SVNURL.parseURIEncoded(PropertyUtil.getSvnUri())));

		System.out.println("---------------修改内容---------------");
		log.setReceiver(new ISvnObjectReceiver<SVNLogEntry>() {
			public void receive(SvnTarget svnTarget, SVNLogEntry svnLogEntry) throws SVNException {
				// 每个版本执行一次
				// System.out.println("版本:" + arg1.getRevision() + "===========作者:" + arg1.getAuthor() + "======时间:" + sdf2.format(arg1.getDate()));
				System.out.println(svnLogEntry.getMessage());
				Map<String, SVNLogEntryPath> map = svnLogEntry.getChangedPaths();
				if (map.size() > 0) {
					Set<String> set = map.keySet();
					for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) {
						String key = (String) iterator.next();
						sb.append(key.replace("/source/project/trunk/BJ/注册会计师行业监管系统/cpams/cpams/", "")).append("\r\n");
						// SVNLogEntryPath path = map.get(key);
						// System.out.println(typeDic.get(path.getType() + "") + ":" + key);
						// handleFile(key);
					}
				}
			}
		});
		log.run();
		System.out.println("----------------------------------");
		return sb.toString();
	}

}
Console

java提供System.console()方法获取Console,需要注意的是这个Console在开发工具中为null,只有在cmd中才是非空的。
使用
readPassword
**方法可以避免密码显示在cmd上。

//使用console
			//好处是:避免控制台显示密码
			//缺点是:无法再eclipse控制台调试
			Console console = System.console();
            if (console == null) {  
                throw new IllegalStateException("Console is not available!");  
            }
			if(account == null || account.equals("")){
				System.out.println("没有找到用户信息!");
	            account = console.readLine(CommonUtil.COUNTER++ + ".请输入用户名:");  
	            char[] password = console.readPassword(CommonUtil.COUNTER++ + ".请输入密码:");
	            pass = String.valueOf(password);
			}

2018/4/25更新结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值