Selaa lähdekoodia

Deploy command.

HorridoJoho 3 vuotta sitten
vanhempi
sitoutus
502d63dd54

+ 0 - 5
src/main/java/com/l2jserver/cli/L2JServerCLI.java

@@ -52,11 +52,6 @@ import picocli.CommandLine.Command;
 	ConfigurationEditorGUICommand.class
 })
 public class L2JServerCLI implements Callable<Void> {
-	
-    public static final String DEFAULT_LOGIN_SOURCE_DIR = "./l2j/git/l2j-server-login";
-    public static final String DEFAULT_GAME_SOURCE_DIR = "./l2j/git/l2j-server-game";
-    public static final String DEFAULT_DATAPACK_SOURCE_DIR = "./l2j/git/l2j-server-datapack";
-
 	@Override
 	public Void call() {
 		System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

+ 13 - 2
src/main/java/com/l2jserver/cli/command/AbstractCommand.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 L2J Server
+ * Copyright © 2019-2022 L2J Server
  *
  * This file is part of L2J Server.
  *
@@ -28,7 +28,18 @@ import java.io.IOException;
  */
 public abstract class AbstractCommand implements Runnable {
 	protected static final String YES = "y";
-	
+
+	protected static final String DEFAULT_LOGIN_REPO = "https://bitbucket.org/l2jserver/l2j-server-login.git";
+	protected static final String DEFAULT_GAME_REPO = "https://bitbucket.org/l2jserver/l2j-server-game.git";
+	protected static final String DEFAULT_DATAPACK_REPO = "https://bitbucket.org/l2jserver/l2j-server-datapack.git";
+
+	protected static final String DEFAULT_LOGIN_SOURCE_DIR = "./l2j/git/l2j-server-login";
+	protected static final String DEFAULT_GAME_SOURCE_DIR = "./l2j/git/l2j-server-game";
+	protected static final String DEFAULT_DATAPACK_SOURCE_DIR = "./l2j/git/l2j-server-datapack";
+
+	protected static final String DEFAULT_LOGIN_DEPLOY_DIR = "./l2j/deploy/login";
+	protected static final String DEFAULT_GAME_DEPLOY_DIR = "./l2j/deploy/game";
+
 	protected static final FilterInputStream FILTER_INPUT_STREAM = new FilterInputStream(System.in) {
 		@Override
 		public void close() throws IOException {

+ 28 - 30
src/main/java/com/l2jserver/cli/command/BuildCommand.java

@@ -30,8 +30,6 @@ import org.apache.maven.shared.invoker.MavenInvocationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.l2jserver.cli.L2JServerCLI;
-
 import picocli.CommandLine.Command;
 
 /**
@@ -42,38 +40,38 @@ import picocli.CommandLine.Command;
 @Command(name = "build", aliases = "b")
 public class BuildCommand extends AbstractCommand {
 
-    private static final Logger LOG = LoggerFactory.getLogger(BuildCommand.class);
+	private static final Logger LOG = LoggerFactory.getLogger(BuildCommand.class);
 
-    @Override
-    public void run() {
-        try {
-            boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+	@Override
+	public void run() {
+		try {
+			boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
 
-            Properties properties = new Properties();
-            properties.setProperty("skipTests", "true");
+			Properties properties = new Properties();
+			properties.setProperty("skipTests", "true");
 
-            System.out.println("Building L2J Loginserver");
-            executeMavenWrapper("install", L2JServerCLI.DEFAULT_LOGIN_SOURCE_DIR, properties, isWindows);
+			System.out.println("Building L2J Loginserver");
+			executeMavenWrapper("install", DEFAULT_LOGIN_SOURCE_DIR, properties, isWindows);
 
-            System.out.println("Building L2J Gameserver");
-            executeMavenWrapper("install", L2JServerCLI.DEFAULT_GAME_SOURCE_DIR, properties, isWindows);
+			System.out.println("Building L2J Gameserver");
+			executeMavenWrapper("install", DEFAULT_GAME_SOURCE_DIR, properties, isWindows);
 
-            System.out.println("Building L2J DataPack");
-            executeMavenWrapper("compile", L2JServerCLI.DEFAULT_DATAPACK_SOURCE_DIR, properties, isWindows);
-        } catch (Exception e) {
-            LOG.error("Unable to build the code!", e);
-        }
-    }
+			System.out.println("Building L2J DataPack");
+			executeMavenWrapper("install", DEFAULT_DATAPACK_SOURCE_DIR, properties, isWindows);
+		} catch (Exception e) {
+			LOG.error("Unable to build the code!", e);
+		}
+	}
 
-    private final void executeMavenWrapper(String goal, String sourceDir, Properties properties, boolean isWindows)
-            throws MavenInvocationException {
-        InvocationRequest request = new DefaultInvocationRequest();
-        request.setPomFile(new File(sourceDir + "/pom.xml"));
-        request.setGoals(Collections.singletonList("install"));
-        request.setProperties(properties);
-        Invoker invoker = new DefaultInvoker();
-        invoker.setMavenHome(new File(sourceDir));
-        invoker.setMavenExecutable(new File("mvnw" + (isWindows ? ".cmd" : "")));
-        invoker.execute(request);
-    }
+	private final void executeMavenWrapper(String goal, String sourceDir, Properties properties, boolean isWindows)
+	        throws MavenInvocationException {
+		InvocationRequest request = new DefaultInvocationRequest();
+		request.setPomFile(new File(sourceDir + "/pom.xml"));
+		request.setGoals(Collections.singletonList("install"));
+		request.setProperties(properties);
+		Invoker invoker = new DefaultInvoker();
+		invoker.setMavenHome(new File(sourceDir));
+		invoker.setMavenExecutable(new File("mvnw" + (isWindows ? ".cmd" : "")));
+		invoker.execute(request);
+	}
 }

+ 49 - 54
src/main/java/com/l2jserver/cli/command/CodeCommand.java

@@ -24,7 +24,6 @@ import org.eclipse.jgit.api.Git;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.l2jserver.cli.L2JServerCLI;
 import com.l2jserver.cli.model.CloneType;
 import com.l2jserver.cli.util.LoggerProgressMonitor;
 
@@ -38,81 +37,77 @@ import picocli.CommandLine.Option;
  */
 @Command(name = "code", aliases = "c")
 public class CodeCommand extends AbstractCommand {
-	
+
 	private static final Logger LOG = LoggerFactory.getLogger(CodeCommand.class);
-	
+
 	private static final LoggerProgressMonitor LOGGER_PROGRESS_MONITOR = new LoggerProgressMonitor(LOG);
-	
-	private static final String DEFAULT_LOGIN_REPO = "https://bitbucket.org/l2jserver/l2j-server-login.git";
-	private static final String DEFAULT_GAME_REPO = "https://bitbucket.org/l2jserver/l2j-server-game.git";
-	private static final String DEFAULT_DATAPACK_REPO = "https://bitbucket.org/l2jserver/l2j-server-datapack.git";
-	
+
 	@Option(names = "--login-repository", defaultValue = DEFAULT_LOGIN_REPO, description = "Login repository")
 	private String loginRepository = DEFAULT_LOGIN_REPO;
 	@Option(names = "--game-repository", defaultValue = DEFAULT_GAME_REPO, description = "Game repository")
 	private String gameRepository = DEFAULT_GAME_REPO;
 	@Option(names = "--datapack-repository", defaultValue = DEFAULT_DATAPACK_REPO, description = "Datapack repository")
 	private String datapackRepository = DEFAULT_DATAPACK_REPO;
-	
-	@Option(names = "--login-directory", defaultValue = L2JServerCLI.DEFAULT_LOGIN_SOURCE_DIR, description = "Login directory")
-	private File loginDirectory = new File(L2JServerCLI.DEFAULT_LOGIN_SOURCE_DIR);
-	@Option(names = "--game-directory", defaultValue = L2JServerCLI.DEFAULT_GAME_SOURCE_DIR, description = "Game directory")
-	private File gameDirectory = new File(L2JServerCLI.DEFAULT_GAME_SOURCE_DIR);
-	@Option(names = "--datapack-directory", defaultValue = L2JServerCLI.DEFAULT_DATAPACK_SOURCE_DIR, description = "DataPack directory")
-	private File datapackDirectory = new File(L2JServerCLI.DEFAULT_DATAPACK_SOURCE_DIR);
-	
+
+	@Option(names = "--login-directory", defaultValue = DEFAULT_LOGIN_SOURCE_DIR, description = "Login directory")
+	private File loginDirectory = new File(DEFAULT_LOGIN_SOURCE_DIR);
+	@Option(names = "--game-directory", defaultValue = DEFAULT_GAME_SOURCE_DIR, description = "Game directory")
+	private File gameDirectory = new File(DEFAULT_GAME_SOURCE_DIR);
+	@Option(names = "--datapack-directory", defaultValue = DEFAULT_DATAPACK_SOURCE_DIR, description = "DataPack directory")
+	private File datapackDirectory = new File(DEFAULT_DATAPACK_SOURCE_DIR);
+
 	@Option(names = "--clone", defaultValue = "ALL", description = "Clone ALL|LOGIN|GAME|DATAPACK")
 	private CloneType cloneType = CloneType.ALL;
-	
+
 	@Override
 	public void run() {
 		try {
 			switch (cloneType) {
-				case ALL: {
-                    LOG.info("Cloning L2J Loginserver");
-                    cloneRepository(loginRepository, loginDirectory);
+			case ALL: {
+				LOG.info("Cloning L2J Loginserver");
+				cloneRepository(loginRepository, loginDirectory);
 
-					LOG.info("Cloning L2J Gameserver");
-					cloneRepository(gameRepository, gameDirectory);
-					
-					LOG.info("Cloning L2J DataPack");
-					cloneRepository(datapackRepository, datapackDirectory);
-					break;
-				}
-				case LOGIN: {
-                    LOG.info("Cloning L2J Loginserver");
-                    cloneRepository(loginRepository, loginDirectory);
-                    break;
-				}
-				case GAME: {
-					LOG.info("Cloning L2J Gameserver");
-					cloneRepository(gameRepository, gameDirectory);
-					break;
-				}
-				case DATAPACK: {
-					LOG.info("Cloning L2J DataPack");
-					cloneRepository(datapackRepository, datapackDirectory);
-					break;
-				}
+				LOG.info("Cloning L2J Gameserver");
+				cloneRepository(gameRepository, gameDirectory);
+
+				LOG.info("Cloning L2J DataPack");
+				cloneRepository(datapackRepository, datapackDirectory);
+				break;
+			}
+			case LOGIN: {
+				LOG.info("Cloning L2J Loginserver");
+				cloneRepository(loginRepository, loginDirectory);
+				break;
+			}
+			case GAME: {
+				LOG.info("Cloning L2J Gameserver");
+				cloneRepository(gameRepository, gameDirectory);
+				break;
+			}
+			case DATAPACK: {
+				LOG.info("Cloning L2J DataPack");
+				cloneRepository(datapackRepository, datapackDirectory);
+				break;
+			}
 			}
 		} catch (Exception ex) {
 			LOG.error("Unable to get the code!", ex);
 		}
 	}
-	
+
 	private void cloneRepository(String repository, File directory) {
-	    try {
-	        if (directory.exists()) {
-	            Git.open(directory).pull();
-	        } else {
-	            Git.cloneRepository() //
-	                .setURI(repository) //
-	                .setDirectory(directory) //
-	                .setProgressMonitor(LOGGER_PROGRESS_MONITOR) //
-	                .call();
-	        }
+		try {
+			if (directory.exists()) {
+				Git.open(directory).pull();
+			} else {
+				Git.cloneRepository() //
+					.setURI(repository) //
+					.setDirectory(directory) //
+					.setProgressMonitor(LOGGER_PROGRESS_MONITOR) //
+					.call();
+			}
 		} catch (Exception ex) {
-		    LOG.error("Unable to get the code!", ex);
+			LOG.error("Unable to get the code!", ex);
 		}
 	}
 }

+ 90 - 3
src/main/java/com/l2jserver/cli/command/DeployCommand.java

@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 L2J Server
+ * Copyright © 2019-2022 L2J Server
  *
  * This file is part of L2J Server.
  *
@@ -18,6 +18,19 @@
  */
 package com.l2jserver.cli.command;
 
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import picocli.CommandLine.Command;
 
 /**
@@ -27,10 +40,84 @@ import picocli.CommandLine.Command;
  */
 @Command(name = "deploy", aliases = "d")
 public class DeployCommand extends AbstractCommand {
+	private static final Logger LOG = LoggerFactory.getLogger(DeployCommand.class);
 	
 	@Override
 	public void run() {
-		// TODO(Zoey76): Implement.
-		System.out.println("Deploying");
+		try {
+			LOG.info("Deploying L2J Loginserver");
+			processArtifact(Paths.get(DEFAULT_LOGIN_SOURCE_DIR), Paths.get(DEFAULT_LOGIN_DEPLOY_DIR));
+			
+			LOG.info("Deploying L2J Gameserver");
+			processArtifact(Paths.get(DEFAULT_GAME_SOURCE_DIR), Paths.get(DEFAULT_GAME_DEPLOY_DIR));
+			
+			LOG.info("Deploying L2J DataPack");
+			processArtifact(Paths.get(DEFAULT_DATAPACK_SOURCE_DIR), Paths.get(DEFAULT_GAME_DEPLOY_DIR));
+		} catch (Exception e) {
+			LOG.error("Unable to deploy components!", e);
+		}
+	}
+
+	public void processArtifact(Path srcDirPath, Path dstDirPath) throws Exception {
+		Files.list(Paths.get(srcDirPath.toString(), "target")).forEach(p->{
+			if (!p.toString().endsWith(".zip")) {
+				return;
+			}
+			
+			LOG.info("Processing zip file {}", p.toString());
+
+			try {
+				processZip(p, dstDirPath);
+			} catch (Exception e) {
+				LOG.error("Unable to process zip file!", e);
+			}
+		});
+	}
+	
+	public void processZip(Path zipFilePath, Path dstDirPath) throws Exception {
+		Map<String, String> env = new HashMap<>();
+		env.put("create", "true");
+		URI uri = URI.create("jar:file:" + zipFilePath.toAbsolutePath().toUri().getPath());
+		try (FileSystem zipFs = FileSystems.newFileSystem(uri, env)) {
+			// mkdirs if not exists
+			if (!Files.exists(dstDirPath)) {
+				dstDirPath.toFile().mkdirs();
+			}
+
+			for (Path p : zipFs.getRootDirectories()) {
+				processZipEntry(p, dstDirPath);
+			}
+		}
+	}
+	
+	public void processZipEntry(Path zipFsPath, Path dstDirPath) throws Exception {
+		if (Files.isDirectory(zipFsPath)) {
+			LOG.info("Process directory {}", zipFsPath.toString());
+			Files.list(zipFsPath).forEach(p->{
+				try {
+					processZipEntry(p, dstDirPath);
+				} catch (Exception e) {
+					LOG.info("Unable to unzip {}!", p, e);
+				}
+			});
+		} else if (Files.isRegularFile(zipFsPath)) {
+			checkZipSlip(dstDirPath, zipFsPath);
+
+			Path outFilePath = Paths.get(dstDirPath.toString(), zipFsPath.toString());
+			Path parentDirPath = outFilePath.getParent();
+			if (!Files.exists(parentDirPath)) {
+				parentDirPath.toFile().mkdirs();
+			}
+
+			Files.copy(zipFsPath, Paths.get(dstDirPath.toString(), zipFsPath.toString()), StandardCopyOption.REPLACE_EXISTING);
+		}
+	}
+
+	public static void checkZipSlip(Path dstDirPath, Path zipFsPath) throws Exception {
+		Path dstFilePath = Paths.get(dstDirPath.toString(), zipFsPath.toString());
+
+		if (!dstFilePath.toAbsolutePath().startsWith(dstDirPath.toAbsolutePath())) {
+			throw new Exception("ZipSlipAttack detected: " + zipFsPath.toString());
+		}
 	}
 }