From 8290a1feaf4bec966be00919cbe5963d4b6e3867 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <k.reinhard@micromata.de>
Date: Mon, 14 Jan 2019 16:23:37 +0000
Subject: [PATCH] Merge pull request #18 from kreinhard/master
---
borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-12_01-00.json.gz | 0
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java | 6
README.adoc | 4
borgbutler-core/README.adoc | 16 +
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java | 12
borgbutler-core/src/main/java/de/micromata/borgbutler/data/DiffFileSystemFilter.java | 19
borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java | 2
borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java | 9
borgbutler-webapp/src/components/views/archives/FileListEntry.jsx | 56 +++
borgbutler-webapp/src/components/views/archives/FileListPanel.jsx | 6
borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java | 149 +++++++++++
borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java | 4
borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/BorgFilesystemItem.java | 3
borgbutler-core/src/main/java/de/micromata/borgbutler/data/FileSystemFilter.java | 169 +++++++-----
borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-13_01-00.json.gz | 0
borgbutler-core/src/main/resources/demodata/repo-list.json.gz | 0
borgbutler-webapp/src/components/views/archives/FileListTable.jsx | 5
borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java | 23 +
borgbutler-core/src/test/java/de/micromata/borgbutler/DiffFileSystemFilterTest.java | 28 +-
borgbutler-webapp/src/components/views/config/ConfigurationServerTab.jsx | 10
borgbutler-webapp/src/components/views/archives/ArchiveView.jsx | 2
borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-13_01-00.json.gz | 0
borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx | 94 ++++---
borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java | 31 +-
borgbutler-webapp/src/components/general/IconComponents.jsx | 14
borgbutler-core/demo/createFiles.sh | 70 +++++
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java | 2
borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java | 4
borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-12_01-00.json.gz | 0
borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java | 3
borgbutler-core/src/main/resources/demodata/repo-info.json.gz | 0
31 files changed, 546 insertions(+), 195 deletions(-)
diff --git a/README.adoc b/README.adoc
index fe4ffb5..0d20c2a 100644
--- a/README.adoc
+++ b/README.adoc
@@ -77,6 +77,10 @@
3. `npm start` (opens the web browser on port 3000)
4. Start `de.micromata.borgbutler.server.Main` (ignore the opened browser window for port 9042)
+=== Profiling heap, cpu and everything using JProfiler
+JProfiler is an excellent tool for analysing your software. BorgButler was optimized regarding heap memory and CPU usage by
+using https://www.ej-technologies.com/products/jprofiler/overview.html[JProfiler from EJ Technologies^]
+
== Ideas
=== 2 factor authentication
https://github.com/j256/two-factor-auth
diff --git a/borgbutler-core/README.adoc b/borgbutler-core/README.adoc
new file mode 100644
index 0000000..8589582
--- /dev/null
+++ b/borgbutler-core/README.adoc
@@ -0,0 +1,16 @@
+Micromata BorgBackup-Butler
+===========================
+Micromata GmbH, Kai Reinhard
+:toc:
+:toclevels: 4
+
+Copyright (C) 2019
+
+ifdef::env-github,env-browser[:outfilesuffix: .adoc]
+
+== Development
+=== Creating test data
+1. Install virtual debian system
+2. `apt install net-tools curl`
+3. Execute script `./createFiles.sh` on debian host (borg is installed automatically)
+4. See the result files in `out.tar`.
\ No newline at end of file
diff --git a/borgbutler-core/demo/createFiles.sh b/borgbutler-core/demo/createFiles.sh
new file mode 100755
index 0000000..56232ee
--- /dev/null
+++ b/borgbutler-core/demo/createFiles.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+export BORG_PASSPHRASE='borgbutler123'
+export BORG_COMMAND='/root/bin/borg-linux64'
+export TEST_DIR='/root/borgbutler-demo'
+
+if [ -f $BORG_COMMAND ]; then
+ echo Borg command already exists...
+else
+ echo Downloading borg;
+ mkdir /root/bin
+ cd /root/bin
+ curl -LJO https://github.com/borgbackup/borg/releases/download/1.1.8/borg-linux64
+ chmod 700 $BORG_COMMAND
+fi;
+
+echo Creating backup dir /backup-test...
+rm -rf /backup-test
+mkdir /backup-test
+
+echo Initializing borg backup...
+$BORG_COMMAND init --encryption=repokey /backup-test
+
+function backup() {
+echo Creating backup...
+$BORG_COMMAND create --filter AME \
+ --stats \
+ --progress \
+ --show-rc \
+ --compression lz4 \
+ --exclude-caches \
+ /backup-test::borgbutlerdemo-$1 \
+ /home /root /etc /usr/bin /usr/sbin /opt
+}
+
+rm -rf $TEST_DIR
+mkdir $TEST_DIR
+cd $TEST_DIR
+touch README.txt
+chmod 700 README.txt
+echo `ls /usr` > filelist
+touch oldfile
+
+backup 2019-01-12_01-00
+
+rm oldfile
+mkdir newDir
+touch newDir/newfile
+chown borgbutler.users README.txt
+chmod 755 README.txt
+echo `ls /` >> filelist
+
+backup 2019-01-13_01-00
+
+cd /root
+rm -rf out
+mkdir out
+cd out
+$BORG_COMMAND info --json /backup-test >repo-info.json
+$BORG_COMMAND list --json /backup-test >repo-list.json
+
+$BORG_COMMAND info --json /backup-test::borgbutlerdemo-2019-01-12_01-00 >archive-info-borgbuterldemo-2019-01-12_01-00.json
+$BORG_COMMAND info --json /backup-test::borgbutlerdemo-2019-01-13_01-00 >archive-info-borgbuterldemo-2019-01-13_01-00.json
+
+$BORG_COMMAND list --json-lines /backup-test::borgbutlerdemo-2019-01-12_01-00 >archive-list-borgbuterldemo-2019-01-12_01-00.json
+$BORG_COMMAND list --json-lines /backup-test::borgbutlerdemo-2019-01-13_01-00 >archive-list-borgbuterldemo-2019-01-13_01-00.json
+
+gzip -9 *
+cd /root
+tar cvf out.tar out
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java
index 7198ef7..4ddc54d 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommand.java
@@ -55,7 +55,7 @@
return this;
}
- String getRepoArchive() {
+ public String getRepoArchive() {
if (archive == null) {
if (repoConfig == null) {
return null;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
index a5c6355..f9ed76e 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
@@ -3,6 +3,7 @@
import de.micromata.borgbutler.config.BorgRepoConfig;
import de.micromata.borgbutler.data.Archive;
import de.micromata.borgbutler.data.Repository;
+import de.micromata.borgbutler.demo.DemoRepos;
import de.micromata.borgbutler.jobs.JobResult;
import de.micromata.borgbutler.json.JsonUtils;
import de.micromata.borgbutler.json.borg.*;
@@ -72,6 +73,7 @@
.setEncryption(repoInfo.getEncryption())
.setSecurityDir(repoInfo.getSecurityDir())
.setLastCacheRefresh(DateUtils.format(LocalDateTime.now()));
+ DemoRepos.repoWasRead(repoConfig, repository);
return repository;
}
@@ -178,7 +180,7 @@
.setTotal(archive.getStats().getNfiles());
BorgJob<List<BorgFilesystemItem>> job = BorgQueueExecutor.getInstance().execute(new BorgJob<List<BorgFilesystemItem>>(command) {
@Override
- protected void processStdOutLine(String line, int level) {
+ public void processStdOutLine(String line, int level) {
BorgFilesystemItem item = JsonUtils.fromJson(BorgFilesystemItem.class, line);
item.setMtime(DateUtils.format(item.getMtime()));
payload.add(item);
@@ -190,7 +192,7 @@
});
job.payload = new ArrayList<>();
JobResult<String> jobResult = job.getResult();
- if (jobResult == null ||jobResult.getStatus() != JobResult.Status.OK) {
+ if (jobResult == null || jobResult.getStatus() != JobResult.Status.OK) {
return null;
}
List<BorgFilesystemItem> items = job.payload;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
index 38d496a..707cc8a 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
@@ -3,7 +3,9 @@
import de.micromata.borgbutler.config.BorgRepoConfig;
import de.micromata.borgbutler.config.ConfigurationHandler;
import de.micromata.borgbutler.data.Archive;
+import de.micromata.borgbutler.demo.DemoRepos;
import de.micromata.borgbutler.jobs.AbstractCommandLineJob;
+import de.micromata.borgbutler.jobs.JobResult;
import de.micromata.borgbutler.json.JsonUtils;
import de.micromata.borgbutler.json.borg.ProgressInfo;
import lombok.AccessLevel;
@@ -70,7 +72,7 @@
return commandLine;
}
- protected void processStdErrLine(String line, int level) {
+ public void processStdErrLine(String line, int level) {
try {
if (StringUtils.startsWith(line, "{\"message")) {
ProgressInfo message = JsonUtils.fromJson(ProgressInfo.class, line);
@@ -103,6 +105,14 @@
}
@Override
+ public JobResult<String> execute() {
+ if (DemoRepos.isDemo(command.getRepoConfig().getRepo())) {
+ return DemoRepos.execute(this);
+ }
+ return super.execute();
+ }
+
+ @Override
public BorgJob<?> clone() {
BorgJob<?> clone = new BorgJob<>();
if (command != null) {
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
index 716e360..2c45d9c 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java
@@ -278,12 +278,9 @@
if (CollectionUtils.isNotEmpty(list)) {
archiveFilelistCache.save(repoConfig, archive, list);
items = new ArrayList<>();
- int fileNumber = -1;
Iterator<BorgFilesystemItem> it = list.iterator(); // Don't use for-each (ConcurrentModificationException)
while (it.hasNext()) {
BorgFilesystemItem item = it.next();
- ++fileNumber;
- item.setFileNumber(fileNumber);
if (filter == null || filter.matches(item)) {
items.add(item);
if (filter != null && filter.isFinished()) break;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
index 28af84c..d06e30b 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+import de.micromata.borgbutler.demo.DemoRepos;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@@ -32,6 +33,10 @@
@Getter
private int maxArchiveContentCacheCapacityMb = 100;
+ @Getter
+ @Setter
+ private boolean showDemoRepos = true;
+
/**
* Default is restore inside BorgButler's home dir (~/.borgbutler/restore).
*/
@@ -41,7 +46,6 @@
@JsonIgnore
private File restoreHomeDir;
- @Getter
private List<BorgRepoConfig> repoConfigs = new ArrayList<>();
public void add(BorgRepoConfig repoConfig) {
@@ -52,7 +56,7 @@
if (idOrName == null) {
return null;
}
- for (BorgRepoConfig repoConfig : repoConfigs) {
+ for (BorgRepoConfig repoConfig : getRepoConfigs()) {
if (StringUtils.equals(idOrName, repoConfig.getRepo()) || StringUtils.equals(idOrName, repoConfig.getId())) {
return repoConfig;
}
@@ -77,5 +81,20 @@
public void copyFrom(Configuration other) {
this.borgCommand = other.borgCommand;
this.maxArchiveContentCacheCapacityMb = other.maxArchiveContentCacheCapacityMb;
+ this.showDemoRepos = other.showDemoRepos;
+ }
+
+ public List<BorgRepoConfig> getRepoConfigs() {
+ if (!ConfigurationHandler.getConfiguration().isShowDemoRepos()) {
+ return repoConfigs;
+ }
+ List<BorgRepoConfig> result = new ArrayList<>();
+ result.addAll(repoConfigs);
+ DemoRepos.addDemoRepos(result);
+ return result;
+ }
+
+ List<BorgRepoConfig> _getRepoConfigs() {
+ return repoConfigs;
}
}
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
index 41bb53c..baad873 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
@@ -48,8 +48,8 @@
}
}
this.configuration = JsonUtils.fromJson(configClazz, json);
- if (this.configuration.getRepoConfigs() != null) {
- for (BorgRepoConfig repoConfig : this.configuration.getRepoConfigs()) {
+ if (this.configuration._getRepoConfigs() != null) {
+ for (BorgRepoConfig repoConfig : this.configuration._getRepoConfigs()) {
if (StringUtils.isBlank(repoConfig.getDisplayName())) {
repoConfig.setDisplayName(repoConfig.getRepo());
}
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/DiffTool.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/data/DiffFileSystemFilter.java
similarity index 75%
rename from borgbutler-core/src/main/java/de/micromata/borgbutler/DiffTool.java
rename to borgbutler-core/src/main/java/de/micromata/borgbutler/data/DiffFileSystemFilter.java
index a0a16a1..a9b6423 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/DiffTool.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/data/DiffFileSystemFilter.java
@@ -1,4 +1,4 @@
-package de.micromata.borgbutler;
+package de.micromata.borgbutler.data;
import de.micromata.borgbutler.json.borg.BorgFilesystemItem;
import org.slf4j.Logger;
@@ -11,15 +11,15 @@
/**
* Extracts the differences between two archives of one repo.
*/
-public class DiffTool {
- private static Logger log = LoggerFactory.getLogger(DiffTool.class);
+public class DiffFileSystemFilter extends FileSystemFilter {
+ private Logger log = LoggerFactory.getLogger(DiffFileSystemFilter.class);
/**
* @param items Sorted list of items from the current archive.
* @param otherItems Sorted list of items of the archive to extract differences.
* @return A list of differing items (new, removed and modified ones).
*/
- public static List<BorgFilesystemItem> extractDifferences(List<BorgFilesystemItem> items, List<BorgFilesystemItem> otherItems) {
+ public List<BorgFilesystemItem> extractDifferences(List<BorgFilesystemItem> items, List<BorgFilesystemItem> otherItems) {
List<BorgFilesystemItem> currentList = items != null ? items : new ArrayList<>();
List<BorgFilesystemItem> otherList = otherItems != null ? otherItems : new ArrayList<>();
List<BorgFilesystemItem> result = new ArrayList<>();
@@ -37,7 +37,8 @@
}
int cmp = current.compareTo(other);
if (cmp == 0) { // Items represents both the same file system item.
- if (current.equals(other)) {
+ if (!checkDirectoryMatchAndRegisterSubDirectories(current) ||
+ current.equals(other)) {
current = other = null; // increment both iterators.
continue;
}
@@ -48,10 +49,14 @@
result.add(current);
current = other = null; // increment both iterators.
} else if (cmp < 0) {
- result.add(current.setDiffStatus(BorgFilesystemItem.DiffStatus.NEW));
+ if (checkDirectoryMatchAndRegisterSubDirectories(current)) {
+ result.add(current.setDiffStatus(BorgFilesystemItem.DiffStatus.NEW));
+ }
current = currentIt.hasNext() ? currentIt.next() : null;
} else {
- result.add(other.setDiffStatus(BorgFilesystemItem.DiffStatus.REMOVED));
+ if (checkDirectoryMatchAndRegisterSubDirectories(other)) {
+ result.add(other.setDiffStatus(BorgFilesystemItem.DiffStatus.REMOVED));
+ }
other = otherIt.hasNext() ? otherIt.next() : null;
}
}
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/data/FileSystemFilter.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/data/FileSystemFilter.java
index cd971c3..6f8e431 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/data/FileSystemFilter.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/data/FileSystemFilter.java
@@ -3,8 +3,6 @@
import de.micromata.borgbutler.json.borg.BorgFilesystemItem;
import lombok.Getter;
import lombok.Setter;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,16 +55,8 @@
}
return false;
}
- if (mode == Mode.TREE) {
- // In this run only register all direct childs of currentDirectory.
- String topLevelDir = getTopLevel(item.getPath());
- if (topLevelDir == null) {
- // item is not inside the current directory.
- return false;
- }
- if (!subDirectories.containsKey(topLevelDir)) {
- subDirectories.put(topLevelDir, item);
- }
+ if (!checkDirectoryMatchAndRegisterSubDirectories(item)) {
+ return false;
}
if (searchKeyWords == null && blackListSearchKeyWords == null) {
processFinishedFlag();
@@ -103,79 +93,47 @@
* @return The original list for mode {@link Mode#FLAT} or the reduced list for the tree view.
*/
public List<BorgFilesystemItem> reduce(List<BorgFilesystemItem> list) {
- if (mode == FileSystemFilter.Mode.TREE) {
- if (MapUtils.isEmpty(subDirectories)) {
- // If matches was not called before, do this now for getting all subdirectories.
- subDirectories = new HashMap<>();
- for (BorgFilesystemItem item : list) {
- // Needed for building subdirectories...
- this.matches(item);
- }
+ if (mode != FileSystemFilter.Mode.TREE) {
+ return list;
+ }
+ Set<String> set = new HashSet<>();
+ List<BorgFilesystemItem> list2 = list;
+ list = new ArrayList<>();
+ for (BorgFilesystemItem item : list2) {
+ String topLevel = getTopLevel(item.getPath());
+ if (topLevel == null) {
+ continue;
}
- Set<String> set = new HashSet<>();
- List<BorgFilesystemItem> list2 = list;
- list = new ArrayList<>();
- for (BorgFilesystemItem item : list2) {
- String topLevel = getTopLevel(item.getPath());
- if (topLevel == null) {
- continue;
- }
- if (set.contains(topLevel) == false) {
- set.add(topLevel);
- BorgFilesystemItem topItem = subDirectories.get(topLevel);
+ if (set.contains(topLevel) == false) {
+ set.add(topLevel);
+ BorgFilesystemItem topItem = subDirectories.get(topLevel);
+ if (topItem == null) {
+ log.error("Internal error, can't find subDirectory: " + topLevel);
+ } else {
topItem.setDisplayPath(StringUtils.removeStart(topItem.getPath(), currentDirectory));
list.add(topItem);
}
}
- list2 = list;
- // Re-ordering (show dot files at last)
- list = new ArrayList<>();
- // First add normal files:
- for (BorgFilesystemItem item : list2) {
- if (!item.getDisplayPath().startsWith(".")) {
- list.add(item);
- }
+ }
+ list2 = list;
+ // Re-ordering (show dot files at last)
+ list = new ArrayList<>();
+ // First add normal files:
+ for (BorgFilesystemItem item : list2) {
+ if (!item.getDisplayPath().startsWith(".")) {
+ list.add(item);
}
- // Now add dot files:
- for (BorgFilesystemItem item : list2) {
- if (item.getDisplayPath().startsWith(".")) {
- list.add(item);
- }
+ }
+ // Now add dot files:
+ for (BorgFilesystemItem item : list2) {
+ if (item.getDisplayPath().startsWith(".")) {
+ list.add(item);
}
}
return list;
}
/**
- * @param path The path of the current item.
- * @return null if the item is not a child of the current directory otherwise the top level sub directory name of
- * the current directory.
- */
- String getTopLevel(String path) {
- if (StringUtils.isEmpty(currentDirectory)) {
- int pos = path.indexOf('/');
- if (pos < 0) {
- return path;
- }
- return path.substring(0, pos);
- }
- if (!path.startsWith(currentDirectory)) {
- // item is not a child of currentDirectory.
- return null;
- }
- if (path.length() <= currentDirectory.length() + 1) {
- // Don't show the current directory itself.
- return null;
- }
- path = StringUtils.removeStart(path, currentDirectory);
- int pos = path.indexOf('/');
- if (pos < 0) {
- return path;
- }
- return path.substring(0, pos);
- }
-
- /**
* @param searchString The search string. If this string contains several key words separated by white chars,
* all key words must be found.
* @return this for chaining.
@@ -211,6 +169,71 @@
}
/**
+ * This method has only effect in FLAT view. This method has to be called for every item of the list before
+ * {@link #reduce(List)} may work, because this method registers sub directories of the current directory needed
+ * by {@link #reduce(List)}.
+ *
+ * @param item
+ * @return false, if the given item is not a sub item of the current directory. You may skip further checkings for this
+ * item. If true, this item might be part of the result.
+ */
+ protected boolean checkDirectoryMatchAndRegisterSubDirectories(BorgFilesystemItem item) {
+ if (mode != Mode.TREE) {
+ return true;
+ }
+ if (StringUtils.isNotEmpty(currentDirectory) && !item.getPath().startsWith(currentDirectory)) {
+ // item is not inside the current directory.
+ return false;
+ }
+ // In this run only register all direct childs of currentDirectory.
+ String topLevelDir = getTopLevel(item.getPath());
+ if (topLevelDir == null) {
+ // item is not inside the current directory.
+ return false;
+ }
+ if (!subDirectories.containsKey(topLevelDir)) {
+ subDirectories.put(topLevelDir, item);
+ }
+ return true;
+ }
+
+
+ /**
+ * currentDirectory '': <tt>home</tt> -> <tt>home</tt><br>
+ * currentDirectory '': <tt>home/kai</tt> -> <tt>home</tt><br>
+ * currentDirectory 'home': <tt>home</tt> -> <tt>null</tt><br>
+ * currentDirectory 'home': <tt>home/kai</tt> -> <tt>kai</tt><br>
+ * currentDirectory 'home': <tt>home/kai/test.java</tt> -> <tt>kai</tt><br>
+ *
+ * @param path The path of the current item.
+ * @return null if the item is not a child of the current directory otherwise the top level sub directory name of
+ * the current directory.
+ */
+ String getTopLevel(String path) {
+ if (StringUtils.isEmpty(currentDirectory)) {
+ int pos = path.indexOf('/');
+ if (pos < 0) {
+ return path;
+ }
+ return path.substring(0, pos);
+ }
+ if (!path.startsWith(currentDirectory)) {
+ // item is not a child of currentDirectory.
+ return null;
+ }
+ if (path.length() <= currentDirectory.length() + 1) {
+ // Don't show the current directory itself.
+ return null;
+ }
+ path = StringUtils.removeStart(path, currentDirectory);
+ int pos = path.indexOf('/');
+ if (pos < 0) {
+ return path;
+ }
+ return path.substring(0, pos);
+ }
+
+ /**
* @param mode
* @return this for chaining.
*/
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java
new file mode 100644
index 0000000..cc0bd61
--- /dev/null
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java
@@ -0,0 +1,149 @@
+package de.micromata.borgbutler.demo;
+
+import de.micromata.borgbutler.BorgCommand;
+import de.micromata.borgbutler.BorgJob;
+import de.micromata.borgbutler.config.BorgRepoConfig;
+import de.micromata.borgbutler.config.ConfigurationHandler;
+import de.micromata.borgbutler.config.Definitions;
+import de.micromata.borgbutler.data.Repository;
+import de.micromata.borgbutler.jobs.JobResult;
+import de.micromata.borgbutler.json.JsonUtils;
+import de.micromata.borgbutler.json.borg.ProgressInfo;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+public class DemoRepos {
+ private enum Type {FAST, SLOW, VERY_SLOW}
+
+ private static Logger log = LoggerFactory.getLogger(DemoRepos.class);
+ private static final String DEMO_IDENTIFIER = "borgbutler-demo";
+
+ private static final String[] REPOS = {"fast", "slow", "very-slow"};
+ private static List<BorgRepoConfig> demoRepos;
+
+ /**
+ * If configured by the user, demo repositories are added to the given list. If not configured this method does nothing.
+ *
+ * @param repositoryList
+ */
+ public static void addDemoRepos(List<BorgRepoConfig> repositoryList) {
+ if (!ConfigurationHandler.getConfiguration().isShowDemoRepos()) {
+ return;
+ }
+ init();
+ for (BorgRepoConfig repo : demoRepos) {
+ repositoryList.add(repo);
+ }
+ }
+
+ public static boolean isDemo(String name) {
+ return StringUtils.startsWith(name, DEMO_IDENTIFIER);
+ }
+
+ public static void repoWasRead(BorgRepoConfig repoConfig, Repository repository) {
+ if (!isDemo(repository.getName())) {
+ return;
+ }
+ repository.setId(repository.getId() + "-" + REPOS[getType(repoConfig).ordinal()]);
+ }
+
+ public static JobResult<String> execute(BorgJob job) {
+ BorgCommand command = job.getCommand();
+ if (!StringUtils.equalsAny(command.getCommand(), "list", "info")) {
+ log.info("Commmand '" + command.getCommand() + "' not supported for demo repositories.");
+ return new JobResult<String>().setStatus(JobResult.Status.ERROR);
+ }
+ StringBuilder sb = new StringBuilder();
+ boolean archive = command.getArchive() != null;
+ if (archive) {
+ sb.append("archive-");
+ } else {
+ sb.append("repo-");
+ }
+ sb.append(command.getCommand());
+ if (archive) {
+ sb.append("-").append(command.getArchive());
+ }
+ sb.append(".json.gz");
+ int wait = 0;
+ Type type = getType(command.getRepoConfig());
+ if (type == Type.VERY_SLOW) {
+ wait = 10;
+ } else if (type == Type.SLOW) {
+ wait = 1;
+ }
+ String file = sb.toString();
+ log.info("Loading demo archive from '" + file + "'...");
+ try (InputStream inputStream = new GzipCompressorInputStream(DemoRepos.class.getResourceAsStream("/demodata/" + file))) {
+ if (wait > 0) {
+ ProgressInfo progress = new ProgressInfo()
+ .setMessage("Faked demo progress")
+ .setTotal(10 * wait);
+ for (int i = 0; i < 10 * wait; i++) {
+ if (job.isCancellationRequested()) {
+ break;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ // Do nothing.
+ }
+ job.processStdErrLine(JsonUtils.toJson(progress.setCurrent(i)), 0);
+ }
+ }
+ if (archive && "list".equals(command.getCommand())) {
+ try (Scanner scanner = new Scanner(inputStream)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ job.processStdOutLine(line, 0);
+ }
+ return new JobResult<String>().setStatus(JobResult.Status.OK);
+ }
+ } else {
+ StringWriter writer = new StringWriter();
+ IOUtils.copy(inputStream, writer, Definitions.STD_CHARSET);
+ return new JobResult<String>().setResultObject(writer.toString()).setStatus(JobResult.Status.OK);
+ }
+ } catch (IOException ex) {
+ log.error("Error while reading demo file '" + file + "': " + ex.getMessage() + ".");
+ return null;
+ }
+ }
+
+ private static Type getType(BorgRepoConfig repoConfig) {
+ if (repoConfig.getRepo().endsWith("very-slow")) {
+ return Type.VERY_SLOW;
+ } else if (repoConfig.getRepo().endsWith("slow")) {
+ return Type.SLOW;
+ }
+ return Type.FAST;
+ }
+
+ private static void init() {
+ synchronized (DEMO_IDENTIFIER) {
+ if (demoRepos != null) {
+ return;
+ }
+ demoRepos = new ArrayList<>();
+ demoRepos.add(new BorgRepoConfig()
+ .setRepo(DEMO_IDENTIFIER + "-fast")
+ .setDisplayName("Demo repository fast"));
+ demoRepos.add(new BorgRepoConfig()
+ .setRepo(DEMO_IDENTIFIER + "-slow")
+ .setDisplayName("Demo repository slow"));
+ demoRepos.add(new BorgRepoConfig()
+ .setRepo(DEMO_IDENTIFIER + "-very-slow")
+ .setDisplayName("Demo repository very-slow"));
+ }
+ }
+}
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java
index bccf7ea..4daf718 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/AbstractCommandLineJob.java
@@ -101,7 +101,7 @@
return result;
}
- protected void processStdOutLine(String line, int level) {
+ public void processStdOutLine(String line, int level) {
//log.info(line);
try {
outputStream.write(line.getBytes());
@@ -111,7 +111,7 @@
}
}
- protected void processStdErrLine(String line, int level) {
+ public void processStdErrLine(String line, int level) {
//log.info(line);
try {
errorOutputStream.write(line.getBytes());
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java
index f57bd9b..809e52f 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobResult.java
@@ -7,7 +7,7 @@
public class JobResult<T> {
public enum Status {OK, ERROR}
@Getter
- @Setter(AccessLevel.PACKAGE)
+ @Setter
private Status status;
@Getter
@Setter
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/BorgFilesystemItem.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/BorgFilesystemItem.java
index 61f6381..8d03c47 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/BorgFilesystemItem.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/BorgFilesystemItem.java
@@ -66,7 +66,8 @@
*/
@Getter
@Setter
- private int fileNumber;
+ private int fileNumber = -1;
+
/**
* If created by diff tool, this flag represents the type of difference.
*/
diff --git a/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-12_01-00.json.gz b/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-12_01-00.json.gz
new file mode 100644
index 0000000..769e79d
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-12_01-00.json.gz
Binary files differ
diff --git a/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-13_01-00.json.gz b/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-13_01-00.json.gz
new file mode 100644
index 0000000..69dd0f5
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/archive-info-borgbutlerdemo-2019-01-13_01-00.json.gz
Binary files differ
diff --git a/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-12_01-00.json.gz b/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-12_01-00.json.gz
new file mode 100644
index 0000000..00cad35
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-12_01-00.json.gz
Binary files differ
diff --git a/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-13_01-00.json.gz b/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-13_01-00.json.gz
new file mode 100644
index 0000000..c9321b9
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/archive-list-borgbutlerdemo-2019-01-13_01-00.json.gz
Binary files differ
diff --git a/borgbutler-core/src/main/resources/demodata/repo-info.json.gz b/borgbutler-core/src/main/resources/demodata/repo-info.json.gz
new file mode 100644
index 0000000..c8bba90
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/repo-info.json.gz
Binary files differ
diff --git a/borgbutler-core/src/main/resources/demodata/repo-list.json.gz b/borgbutler-core/src/main/resources/demodata/repo-list.json.gz
new file mode 100644
index 0000000..c60b152
--- /dev/null
+++ b/borgbutler-core/src/main/resources/demodata/repo-list.json.gz
Binary files differ
diff --git a/borgbutler-core/src/test/java/de/micromata/borgbutler/DiffToolTest.java b/borgbutler-core/src/test/java/de/micromata/borgbutler/DiffFileSystemFilterTest.java
similarity index 88%
rename from borgbutler-core/src/test/java/de/micromata/borgbutler/DiffToolTest.java
rename to borgbutler-core/src/test/java/de/micromata/borgbutler/DiffFileSystemFilterTest.java
index 5fd2940..23ff366 100644
--- a/borgbutler-core/src/test/java/de/micromata/borgbutler/DiffToolTest.java
+++ b/borgbutler-core/src/test/java/de/micromata/borgbutler/DiffFileSystemFilterTest.java
@@ -1,5 +1,6 @@
package de.micromata.borgbutler;
+import de.micromata.borgbutler.data.DiffFileSystemFilter;
import de.micromata.borgbutler.json.borg.BorgFilesystemItem;
import org.junit.jupiter.api.Test;
@@ -9,7 +10,7 @@
import static org.junit.jupiter.api.Assertions.*;
-public class DiffToolTest {
+public class DiffFileSystemFilterTest {
@Test
void differencesTest() {
BorgFilesystemItem i1 = create("etc", true, "drwx------", 0, "2018-11-21");
@@ -28,33 +29,34 @@
List<BorgFilesystemItem> l1 = null;
List<BorgFilesystemItem> l2 = null;
List<BorgFilesystemItem> result;
- assertEquals(0, DiffTool.extractDifferences(l1, l2).size());
+ DiffFileSystemFilter filter = new DiffFileSystemFilter();
+ assertEquals(0, filter.extractDifferences(l1, l2).size());
l1 = create();
- result = DiffTool.extractDifferences(l1, l2);
+ result = filter.extractDifferences(l1, l2);
assertEquals(7, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(1).getDiffStatus());
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(7, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(1).getDiffStatus());
l1 = create();
l2 = create();
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(0, result.size());
remove(l2, "etc"); // 0
remove(l2, "etc/passwd"); // 1
remove(l1, "home/kai/.borgbutler/borgbutler-config-bak.json"); // 2
get(l1, "home/kai/.borgbutler/borgbutler-config.json").setSize(712).setMtime("2018-11-22"); // 3
- result = DiffTool.extractDifferences(l1, l2);
+ result = filter.extractDifferences(l1, l2);
assertEquals(4, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(1).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(2).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.MODIFIED, result.get(3).getDiffStatus());
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(4, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(1).getDiffStatus());
@@ -66,12 +68,12 @@
remove(l2, "etc"); // 0
remove(l2, "etc/passwd"); // 1
remove(l1, "home/kai/.borgbutler/borgbutler-config.json"); // 2
- result = DiffTool.extractDifferences(l1, l2);
+ result = filter.extractDifferences(l1, l2);
assertEquals(3, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(1).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(2).getDiffStatus());
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(3, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(1).getDiffStatus());
@@ -82,11 +84,11 @@
l2 = create();
remove(l1, "home/kai/.borgbutler/borgbutler-config-bak.json");
remove(l2, "home/kai/.borgbutler/borgbutler-config.json");
- result = DiffTool.extractDifferences(l1, l2);
+ result = filter.extractDifferences(l1, l2);
assertEquals(2, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(1).getDiffStatus());
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(2, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(1).getDiffStatus());
@@ -96,12 +98,12 @@
remove(l1, "home/kai");
remove(l1, "home/kai/.borgbutler");
remove(l2, "home/kai/.borgbutler/borgbutler-config-bak.json");
- result = DiffTool.extractDifferences(l1, l2);
+ result = filter.extractDifferences(l1, l2);
assertEquals(3, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.REMOVED, result.get(1).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(2).getDiffStatus());
- result = DiffTool.extractDifferences(l2, l1);
+ result = filter.extractDifferences(l2, l1);
assertEquals(3, result.size());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(0).getDiffStatus());
assertEquals(BorgFilesystemItem.DiffStatus.NEW, result.get(1).getDiffStatus());
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java
index d3f0ad8..ce67240 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java
@@ -1,12 +1,9 @@
package de.micromata.borgbutler.server;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.micromata.borgbutler.cache.ButlerCache;
import de.micromata.borgbutler.config.Configuration;
import de.micromata.borgbutler.config.ConfigurationHandler;
-import lombok.Getter;
-import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,16 +12,11 @@
private static Logger log = LoggerFactory.getLogger(ServerConfiguration.class);
private final static String[] SUPPORTED_LANGUAGES = {"en", "de"};
public static final int WEBSERVER_PORT_DEFAULT = 9042;
- private static final boolean SHOW_TEST_DATA_PREF_DEFAULT = false;
private static final boolean WEB_DEVELOPMENT_MODE_PREF_DEFAULT = false;
private static String applicationHome;
private int port = WEBSERVER_PORT_DEFAULT;
- @Getter
- @Setter
- @JsonIgnore
- private boolean showTestData = SHOW_TEST_DATA_PREF_DEFAULT;
private boolean webDevelopmentMode = WEB_DEVELOPMENT_MODE_PREF_DEFAULT;
@JsonProperty
public String getCacheDir() {
@@ -72,7 +64,6 @@
public void copyFrom(ServerConfiguration other) {
super.copyFrom(other);
this.port = other.port;
- this.showTestData = other.showTestData;
this.webDevelopmentMode = other.webDevelopmentMode;
}
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
index b24774b..582715e 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
@@ -1,11 +1,11 @@
package de.micromata.borgbutler.server.rest;
import de.micromata.borgbutler.BorgCommands;
-import de.micromata.borgbutler.DiffTool;
import de.micromata.borgbutler.cache.ButlerCache;
import de.micromata.borgbutler.config.BorgRepoConfig;
import de.micromata.borgbutler.config.ConfigurationHandler;
import de.micromata.borgbutler.data.Archive;
+import de.micromata.borgbutler.data.DiffFileSystemFilter;
import de.micromata.borgbutler.data.FileSystemFilter;
import de.micromata.borgbutler.data.Repository;
import de.micromata.borgbutler.json.JsonUtils;
@@ -77,29 +77,30 @@
@QueryParam("diffArchiveId") String diffArchiveId,
@QueryParam("force") boolean force,
@QueryParam("prettyPrinter") boolean prettyPrinter) {
+ boolean diffMode = StringUtils.isNotBlank(diffArchiveId);
int maxSize = NumberUtils.toInt(maxResultSize, 50);
- FileSystemFilter filter = new FileSystemFilter()
- .setSearchString(searchString)
- .setMaxResultSize(maxSize)
- .setMode(mode)
+ FileSystemFilter filter = diffMode ? new DiffFileSystemFilter() : new FileSystemFilter();
+ filter.setSearchString(searchString)
.setCurrentDirectory(currentDirectory);
List<BorgFilesystemItem> items = null;
- if (StringUtils.isBlank(diffArchiveId)) {
+ if (diffMode) {
+ filter.setMode(FileSystemFilter.Mode.FLAT);
+ items = ButlerCache.getInstance().getArchiveContent(archiveId, true, filter);
+ List<BorgFilesystemItem> diffItems = ButlerCache.getInstance().getArchiveContent(diffArchiveId, true,
+ filter);
+ filter.setMaxResultSize(maxSize)
+ .setMode(mode);
+ items = ((DiffFileSystemFilter) filter).extractDifferences(items, diffItems);
+ items = filter.reduce(items);
+ } else {
+ filter.setMode(mode)
+ .setMaxResultSize(maxSize);
// Get file list (without running diff).
items = ButlerCache.getInstance().getArchiveContent(archiveId, force,
filter);
if (items == null) {
return "[{\"mode\": \"notLoaded\"}]";
}
- } else {
- filter.setMode(FileSystemFilter.Mode.FLAT).setMaxResultSize(-1);
- items = ButlerCache.getInstance().getArchiveContent(archiveId, true, filter);
- List<BorgFilesystemItem> diffItems = ButlerCache.getInstance().getArchiveContent(diffArchiveId, true,
- filter);
- items = DiffTool.extractDifferences(items, diffItems);
- filter.setMaxResultSize(maxSize)
- .setMode(mode);
- items = filter.reduce(items);
}
return JsonUtils.toJson(items, prettyPrinter);
}
diff --git a/borgbutler-webapp/src/components/general/IconComponents.jsx b/borgbutler-webapp/src/components/general/IconComponents.jsx
index 1bb6474..f8707cf 100644
--- a/borgbutler-webapp/src/components/general/IconComponents.jsx
+++ b/borgbutler-webapp/src/components/general/IconComponents.jsx
@@ -1,5 +1,6 @@
import React from 'react';
import {
+ faBan,
faCaretDown,
faCaretUp,
faCheck,
@@ -8,12 +9,12 @@
faExclamationTriangle,
faInfoCircle,
faPlus,
+ faSkullCrossbones,
faSortDown,
faSortUp,
faSync,
- faTrash,
faTimes,
- faSkullCrossbones,
+ faTrash,
faUpload
} from '@fortawesome/free-solid-svg-icons'
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
@@ -24,6 +25,12 @@
);
}
+function IconBan() {
+ return (
+ <FontAwesomeIcon icon={faBan}/>
+ );
+}
+
function IconCancel() {
return (
<FontAwesomeIcon icon={faTimes}/>
@@ -80,7 +87,7 @@
function IconSpinner() {
return (
- <FontAwesomeIcon icon={faCircleNotch} spin={true} size={'3x'} color={'#aaaaaa'} />
+ <FontAwesomeIcon icon={faCircleNotch} spin={true} size={'3x'} color={'#aaaaaa'}/>
);
}
@@ -110,6 +117,7 @@
export {
IconAdd,
+ IconBan,
IconCancel,
IconCheck,
IconCollapseClose,
diff --git a/borgbutler-webapp/src/components/views/archives/ArchiveView.jsx b/borgbutler-webapp/src/components/views/archives/ArchiveView.jsx
index 437a84c..3a32ffc 100644
--- a/borgbutler-webapp/src/components/views/archives/ArchiveView.jsx
+++ b/borgbutler-webapp/src/components/views/archives/ArchiveView.jsx
@@ -99,7 +99,7 @@
<TabPane tabId={'1'}>
<FileListPanel
repoId={this.state.repoId}
- archiveId={archive.id}
+ archive={archive}
archiveShortInfoList={archive.archiveShortInfoList}
/>
</TabPane>
diff --git a/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx b/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
index 5f7f9cd..38dab55 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
@@ -2,19 +2,24 @@
import PropTypes from 'prop-types';
import Highlight from 'react-highlighter';
import {Button, UncontrolledTooltip} from 'reactstrap';
-import {IconCheck, IconDownload} from '../../general/IconComponents';
+import {IconBan, IconCheck, IconDownload} from '../../general/IconComponents';
import {getResponseHeaderFilename, getRestServiceUrl, humanFileSize} from '../../../utilities/global';
import fileDownload from 'js-file-download';
class FileListEntry extends React.Component {
state = {
- downloaded: false
+ thisDownloaded: false,
+ otherDownloaded: false
};
- download(archiveId, fileNumber) {
+ download(archiveId, fileNumber, thisDownload) {
let filename;
- this.setState({downloaded: true});
+ if (thisDownload) {
+ this.setState({thisDownloaded: true});
+ } else {
+ this.setState({otherDownloaded: true});
+ }
fetch(getRestServiceUrl('archives/restore', {
archiveId: archiveId,
fileNumber: fileNumber
@@ -42,7 +47,6 @@
render = () => {
const entry = this.props.entry;
- let downloadArchiveId = this.props.archiveId;
let displayPath = entry.displayPath;
let pathCss = 'tt';
@@ -61,14 +65,46 @@
let mtimeCss = 'tt';
let mtimeTooltip = undefined;
let mtimeId = undefined;
+ let iconBan = <div className={'btn'}><IconBan/></div>;
+ let iconCheck = <div className={'btn'}><IconCheck/></div>;
+
+ let icon1 = iconCheck;
+ let icon1Tooltip = '';
+ if (!this.state.thisDownloaded) {
+ const icon1Id = `icon1-${entry.fileNumber}`;
+ icon1 = <div id={icon1Id} className={'btn'}
+ onClick={() => this.download(this.props.archive.id, entry.fileNumber, true)}>
+ <IconDownload/></div>;
+ icon1Tooltip = <UncontrolledTooltip target={icon1Id}>
+ {this.props.archive.time}
+ </UncontrolledTooltip>;
+ }
+ let icon2 = '';
+ let icon2Tooltip = '';
+ if (this.props.diffArchiveId) {
+ icon2 = iconCheck;
+ if (!this.state.otherDownloaded) {
+ const icon2Id = `icon2-${entry.fileNumber}`;
+ icon2 =
+ <div id={icon2Id} className={'btn'}
+ onClick={() => this.download(this.props.diffArchiveId, entry.fileNumber, false)}>
+ <IconDownload/></div>;
+ icon2Tooltip = <UncontrolledTooltip target={icon2Id}>
+ other
+ </UncontrolledTooltip>;
+ }
+ }
if (entry.diffStatus === 'NEW') {
pathCss = 'tt file-new';
pathtooltipText = 'NEW';
+ icon2 = iconBan;
+ icon2Tooltip = '';
} else if (entry.diffStatus === 'REMOVED') {
pathCss = 'tt file-removed';
// Download removed files from other archive.
- downloadArchiveId = this.props.diffArchiveId;
pathtooltipText = 'REMOVED';
+ icon1 = iconBan;
+ icon1Tooltip = '';
} else if (entry.diffStatus === 'MODIFIED') {
if (entry.differences) {
pathCss = 'tt file-modified';
@@ -100,7 +136,7 @@
}
}
if (pathtooltipText) {
- pathId = `path-${entry.fileNumber}`;
+ pathId = `path-${entry.fileNumber}-${entry.diffStatus}`;
pathTooltip =
<UncontrolledTooltip target={pathId}>
{pathtooltipText}
@@ -113,16 +149,13 @@
} else {
path = <Highlight search={this.props.search} id={pathId}>{displayPath}</Highlight>;
}
- let icon = this.state.downloaded ? <IconCheck/> :
- <div className={'btn'} onClick={() => this.download(downloadArchiveId, entry.fileNumber)}>
- <IconDownload/></div>;
return (
<tr>
<td className={pathCss}>
{path}{pathTooltip}
</td>
<td className={'tt'} style={{textAlign: 'center'}}>
- {icon}
+ {icon1}{icon1Tooltip} {icon2}{icon2Tooltip}
</td>
<td className={sizeCss} style={{textAlign: 'center'}}>
<span id={sizeId}>{humanFileSize(entry.size, true, true)}</span>{sizeTooltip}
@@ -149,6 +182,7 @@
entry: PropTypes.shape({}).isRequired,
search: PropTypes.string,
mode: PropTypes.string,
+ diffArchiveId: PropTypes.string,
changeCurrentDirectory: PropTypes.func.isRequired
};
diff --git a/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx b/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
index af47cc7..3f8b3b7 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
@@ -51,7 +51,7 @@
failed: false
});
fetch(getRestServiceUrl('archives/filelist', {
- archiveId: this.props.archiveId,
+ archiveId: this.props.archive.id,
diffArchiveId: this.state.filter.diffArchiveId,
force: force,
searchString: this.state.filter.search,
@@ -128,12 +128,12 @@
event.preventDefault();
this.fetchArchiveFileList();
}}
- currentArchiveId={this.props.archiveId}
+ currentArchiveId={this.props.archive.id}
archiveShortInfoList={this.props.archiveShortInfoList}
/>
{breadcrumb}
<FileListTable
- archiveId={this.props.archiveId}
+ archive={this.props.archive}
diffArchiveId={this.state.filter.diffArchiveId}
entries={this.state.fileList}
search={this.state.filter.search}
diff --git a/borgbutler-webapp/src/components/views/archives/FileListTable.jsx b/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
index 8b03adc..710ffa6 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
@@ -3,7 +3,7 @@
import {Table} from 'reactstrap';
import FileListEntry from './FileListEntry';
-function FileListTable({archiveId, diffArchiveId, entries, search, mode, changeCurrentDirectory}) {
+function FileListTable({archive, diffArchiveId, entries, search, mode, changeCurrentDirectory}) {
const lowercaseSearch = search.split(' ')[0].toLowerCase();
return (
<Table striped bordered hover size={'sm'} responsive>
@@ -19,7 +19,7 @@
<tbody>
{entries
.map((entry, index) => <FileListEntry
- archiveId={archiveId}
+ archive={archive}
diffArchiveId={diffArchiveId}
entry={entry}
search={lowercaseSearch}
@@ -33,7 +33,6 @@
}
FileListTable.propTypes = {
- archiveId: PropTypes.string,
diffArchiveId: PropTypes.string,
entries: PropTypes.array,
search: PropTypes.string,
diff --git a/borgbutler-webapp/src/components/views/config/ConfigurationServerTab.jsx b/borgbutler-webapp/src/components/views/config/ConfigurationServerTab.jsx
index 827a47c..84f0e2d 100644
--- a/borgbutler-webapp/src/components/views/config/ConfigurationServerTab.jsx
+++ b/borgbutler-webapp/src/components/views/config/ConfigurationServerTab.jsx
@@ -45,6 +45,7 @@
failed: false,
port: 9042,
webdevelopmentMode: false,
+ showDemoRepos: true,
maxArchiveContentCacheCapacityMb: 100,
redirect: false,
confirmModal: false
@@ -73,7 +74,8 @@
var config = {
port: this.state.port,
maxArchiveContentCacheCapacityMb : this.state.maxArchiveContentCacheCapacityMb,
- webDevelopmentMode: this.state.webDevelopmentMode
+ webDevelopmentMode: this.state.webDevelopmentMode,
+ showDemoRepos: this.state.showDemoRepos
};
return fetch(getRestServiceUrl("configuration/config"), {
method: 'POST',
@@ -140,6 +142,12 @@
onChange={this.handleTextChange}
placeholder="Enter maximum Capacity"
hint={`Limits the cache size of archive file lists in the local cache directory: ${this.state.cacheDir}`} />
+ <FormLabelField label={'Show demo repositories'} fieldLength={2}>
+ <FormCheckbox checked={this.state.showDemoRepos}
+ hint={'If true, some demo repositories are shown for testing the functionality of BorgButler without any further configuration and running borg backups.'}
+ name="showDemoRepos"
+ onChange={this.handleCheckboxChange} />
+ </FormLabelField>
<FormLabelField label={<I18n name={'configuration.webDevelopmentMode'} />} fieldLength={2}>
<FormCheckbox checked={this.state.webDevelopmentMode}
hintKey={'configuration.webDevelopmentMode.hint'}
diff --git a/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx b/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
index 81cbe43..32b1b91 100644
--- a/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
+++ b/borgbutler-webapp/src/components/views/repos/RepoArchiveListView.jsx
@@ -77,6 +77,56 @@
<IconRefresh/>
</div>
</React.Fragment>;
+ let stats = '';
+ if (repo.cache && repo.cache.stats) {
+ stats = <tr>
+ <td>Stats</td>
+ <td>
+ <table className="inline">
+ <tbody>
+ <tr>
+ <td>Total chunks</td>
+ <td>{Number(repo.cache.stats.total_chunks).toLocaleString()}</td>
+ </tr>
+ <tr>
+ <td>Total csize</td>
+ <td>{humanFileSize(repo.cache.stats.total_csize)}</td>
+ </tr>
+ <tr>
+ <td>Total size</td>
+ <td>{humanFileSize(repo.cache.stats.total_size)}</td>
+ </tr>
+ <tr>
+ <td>Total unique chunks</td>
+ <td>{Number(repo.cache.stats.total_unique_chunks).toLocaleString()}</td>
+ </tr>
+ <tr>
+ <td>Unique csize</td>
+ <td>{humanFileSize(repo.cache.stats.unique_csize)}</td>
+ </tr>
+ <tr>
+ <td>Unique size</td>
+ <td>{humanFileSize(repo.cache.stats.unique_size)}</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ }
+ let encryption = '';
+ if (repo.encryption) {
+ encryption = <tr>
+ <td>Encryption</td>
+ <td>{repo.encryption.mode}</td>
+ </tr>
+ }
+ let cachePath = '';
+ if (repo.cache) {
+ cachePath = <tr>
+ <td>Cache</td>
+ <td>{repo.cache.path}</td>
+ </tr>
+ }
content = <React.Fragment>
<Nav tabs>
<NavLink
@@ -134,51 +184,13 @@
<td>Location</td>
<td>{repo.location}</td>
</tr>
- <tr>
- <td>Stats</td>
- <td>
- <table className="inline">
- <tbody>
- <tr>
- <td>Total chunks</td>
- <td>{Number(repo.cache.stats.total_chunks).toLocaleString()}</td>
- </tr>
- <tr>
- <td>Total csize</td>
- <td>{humanFileSize(repo.cache.stats.total_csize)}</td>
- </tr>
- <tr>
- <td>Total size</td>
- <td>{humanFileSize(repo.cache.stats.total_size)}</td>
- </tr>
- <tr>
- <td>Total unique chunks</td>
- <td>{Number(repo.cache.stats.total_unique_chunks).toLocaleString()}</td>
- </tr>
- <tr>
- <td>Unique csize</td>
- <td>{humanFileSize(repo.cache.stats.unique_csize)}</td>
- </tr>
- <tr>
- <td>Unique size</td>
- <td>{humanFileSize(repo.cache.stats.unique_size)}</td>
- </tr>
- </tbody>
- </table>
- </td>
- </tr>
+ {stats}
<tr>
<td>Security dir</td>
<td>{repo.securityDir}</td>
</tr>
- <tr>
- <td>Encryption</td>
- <td>{repo.encryption.mode}</td>
- </tr>
- <tr>
- <td>Cache</td>
- <td>{repo.cache.path}</td>
- </tr>
+ {encryption}
+ {cachePath}
</tbody>
</Table>
</TabPane>
--
Gitblit v1.10.0