diff --git a/core/pom.xml b/core/pom.xml
index 943e84a..5126b7d 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -16,6 +16,14 @@
${asys.version}
+
+
+ commons-io
+ commons-io
+ 2.5
+
+
+
${project.groupId}.${project.artifactId}-${project.version}
diff --git a/core/src/main/java/asys/core/buildscript/BuildScript.java b/core/src/main/java/asys/core/buildscript/BuildScript.java
new file mode 100644
index 0000000..49454b9
--- /dev/null
+++ b/core/src/main/java/asys/core/buildscript/BuildScript.java
@@ -0,0 +1,268 @@
+/*
+ * DmitriyMX
+ * 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;
+
+/**
+ * Скрипт формирования окружения игрового сервера.
+ *
+ * Команды:
+ * - lnk [источник] [цель] - создание ссылки;
+ * - copy [источник] [цель] - копирование;
+ * - mkdir [путь] - создание папки или древа папок;
+ * - unpack [архив] [папка] - распаковка архива в указанную папку;
+ * - undoparent - отменить запланированные действия вышестоящего скрипта.
+ */
+public class BuildScript {
+ private Logger logger = LoggerFactory.getLogger(BuildScript.class);
+ List scriptLines = new ArrayList<>();
+ private Map 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 variables) {
+ this.variables = variables;
+ }
+
+ private String[] parseCommandLine(String line) throws UnknowCommandException {
+ final StringTokenizer strTok = new StringTokenizer(line, " \"\'", true);
+ final List 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 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
+ }
+}
diff --git a/core/src/main/java/asys/core/buildscript/CommandException.java b/core/src/main/java/asys/core/buildscript/CommandException.java
new file mode 100644
index 0000000..3ecef67
--- /dev/null
+++ b/core/src/main/java/asys/core/buildscript/CommandException.java
@@ -0,0 +1,15 @@
+/*
+ * DmitriyMX
+ * 2016-06-28
+ */
+package asys.core.buildscript;
+
+class CommandException extends Exception {
+ CommandException(String message) {
+ super(message);
+ }
+
+ CommandException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/core/src/main/java/asys/core/buildscript/UnknowCommandException.java b/core/src/main/java/asys/core/buildscript/UnknowCommandException.java
new file mode 100644
index 0000000..81d8555
--- /dev/null
+++ b/core/src/main/java/asys/core/buildscript/UnknowCommandException.java
@@ -0,0 +1,11 @@
+/*
+ * DmitriyMX
+ * 2016-06-23
+ */
+package asys.core.buildscript;
+
+class UnknowCommandException extends CommandException {
+ UnknowCommandException(String message) {
+ super(message);
+ }
+}
diff --git a/core/src/test/java/asys/core/buildscript/TestBuildScript.java b/core/src/test/java/asys/core/buildscript/TestBuildScript.java
new file mode 100644
index 0000000..cbe3aa7
--- /dev/null
+++ b/core/src/test/java/asys/core/buildscript/TestBuildScript.java
@@ -0,0 +1,219 @@
+/*
+ * DmitriyMX
+ * 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 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 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 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());
+ }
+}
diff --git a/pom.xml b/pom.xml
index c7d9f86..bcb1118 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,6 +10,7 @@
0.2
UTF-8
1.8
+ 1.7.20
asys
@@ -25,13 +26,25 @@
org.slf4j
slf4j-api
- 1.7.20
+ ${slf4j.version}
org.osgi
org.osgi.core
6.0.0
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.slf4j
+ slf4j-jdk14
+ ${slf4j.version}
+ test
+