package bs.util.tool.ant;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.Properties;
import javax.swing.JTextArea;
import bs.util.web.tool.eclipse.ProjectPropertiesDeal;
import bs.util.web.tool.eclipse.ProjectPropertiesDealInterface;
/**
* Ant Script Auto Build.
*
* @author Baishui2004
* @version 1.1
* @date 2013-4-5
*/
public class AntScriptAutoBuild {
/**
* Eclipse的Java Project、Dynamic Web Project或者MyEclipse的Web Project绝对路径地址.
*/
private String projectPath;
/**
* Project properties.
*/
private ProjectPropertiesDealInterface projectProperties;
/**
* AntScriptAutoBuild conf properties.
*/
private Properties confProperties;
/**
* 生成Ant 脚本属性文件路径.
*/
private String antPropertiesFilePath;
/**
* 生成Ant 脚本文件路径.
*/
private String antScriptFilePath;
/**
* 是否备份已存在的同名构建属性脚本及脚本.
*/
private boolean isBak = true;
public void setIsBak(boolean isBak) {
this.isBak = isBak;
}
/**
* 运行日志输出文本域.
*/
private JTextArea runLogTextArea;
public void setRunLogTextArea(JTextArea runLogTextArea) {
this.runLogTextArea = runLogTextArea;
}
/**
* 输出.
*/
private void print(String log) {
if (runLogTextArea != null) {
runLogTextArea.append(log + "\n");
} else {
System.out.print(log + "\n");
}
}
/**
* Main入口.
*
* <pre>
* 只接受传入一个参数, 即Eclipse的Dynamic Web Project或者MyEclipse的Web Project绝对路径地址.
* </pre>
*/
public static void main(String[] args) throws IOException, URISyntaxException {
if (args.length == 2) {
AntScriptAutoBuild build = new AntScriptAutoBuild();
ProjectPropertiesDealInterface propertiesDeal = new ProjectPropertiesDeal();
propertiesDeal.deal(args[0]);
build.autoBuild(args[0], propertiesDeal, args[1]);
} else {
throw new IllegalArgumentException("Parameters error.");
}
}
/**
* 根据Eclipse/MyEclipse Project属性创建Ant脚本.
*/
public void autoBuild(String projectPath, ProjectPropertiesDealInterface properties, String taskNames)
throws IOException, URISyntaxException {
this.projectPath = projectPath;
this.projectProperties = properties;
this.antPropertiesFilePath = this.projectPath + "/build.properties";
this.antScriptFilePath = this.projectPath + "/build.xml";
this.confProperties = new Properties();
InputStream in = null;
try {
in = new FileInputStream(new File(getActualPath("conf/AntScriptAutoBuild/conf.properties")));
this.confProperties.load(in);
} finally {
if (in != null) {
in.close();
}
}
String actualTask = getActualAndSortTaskNames(taskNames);
String specialTask = getSpecialAndSortTaskNames(taskNames);
String printTask = actualTask + "," + specialTask;
if (printTask.startsWith(",")) {
printTask = printTask.substring(1);
}
if (printTask.endsWith(",")) {
printTask = printTask.substring(0, printTask.length() - 1);
}
print("Ant Task: " + printTask.replace(",", ", ") + ".\n");
appendPropertiesAndScriptFile(actualTask, specialTask);
autoReBuildPropertiesFile();
print("\nAuto build Ant Script Done.");
}
/**
* 重新排序Ant Task.
*/
private String getActualAndSortTaskNames(String taskNames) {
String baseTask = this.confProperties.getProperty("baseTask").trim();
String javaTask = this.confProperties.getProperty("javaTask").trim();
String javaWebTask = this.confProperties.getProperty("javaWebTask").trim();
String generalTask = this.confProperties.getProperty("generalTask").trim();
String allTask = baseTask + "," + javaTask + "," + javaWebTask + "," + generalTask + ",";
String[] tasks = allTask.split(",");
StringBuilder sortTaskName = new StringBuilder();
for (String task : tasks) {
if (("," + taskNames.toLowerCase() + ",").contains("," + task.toLowerCase() + ",")) {
if (!(!this.projectProperties.isJavaWebProject() && ("," + javaWebTask.toLowerCase() + ",")
.contains("," + task.toLowerCase() + ","))) {
sortTaskName.append("," + task);
}
}
}
return sortTaskName.length() != 0 ? sortTaskName.substring(1) : sortTaskName.toString();
}
/**
* 特殊Ant Task.
*/
private String getSpecialAndSortTaskNames(String taskNames) {
String specialTask = this.confProperties.getProperty("specialTask").trim();
String[] tasks = specialTask.split(",");
StringBuilder sortTaskName = new StringBuilder();
for (String task : tasks) {
if (("," + taskNames.toLowerCase() + ",").contains("," + task.toLowerCase() + ",")) {
sortTaskName.append("," + task);
}
}
return sortTaskName.length() != 0 ? sortTaskName.substring(1) : sortTaskName.toString();
}
/**
* 组装build.properties及build.xml.
*/
private void appendPropertiesAndScriptFile(String taskNames, String specialTaskNames) throws IOException,
URISyntaxException {
// build.properties
appendFile(this.antPropertiesFilePath, getActualPath("conf/AntScriptAutoBuild/properties/"), taskNames,
"#Auto build properties, " + new Date() + ".\n", "");
// build.xml
String xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + "\n" + "<project name=\""
+ this.projectProperties.getProjectName() + "\" default=\"all\" basedir=\".\">" + "\n\n"
+ " <!-- properties属性配置文件 -->\n" + " <property file=\"build.properties\" />";
String xmlEnd = "\n <!-- 全部任务 -->\n" + " <target name=\"all\" depends=\"";
appendFile(this.antScriptFilePath, getActualPath("conf/AntScriptAutoBuild/script/"), taskNames, xmlHeader,
xmlEnd + taskNames + "\" />" + "\n\n" + "</project>");
// 特殊任务,此类任务每个任务单独生成一个构建脚本build-taskName.xml
if (specialTaskNames.length() != 0) {
String[] specialTasks = specialTaskNames.split(",");
for (String task : specialTasks) {
appendFile(this.antScriptFilePath.substring(0, this.antScriptFilePath.length() - 4) + "-" + task
+ ".xml", getActualPath("conf/AntScriptAutoBuild/script/"), task, xmlHeader, xmlEnd + task
+ "\" />" + "\n\n" + "</project>");
}
}
}
/**
* 根据taskNames拼装文件.
*/
private void appendFile(String mergerFilePath, String folderPath, String taskNames, String header, String end)
throws IOException {
File mergerFile = new File(mergerFilePath);
if (mergerFile.exists()) {
if (isBak) {
String reNameMergerFilePath = mergerFilePath + "." + new Date().getTime() + "bak";
File reNameMergerFile = new File(reNameMergerFilePath);
mergerFile.renameTo(reNameMergerFile);
print("old file \"" + mergerFile.getName() + "\" renamed to " + "\"" + reNameMergerFile.getName()
+ "\".");
} else {
print("File \"" + mergerFile.getName() + "\" exist but be covered.");
}
}
StringBuilder inSb = new StringBuilder(header + "\n");
String[] tasks = taskNames.split(",");
for (String task : tasks) {
inSb.append("\n");
appendFile(inSb, folderPath + task);
}
inSb.append("\n" + end);
OutputStream fos = new FileOutputStream(mergerFile);
// 不采用fos.write(bytes)是为了保证输出文件的存储格式为"UTF-8"
// fos.write(inSb.toString().getBytes());
// 使用下面的方式能够保证输出文件的存储格式为"UTF-8"
Writer writer = new OutputStreamWriter(fos, "UTF-8");
writer.write(inSb.toString());
writer.flush();
writer.close();
fos.close();
if (!System.getProperty("os.name").contains("Windows")) {
try {
Runtime.getRuntime().exec(new String[] { "chmod", "755", mergerFilePath }).waitFor();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* 拼装文件.
*/
private void appendFile(StringBuilder inSb, String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
return;
}
InputStream in = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(in, "UTF-8");
BufferedReader bfReader = new BufferedReader(reader);
while (true) {
String line = bfReader.readLine();
if (line == null) {
break;
}
inSb.append(line).append("\n");
}
in.close();
reader.close();
bfReader.close();
}
/**
* 根据Eclipse/MyEclipse Project属性重设build.properties部分属性值.
*/
private void autoReBuildPropertiesFile() throws IOException {
File propertiesFile = new File(this.antPropertiesFilePath);
InputStream in = new FileInputStream(propertiesFile);
InputStreamReader reader = new InputStreamReader(in, "UTF-8");
BufferedReader bfReader = new BufferedReader(reader);
StringBuilder inSb = new StringBuilder();
while (true) {
String line = bfReader.readLine();
if (line == null) {
break;
}
if (line.startsWith("project.name=")) {
line = "project.name=" + this.projectProperties.getProjectName();
} else if (line.startsWith("dir.lib=") && this.projectProperties.isJavaWebProject()) {
line = "dir.lib=" + this.projectProperties.getWebappPath() + "/WEB-INF/lib";
} else if (line.startsWith("dir.web=") && this.projectProperties.isJavaWebProject()) {
line = "dir.web=" + this.projectProperties.getWebappPath();
} else if (line.startsWith("project.compile.source=")) {
line = "project.compile.source=" + this.projectProperties.getCompileSource();
} else if (line.startsWith("project.compile.target=")) {
line = "project.compile.target=" + this.projectProperties.getCompileTarget();
} else if (line.startsWith("dir.src=")) {
line = "dir.src=" + this.projectProperties.getJavaSourcesPath()[0];
} else if (line.startsWith("dir.classes=")) {
line = "dir.classes=" + this.projectProperties.getOutputPath();
}
inSb.append(line).append("\n");
}
OutputStream fos = new FileOutputStream(propertiesFile);
// 不采用fos.write(bytes)是为了保证输出文件的存储格式为"UTF-8"
// fos.write(inSb.toString().getBytes());
// 使用下面的方式能够保证输出文件的存储格式为"UTF-8"
Writer writer = new OutputStreamWriter(fos, "UTF-8");
writer.write(inSb.toString());
writer.flush();
writer.close();
in.close();
reader.close();
bfReader.close();
fos.close();
}
/**
* 获取与Jar lib目录同级的文件(夹)或同级文件夹的子文件(夹)的绝对路径.
*/
public static String getActualPath(String path) {
return LIB_PARENT_PATH + path;
}
/**
* Jar lib目录的父路径.
*/
private static String LIB_PARENT_PATH = getLibParentPath();
/**
* 获取Jar lib目录的父路径.
*/
private static String getLibParentPath() {
String classResource = AntScriptAutoBuild.class.getName().replace(".", "/") + ".class";
String path = "";
try {
path = AntScriptAutoBuild.class.getClassLoader().getResource(classResource).getPath();
path = path.replace("+", "%2b"); // "+"号decode后为空格" ","%2b"号decode后为"+"号
path = URLDecoder.decode(path, "UTF-8");
path = path.substring(0, path.length() - classResource.length());
if (path.contains(".jar!")) {
path = path.substring(5, path.indexOf(".jar!") + 4);
path = path.substring(0, path.lastIndexOf("/"));
path = path.substring(0, path.length() - "lib".length());
} else {
path = path.substring(0, path.length() - "classes".length() - 1);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return path;
}
}