Archived
0

BuildScript

This commit is contained in:
2016-07-13 16:09:01 +03:00
parent bf8a4f5787
commit d38eb2345e
6 changed files with 535 additions and 1 deletions

View File

@@ -16,6 +16,14 @@
<version>${asys.version}</version>
</parent>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
<build>
<finalName>${project.groupId}.${project.artifactId}-${project.version}</finalName>
<plugins>

View File

@@ -0,0 +1,268 @@
/*
* DmitriyMX <mail@dmitriymx.ru>
* 2016-06-23
*/
package asys.core.buildscript;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Скрипт формирования окружения игрового сервера.<br><br>
*
* Команды:<br>
* - <code>lnk [источник] [цель]</code> - создание ссылки;<br>
* - <code>copy [источник] [цель]</code> - копирование;<br>
* - <code>mkdir [путь]</code> - создание папки или древа папок;<br>
* - <code>unpack [архив] [папка]</code> - распаковка архива в указанную папку;<br>
* - <code>undoparent</code> - отменить запланированные действия вышестоящего скрипта.
*/
public class BuildScript {
private Logger logger = LoggerFactory.getLogger(BuildScript.class);
List<String[]> scriptLines = new ArrayList<>();
private Map<String, String> variables;
public BuildScript(String script) throws UnknowCommandException {
if (script == null || script.trim().isEmpty()) {
logger.warn("Empty script!");
return;
}
if (script.contains("\r\n")) {
logger.warn("Finded CRLF! Replaced...");
script = script.replaceAll("\r\n", "\n");
}
for (String line : script.split("\n")) {
scriptLines.add(parseCommandLine(line));
}
}
public void setVariables(Map<String, String> variables) {
this.variables = variables;
}
private String[] parseCommandLine(String line) throws UnknowCommandException {
final StringTokenizer strTok = new StringTokenizer(line, " \"\'", true);
final List<String> preArr = new ArrayList<>();
byte state = 0; // 0-normal, 1-quoting1, 2-quoting2
String buff = "";
boolean foundCmd = false;
while (strTok.hasMoreTokens()) {
String partLine = strTok.nextToken();
if (!foundCmd) {
switch (partLine) {
case "lnk":
case "copy":
case "mkdir":
case "unpack":
case "undoparent":
foundCmd = true; // cmd correct;
partLine = partLine.toLowerCase();
break;
default:
foundCmd = false; // cmd correct;
}
if (!foundCmd) {
throw new UnknowCommandException(partLine);
}
}
if (partLine.equals("\"")) {
if (state == 0) {
state = 1;
continue;
} else if (state == 1){
state = 0;
preArr.add(buff);
buff = "";
continue;
}
}
if (partLine.equals("\'")) {
if (state == 0) {
state = 2;
continue;
} else if (state == 2){
state = 0;
preArr.add(buff);
buff = "";
continue;
}
}
if (state == 1 || state == 2) {
buff += partLine;
continue;
}
if (partLine.equals(" ")) continue;
preArr.add(partLine);
}
return preArr.toArray(new String[preArr.size()]);
}
public void execute() throws CommandException {
for (String[] cmdline : scriptLines) {
switch (cmdline[0]) {
case "lnk": cmd_lnk(cmdline[1], cmdline[2]); break;
case "copy": cmd_copy(cmdline[1], cmdline[2]); break;
case "mkdir": cmd_mkdir(cmdline[1]); break;
case "unpack": cmd_unpack(cmdline[1], cmdline[2]); break;
case "undoparent": cmd_undo(); break;
default: return;
}
}
}
private String applyVariables(String string) {
if (variables != null && !variables.isEmpty()) {
for (Map.Entry<String, String> entry : variables.entrySet()) {
string = string.replace("%"+entry.getKey()+"%", entry.getValue());
}
}
return string;
}
/* Создание символьной ссылки */
private void cmd_lnk(String source, String target) throws CommandException {
try {
Files.createSymbolicLink(
Paths.get(applyVariables(target)),
Paths.get(applyVariables(source)));
} catch (IOException e) {
throw new CommandException("LNK", e);
}
}
/* Коирование */
private void cmd_copy(String source, String target) throws CommandException {
//TODO надо изюавиться от излишних Path.toFile()
Path sourcePath = Paths.get(applyVariables(source));
if (!sourcePath.toFile().exists()) {
throw new CommandException(String.format("COPY: source not found %s [%s]", source, sourcePath.toAbsolutePath()));
}
Path targetPath = Paths.get(applyVariables(target));
if (!targetPath.toFile().exists()) {
if (sourcePath.toFile().isDirectory()) {
try {
FileUtils.copyDirectory(sourcePath.toFile(), targetPath.toFile());
} catch (IOException e) {
throw new CommandException("COPY: error copy directory", e);
}
} else if (sourcePath.toFile().isFile()) {
try {
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
} catch (IOException e) {
throw new CommandException("COPY: error copy file", e);
}
} else {
throw new CommandException("COPY: unknow type source file");
}
} else {
if (sourcePath.toFile().isDirectory()) {
if (targetPath.toFile().isFile()) {
throw new CommandException("COPY: can't be copy dir to file");
} else {
try {
FileUtils.copyDirectory(sourcePath.toFile(), targetPath.toFile());
} catch (IOException e) {
throw new CommandException("COPY: error copy directory", e);
}
}
} else if (sourcePath.toFile().isFile()) {
if (targetPath.toFile().isDirectory()) {
try {
FileUtils.copyFileToDirectory(sourcePath.toFile(), targetPath.toFile());
} catch (IOException e) {
throw new CommandException("COPY: error copy file", e);
}
} else if (targetPath.toFile().isFile()) {
try {
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
} catch (IOException e) {
throw new CommandException("COPY: error copy file", e);
}
}
}
}
}
/* Создание папки/древа папок
* параметры: цель */
private void cmd_mkdir(String dir) throws CommandException {
File treeDir = Paths.get(applyVariables(dir)).toFile();
if (treeDir.mkdirs() && !treeDir.exists()) {
throw new CommandException(String.format("MKDIR: can't create dirs %s [%s]", dir, treeDir.getAbsolutePath()));
}
}
private void cmd_unpack(String source, String target) throws CommandException {
Path sourcePath = Paths.get(applyVariables(source));
if (!sourcePath.toFile().exists()) {
throw new CommandException(String.format("UNPACK: source not found %s [%s]", source, sourcePath.toFile().getAbsolutePath()));
}
if (!sourcePath.toFile().isFile()) {
throw new CommandException(String.format("UNPACK: source is not file %s [%s]", source, sourcePath.toFile().getAbsolutePath()));
}
Path targetPath = Paths.get(applyVariables(target));
if (!targetPath.toFile().exists()) {
if (targetPath.toFile().mkdirs() && !targetPath.toFile().exists()) {
throw new CommandException(String.format("UNPACK: can't create dir %s [%s]", target, targetPath.toFile().getAbsolutePath()));
}
} else if (targetPath.toFile().exists() && targetPath.toFile().isFile()) {
throw new CommandException(String.format("UNPACK: target can't be file %s [%s]", target, targetPath.toFile().getAbsolutePath()));
}
// unzip
byte[] buffer = new byte[65536];
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(sourcePath.toFile()));
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
String fileName = ze.getName();
File newFile = new File(targetPath.toFile(), fileName);
Files.createDirectories(Paths.get(newFile.getParent()));
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zis.closeEntry();
zis.close();
} catch (IOException e) {
throw new CommandException("UNPACK", e);
}
}
private void cmd_undo() {
// empty
}
}

