borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
@@ -128,7 +128,7 @@ .setRepoConfig(repoConfig) .setCommand("info") .setArchive(archive.getName()) .setParams("--json", "--progress") .setParams("--json", "--log-json", "--progress") .setDescription("Loading info of archive '" + archive.getName() + "' of repo '" + repoConfig.getDisplayName() + "'."); JobResult<String> jobResult = execute(command).getResult(); if (jobResult.getStatus() != JobResult.Status.OK) { borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
@@ -47,6 +47,9 @@ @Override protected CommandLine buildCommandLine() { if (command == null) { return null; } CommandLine commandLine = new CommandLine(ConfigurationHandler.getConfiguration().getBorgCommand()); commandLine.addArgument(command.getCommand()); if (command.getParams() != null) { @@ -68,12 +71,10 @@ } protected void processStdErrLine(String line, int level) { log.info(line); try { if (StringUtils.startsWith(line, "{\"message")) { ProgressMessage message = JsonUtils.fromJson(ProgressMessage.class, line); if (message != null) { log.info(JsonUtils.toJson(progressMessage)); progressMessage = message; return; } @@ -114,6 +115,9 @@ clone.setStatus(getStatus()); clone.setWorkingDirectory(getWorkingDirectory()); clone.setDescription(getDescription()); if (progressMessage != null) { clone.setProgressMessage(progressMessage.clone()); } return clone; } } borgbutler-core/src/main/java/de/micromata/borgbutler/BorgQueueExecutor.java
@@ -6,10 +6,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.*; /** * A queue is important because Borg doesn't support parallel calls for one repository. @@ -27,6 +24,16 @@ private Map<String, JobQueue<String>> queueMap = new HashMap<>(); /** * @return A list of all repos with queues. */ public List<String> getRepos() { List<String> list = new ArrayList<>(); list.addAll(queueMap.keySet()); Collections.sort(list); return list; } /** * For displaying purposes. * * @param repo borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressMessage.java
@@ -7,7 +7,7 @@ * Output of borg option <tt>--progress</tt>. * See https://borgbackup.readthedocs.io/en/stable/internals/frontends.html, */ public class ProgressMessage { public class ProgressMessage implements Cloneable { // {"message": "Calculating statistics... 0%", "current": 1, "total": 2497, "info": null, "operation": 1, "msgid": null, "type": "progress_percent", "finished": false, "time": 1546640510.116256} /** * e. g. Calculating statistics... 5% @@ -52,4 +52,15 @@ ++current; return this; } @Override public ProgressMessage clone() { ProgressMessage clone = null; try { clone = (ProgressMessage) super.clone(); } catch (CloneNotSupportedException ex) { throw new UnsupportedOperationException(this.getClass().getCanonicalName() + " isn't cloneable: " + ex.getMessage(), ex); } return clone; } } borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
@@ -2,10 +2,9 @@ import de.micromata.borgbutler.BorgJob; import de.micromata.borgbutler.BorgQueueExecutor; import de.micromata.borgbutler.data.Archive; import de.micromata.borgbutler.data.Repository; import de.micromata.borgbutler.json.JsonUtils; import de.micromata.borgbutler.server.rest.queue.JsonJob; import de.micromata.borgbutler.server.rest.queue.JsonJobQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,24 +24,24 @@ @Produces(MediaType.APPLICATION_JSON) /** * * @param repo Name of repository ({@link Repository#getName()}. * @param prettyPrinter If true then the json output will be in pretty format. * @return Job queue as json string. * @return Job queues as json string. * @see JsonUtils#toJson(Object, boolean) */ public String getJobs(@QueryParam("repo") String repoName, @QueryParam("prettyPrinter") boolean prettyPrinter) { public String getJobs(@QueryParam("prettyPrinter") boolean prettyPrinter) { BorgQueueExecutor borgQueueExecutor = BorgQueueExecutor.getInstance(); List<BorgJob<?>> borgJobList = borgQueueExecutor.getJobListCopy(repoName); List<JsonJob> jobList = new ArrayList<>(borgJobList.size()); for (BorgJob<?> borgJob : borgJobList) { JsonJob job = new JsonJob(); job.setTitle(borgJob.getTitle()); // job.setProgressText(borgJob.get); job.setStatus(borgJob.getStatus()); job.setCancelledRequested(borgJob.isCancelledRequested()); List<JsonJobQueue> queueList = new ArrayList<>(); for (String repo : borgQueueExecutor.getRepos()) { List<BorgJob<?>> borgJobList = borgQueueExecutor.getJobListCopy(repo); JsonJobQueue queue = new JsonJobQueue() .setRepo(repo); queueList.add(queue); queue.setJobs(new ArrayList<>(borgJobList.size())); for (BorgJob<?> borgJob : borgJobList) { JsonJob job = new JsonJob(borgJob); queue.getJobs().add(job); } } Archive archive = null; return JsonUtils.toJson(archive, prettyPrinter); return JsonUtils.toJson(queueList, prettyPrinter); } } borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java
@@ -1,6 +1,9 @@ package de.micromata.borgbutler.server.rest.queue; import de.micromata.borgbutler.BorgJob; import de.micromata.borgbutler.jobs.AbstractJob; import de.micromata.borgbutler.json.borg.ProgressMessage; import de.micromata.borgbutler.server.user.UserUtils; import lombok.Getter; import lombok.Setter; @@ -15,6 +18,52 @@ @Setter private String title; @Getter private String description; @Getter @Setter private String progressText; @Setter @Getter private ProgressMessage progressMessage; @Getter private String commandLineAsString; public JsonJob() { } public JsonJob(BorgJob<?> borgJob) { this.cancelledRequested = borgJob.isCancelledRequested(); this.status = borgJob.getStatus(); this.title = borgJob.getTitle(); ProgressMessage progressMessage = borgJob.getProgressMessage(); if (progressMessage != null) { this.progressMessage = progressMessage; this.progressText = progressMessageToString(); } this.commandLineAsString = borgJob.getCommandLineAsString(); this.description = borgJob.getDescription(); } public String progressMessageToString() { if (progressMessage == null) { return ""; } StringBuilder sb = new StringBuilder(); if (progressMessage.getMessage()!= null) { sb.append(progressMessage.getMessage()); } if (progressMessage.getCurrent() > 0) { sb.append(" (").append(UserUtils.formatNumber(progressMessage.getCurrent())); if (progressMessage.getTotal() > 0) { sb.append("/").append(UserUtils.formatNumber(progressMessage.getTotal())); } sb.append(")"); } if (progressMessage.isFinished()) { sb.append(" (finished)"); } sb.append("."); return sb.toString(); } } borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJobQueue.java
@@ -8,7 +8,7 @@ public class JsonJobQueue { @Getter @Setter private String title; private String repo; @Getter @Setter private List<JsonJob> jobs; borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserUtils.java
@@ -1,5 +1,6 @@ package de.micromata.borgbutler.server.user; import java.text.NumberFormat; import java.util.Locale; public class UserUtils { @@ -25,6 +26,9 @@ if (locale == null) { locale = userInfo.requestLocale; } if (locale == null) { locale = Locale.getDefault(); } return locale; } @@ -50,4 +54,9 @@ this.requestLocale = requestLocale; } } public static String formatNumber(long number) { NumberFormat numberFormat = NumberFormat.getInstance(getUserLocale()); return numberFormat.format(number); } } borgbutler-webapp/src/components/views/develop/RestServices.jsx
@@ -36,6 +36,12 @@ <li><RestUrlLink service='repos/list'/></li> </ul> <h3> Job monitor </h3> <ul> <li><RestUrlLink service='jobs'/></li> </ul> <h3> Config </h3> <ul>