borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java
@@ -1,26 +1,84 @@ package de.micromata.borgbutler; import de.micromata.borgbutler.config.BorgRepoConfig; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.naming.Context; import java.io.File; /** * Represents a command to be queued for executing. */ public class BorgCommand { private Logger log = LoggerFactory.getLogger(BorgCommand.class); /** * The current Thread assigned to this command sets the state and reads for the state {@link State#TERMINATE_SIGNAL_RECEIVED}. * If received, the thread will be terminated without executing the borg command. */ public enum State { /** * This command is waiting in the queue. */ WAITING_IN_QUEUE, /** * This command is running (beeing executed). */ RUNNING, /** * This command should not be terminated before starting. */ TERMINATE_SIGNAL_RECEIVED} public enum ResultStatus { OK, ERROR } @Getter @Setter File workingDir; String[] args; String[] params; private File workingDir; @Getter private String[] args; @Getter private String[] params; @Getter @Setter BorgRepoConfig repoConfig; private BorgRepoConfig repoConfig; @Getter @Setter String command; private String command; @Getter @Setter String archive; private String archive; @Getter private State state; /** * For displaying and information purposes for the user only, when browsing the current command queue. */ @Setter @Getter private String description; /** * The result of the call will be written to this String. */ @Getter @Setter(AccessLevel.PACKAGE) private String response; @Getter @Setter(AccessLevel.PACKAGE) private ResultStatus resultStatus; /** * Requests the thread handling this command to terminate / cancel this action. */ public void terminate() { this.state = State.TERMINATE_SIGNAL_RECEIVED; } BorgCommand setArgs(String... args) { this.args = args; @@ -38,4 +96,12 @@ } return repoConfig.getRepo() + "::" + archive; } /** * * @return Abbreviated response e. g. for logging an error. */ public String getAbbreviatedResponse() { return StringUtils.abbreviate(response, 1000); } } borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
@@ -9,14 +9,12 @@ import de.micromata.borgbutler.utils.DateUtils; import de.micromata.borgbutler.utils.ReplaceUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; @@ -33,12 +31,12 @@ * @return Parsed repo config returned by Borg command (without archives). */ public static Repository info(BorgRepoConfig repoConfig) { BorgCommand context = new BorgCommand().setRepoConfig(repoConfig).setCommand("info").setParams("--json"); String json = execute(context); if (json == null) { BorgCommand command = new BorgCommand().setRepoConfig(repoConfig).setCommand("info").setParams("--json"); execute(command); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { return null; } BorgRepoInfo repoInfo = JsonUtils.fromJson(BorgRepoInfo.class, json); BorgRepoInfo repoInfo = JsonUtils.fromJson(BorgRepoInfo.class, command.getResponse()); BorgRepository borgRepository = repoInfo.getRepository(); Repository repository = new Repository() .setId(borgRepository.getId()) @@ -62,12 +60,12 @@ */ public static void list(BorgRepoConfig repoConfig, Repository repository) { BorgCommand command = new BorgCommand().setRepoConfig(repoConfig).setCommand("list").setParams("--json"); String json = execute(command); if (json == null) { execute(command); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { log.error("Can't load archives from repo '" + repository.getName() + "'."); return; } BorgRepoList repoList = JsonUtils.fromJson(BorgRepoList.class, json); BorgRepoList repoList = JsonUtils.fromJson(BorgRepoList.class, command.getResponse()); if (repoList == null || CollectionUtils.isEmpty(repoList.getArchives())) { log.error("Can't load archives from repo '" + repository.getName() + "'."); return; @@ -99,11 +97,11 @@ public static void info(BorgRepoConfig repoConfig, Archive archive, Repository repository) { BorgCommand command = new BorgCommand().setRepoConfig(repoConfig).setCommand("info").setArchive(archive.getName()) .setParams("--json"); String json = execute(command); if (json == null) { execute(command); if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { return; } BorgArchiveInfo archiveInfo = JsonUtils.fromJson(BorgArchiveInfo.class, json); BorgArchiveInfo archiveInfo = JsonUtils.fromJson(BorgArchiveInfo.class, command.getResponse()); if (archiveInfo == null) { log.error("Archive '" + command.getRepoArchive() + "' not found."); return; @@ -113,7 +111,7 @@ archive.setCache(archiveInfo.getCache()) .setEncryption(archiveInfo.getEncryption()); if (CollectionUtils.isEmpty(archiveInfo.getArchives())) { log.error("The returned borg archive contains no archive infos: " + json); log.error("The returned borg archive contains no archive infos: " + command.getAbbreviatedResponse()); return; } if (archiveInfo.getArchives().size() > 1) { @@ -136,11 +134,12 @@ public static List<BorgFilesystemItem> listArchiveContent(BorgRepoConfig repoConfig, String archive) { BorgCommand command = new BorgCommand().setRepoConfig(repoConfig).setCommand("list").setArchive(archive) .setParams("--json-lines"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); execute(outputStream, command); String response = outputStream.toString(Definitions.STD_CHARSET); execute(command); List<BorgFilesystemItem> content = new ArrayList<>(); try (Scanner scanner = new Scanner(response)) { if (command.getResultStatus() != BorgCommand.ResultStatus.OK) { return content; } try (Scanner scanner = new Scanner(command.getResponse())) { while (scanner.hasNextLine()) { String json = scanner.nextLine(); BorgFilesystemItem item = JsonUtils.fromJson(BorgFilesystemItem.class, json); @@ -173,15 +172,9 @@ return restoreDir; } private static String execute(BorgCommand command) { private static void execute(BorgCommand command) { Validate.notNull(command); Validate.notNull(command.repoConfig); return BorgExecutorQueue.getQueue(command.repoConfig).execute(command); } private static void execute(OutputStream outputStream, BorgCommand command) { Validate.notNull(command); Validate.notNull(command.repoConfig); BorgExecutorQueue.getQueue(command.repoConfig).execute(outputStream, command); Validate.notNull(command.getRepoConfig()); BorgExecutorQueue.getQueue(command.getRepoConfig()).execute(command); } } borgbutler-core/src/main/java/de/micromata/borgbutler/BorgExecutorQueue.java
@@ -14,7 +14,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; @@ -41,44 +40,41 @@ private ConcurrentLinkedQueue<BorgCommand> commandQueue = new ConcurrentLinkedQueue<>(); public String execute(BorgCommand command) { public void execute(BorgCommand command) { synchronized (this) { return _exceute(command); commandQueue.add(command); _execute(command); } /* while (true) { try { Thread.sleep(1000); } catch (InterruptedException ex) { log.warn("Command '" + command.); } }*/ } private String _exceute(BorgCommand command) { private void _execute(BorgCommand command) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); execute(outputStream, command); String json = outputStream.toString(Definitions.STD_CHARSET); return json; } public void execute(OutputStream outputStream, BorgCommand command) { synchronized (this) { _execute(outputStream, command); } } private void _execute(OutputStream outputStream, BorgCommand command) { CommandLine cmdLine = new CommandLine(ConfigurationHandler.getConfiguration().getBorgCommand()); cmdLine.addArgument(command.command); if (command.params != null) { for (String param : command.params) { cmdLine.addArgument(command.getCommand()); if (command.getParams() != null) { for (String param : command.getParams()) { if (param != null) cmdLine.addArgument(param); } } cmdLine.addArgument(command.getRepoArchive()); if (command.args != null) { for (String arg : command.args) { if (command.getArgs() != null) { for (String arg : command.getArgs()) { if (arg != null) cmdLine.addArgument(arg); } } DefaultExecutor executor = new DefaultExecutor(); if (command.workingDir != null) { executor.setWorkingDirectory(command.workingDir); if (command.getWorkingDir() != null) { executor.setWorkingDirectory(command.getWorkingDir()); } //executor.setExitValue(2); //ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); @@ -89,12 +85,16 @@ String borgCall = cmdLine.getExecutable() + " " + StringUtils.join(cmdLine.getArguments(), " "); log.info("Executing '" + borgCall + "'..."); try { executor.execute(cmdLine, getEnvironment(command.repoConfig)); executor.execute(cmdLine, getEnvironment(command.getRepoConfig())); } catch (Exception ex) { log.error("Error while creating environment for borg call '" + borgCall + "': " + ex.getMessage(), ex); log.error("Response: " + StringUtils.abbreviate(outputStream.toString(), 10000)); return; command.setResultStatus(BorgCommand.ResultStatus.ERROR); } command.setResponse(outputStream.toString(Definitions.STD_CHARSET)); if (command.getResultStatus() == BorgCommand.ResultStatus.ERROR) { log.error("Response: " + command.getAbbreviatedResponse()); } }