View File

@@ -0,0 +1,15 @@
/*
* DmitriyMX <mail@dmitriymx.ru>
* 2016-06-28
*/
package asys.core.buildscript;
class CommandException extends Exception {
CommandException(String message) {
super(message);
}
CommandException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <mail@dmitriymx.ru>
* 2016-06-23
*/
package asys.core.buildscript;
class UnknowCommandException extends CommandException {
UnknowCommandException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,219 @@
/*
* DmitriyMX <mail@dmitriymx.ru>
* 2016-06-23
*/
package asys.core.buildscript;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.junit.Assert.*;
public class TestBuildScript {
private static File tempDirectory;
private Map<String, String> variables = new HashMap<>();
@BeforeClass
public static void beforeTestClass() throws IOException {
tempDirectory = new File(FileUtils.getTempDirectory(), "test_buildscript");
if (tempDirectory.exists()) {
if (tempDirectory.isDirectory()) {
FileUtils.deleteDirectory(tempDirectory);
if (tempDirectory.exists()) {
throw new IOException(String.format("Can't delete temp directory [%s]", tempDirectory.getAbsolutePath()));
}
} else {
if (!tempDirectory.delete()) {
throw new IOException(String.format("Can't delete temp file [%s]", tempDirectory.getAbsolutePath()));
}
}
}
if (!tempDirectory.mkdir()) {
throw new IOException(String.format("Can't create temp dir [%s]", tempDirectory.getAbsolutePath()));
}
}
@Before
public void beforeTest() throws IOException {
variables.clear();
variables.put("dir", tempDirectory.getAbsolutePath());
File[] files = tempDirectory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
FileUtils.deleteDirectory(file);
assertFalse(file.exists());
} else {
assertTrue(file.delete());
}
}
}
}
@Test
public void testParseCommandLine() throws UnknowCommandException {
BuildScript buildScript = new BuildScript("lnk \"%distr%/spigot 1.8.8.jar\" '%srv%/spi 1 got.jar'");
String[] partsLine = buildScript.scriptLines.get(0);
assertNotNull(partsLine);
assertEquals(3, partsLine.length);
assertEquals("lnk", partsLine[0]);
assertEquals("%distr%/spigot 1.8.8.jar", partsLine[1]);
assertEquals("%srv%/spi 1 got.jar", partsLine[2]);
}
@Test(expected = UnknowCommandException.class)
public void testUnknowCommand() throws UnknowCommandException {
new BuildScript("ololo push pop");
}
@Test
public void testExecuteMkdir() throws CommandException, IOException {
String script = "mkdir %dir%/someDir";
BuildScript buildScript = new BuildScript(script);
buildScript.setVariables(variables);
buildScript.execute();
File dir = new File(tempDirectory, "someDir");
assertTrue(dir.exists());
}
@Test
public void testExecuteLnk() throws CommandException, IOException {
String script = "mkdir %dir%/someDir\n" +
"lnk %dir%/someDir %dir%/dirLink";
BuildScript buildScript = new BuildScript(script);
buildScript.setVariables(variables);
buildScript.execute();
File dir = new File(tempDirectory, "someDir");
assertTrue(dir.exists());
assertTrue(dir.isDirectory());
File dirLink = new File(tempDirectory, "dirLink");
assertTrue(dirLink.exists());
assertTrue(dirLink.isDirectory());
}
private void prepareTestExecuteCopy() throws IOException {
File dir = new File(tempDirectory, "someDir");
assertTrue(dir.mkdir());
FileWriter fw = new FileWriter(new File(dir, "file1"));
fw.write("123\n456");
fw.close();
fw = new FileWriter(new File(dir, "file2"));
fw.write("789\n101112");
fw.close();
assertTrue(new File(dir, "indir").mkdir());
fw = new FileWriter(new File(dir, "indir/file3"));
fw.write("131415\n161718");
fw.close();
}
@Test
public void testExecuteCopy() throws CommandException, IOException {
prepareTestExecuteCopy();
String script = "copy %dir%/someDir %dir%/newDir";
BuildScript buildScript = new BuildScript(script);
buildScript.setVariables(variables);
buildScript.execute();
// проверка результатов
File file = new File(tempDirectory, "newDir/file1");
assertTrue(file.exists());
assertTrue(file.isFile());
file = new File(tempDirectory, "newDir/file2");
assertTrue(file.exists());
assertTrue(file.isFile());
file = new File(tempDirectory, "newDir/indir");
assertTrue(file.exists());
assertTrue(file.isDirectory());
file = new File(tempDirectory, "newDir/indir/file3");
assertTrue(file.exists());
assertTrue(file.isFile());
}
private void genListFile(List<String> list, File node, String sourcePathRoot) {
if (node.isFile()) {
String filePath = node.getAbsolutePath();
list.add(filePath.substring(sourcePathRoot.length()+1, filePath.length()));
} else if (node.isDirectory()) {
File[] files = node.listFiles();
if (files != null) {
for (File file : files) {
genListFile(list, file, sourcePathRoot);
}
}
}
}
private void prepareTestExeuteUnzip() throws IOException {
prepareTestExecuteCopy();
List<String> listFiles = new ArrayList<>();
genListFile(listFiles, new File(tempDirectory, "someDir"), tempDirectory.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(new File(tempDirectory, "arch.zip"));
ZipOutputStream zos = new ZipOutputStream(fos);
byte[] buffer = new byte[16];
for (String fileStr : listFiles) {
ZipEntry zipEntry = new ZipEntry(fileStr);
zos.putNextEntry(zipEntry);
FileInputStream fis = new FileInputStream(tempDirectory.getAbsolutePath() + File.separator + fileStr);
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
fis.close();
}
zos.closeEntry();
zos.close();
}
@Test
public void testExeuteUnzip() throws CommandException, IOException {
prepareTestExeuteUnzip();
String script = "unpack %dir%/arch.zip %dir%/unpack";
BuildScript buildScript = new BuildScript(script);
buildScript.setVariables(variables);
buildScript.execute();
// проверка результатов
File file = new File(tempDirectory, "unpack/someDir/file1");
assertTrue(file.exists());
assertTrue(file.isFile());
file = new File(tempDirectory, "unpack/someDir/file2");
assertTrue(file.exists());
assertTrue(file.isFile());
file = new File(tempDirectory, "unpack/someDir/indir");
assertTrue(file.exists());
assertTrue(file.isDirectory());
file = new File(tempDirectory, "unpack/someDir/indir/file3");
assertTrue(file.exists());
assertTrue(file.isFile());
}
}