Merge pull request #18 from kreinhard/master
Some work...
9 files added
2 files renamed
20 files modified
| | |
| | | 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 |
| New file |
| | |
| | | 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`. |
| New file |
| | |
| | | #!/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 |
| | |
| | | return this; |
| | | } |
| | | |
| | | String getRepoArchive() { |
| | | public String getRepoArchive() { |
| | | if (archive == null) { |
| | | if (repoConfig == null) { |
| | | return null; |
| | |
| | | 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.*; |
| | |
| | | .setEncryption(repoInfo.getEncryption()) |
| | | .setSecurityDir(repoInfo.getSecurityDir()) |
| | | .setLastCacheRefresh(DateUtils.format(LocalDateTime.now())); |
| | | DemoRepos.repoWasRead(repoConfig, repository); |
| | | return repository; |
| | | } |
| | | |
| | |
| | | .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); |
| | |
| | | }); |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | } |
| | | |
| | | @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) { |
| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | |
| | | @Getter |
| | | private int maxArchiveContentCacheCapacityMb = 100; |
| | | |
| | | @Getter |
| | | @Setter |
| | | private boolean showDemoRepos = true; |
| | | |
| | | /** |
| | | * Default is restore inside BorgButler's home dir (~/.borgbutler/restore). |
| | | */ |
| | |
| | | @JsonIgnore |
| | | private File restoreHomeDir; |
| | | |
| | | @Getter |
| | | private List<BorgRepoConfig> repoConfigs = new ArrayList<>(); |
| | | |
| | | public void add(BorgRepoConfig repoConfig) { |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | 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()); |
| | | } |
| File was renamed from borgbutler-core/src/main/java/de/micromata/borgbutler/DiffTool.java |
| | |
| | | package de.micromata.borgbutler; |
| | | package de.micromata.borgbutler.data; |
| | | |
| | | import de.micromata.borgbutler.json.borg.BorgFilesystemItem; |
| | | import org.slf4j.Logger; |
| | |
| | | /** |
| | | * 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<>(); |
| | |
| | | } |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | } |
| | | 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(); |
| | |
| | | * @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. |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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. |
| | | */ |
| New file |
| | |
| | | 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")); |
| | | } |
| | | } |
| | | } |
| | |
| | | return result; |
| | | } |
| | | |
| | | protected void processStdOutLine(String line, int level) { |
| | | public void processStdOutLine(String line, int level) { |
| | | //log.info(line); |
| | | try { |
| | | outputStream.write(line.getBytes()); |
| | |
| | | } |
| | | } |
| | | |
| | | protected void processStdErrLine(String line, int level) { |
| | | public void processStdErrLine(String line, int level) { |
| | | //log.info(line); |
| | | try { |
| | | errorOutputStream.write(line.getBytes()); |
| | |
| | | public class JobResult<T> { |
| | | public enum Status {OK, ERROR} |
| | | @Getter |
| | | @Setter(AccessLevel.PACKAGE) |
| | | @Setter |
| | | private Status status; |
| | | @Getter |
| | | @Setter |
| | |
| | | */ |
| | | @Getter |
| | | @Setter |
| | | private int fileNumber; |
| | | private int fileNumber = -1; |
| | | |
| | | /** |
| | | * If created by diff tool, this flag represents the type of difference. |
| | | */ |
| File was renamed from borgbutler-core/src/test/java/de/micromata/borgbutler/DiffToolTest.java |
| | |
| | | package de.micromata.borgbutler; |
| | | |
| | | import de.micromata.borgbutler.data.DiffFileSystemFilter; |
| | | import de.micromata.borgbutler.json.borg.BorgFilesystemItem; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | |
| | | |
| | | 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"); |
| | |
| | | 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()); |
| | |
| | | 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()); |
| | |
| | | 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()); |
| | |
| | | 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()); |
| | |
| | | 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; |
| | |
| | | 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() { |
| | |
| | | public void copyFrom(ServerConfiguration other) { |
| | | super.copyFrom(other); |
| | | this.port = other.port; |
| | | this.showTestData = other.showTestData; |
| | | this.webDevelopmentMode = other.webDevelopmentMode; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | @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); |
| | | } |
| | |
| | | import React from 'react'; |
| | | import { |
| | | faBan, |
| | | faCaretDown, |
| | | faCaretUp, |
| | | faCheck, |
| | |
| | | faExclamationTriangle, |
| | | faInfoCircle, |
| | | faPlus, |
| | | faSkullCrossbones, |
| | | faSortDown, |
| | | faSortUp, |
| | | faSync, |
| | | faTrash, |
| | | faTimes, |
| | | faSkullCrossbones, |
| | | faTrash, |
| | | faUpload |
| | | } from '@fortawesome/free-solid-svg-icons' |
| | | import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; |
| | |
| | | ); |
| | | } |
| | | |
| | | function IconBan() { |
| | | return ( |
| | | <FontAwesomeIcon icon={faBan}/> |
| | | ); |
| | | } |
| | | |
| | | function IconCancel() { |
| | | return ( |
| | | <FontAwesomeIcon icon={faTimes}/> |
| | |
| | | |
| | | function IconSpinner() { |
| | | return ( |
| | | <FontAwesomeIcon icon={faCircleNotch} spin={true} size={'3x'} color={'#aaaaaa'} /> |
| | | <FontAwesomeIcon icon={faCircleNotch} spin={true} size={'3x'} color={'#aaaaaa'}/> |
| | | ); |
| | | } |
| | | |
| | |
| | | |
| | | export { |
| | | IconAdd, |
| | | IconBan, |
| | | IconCancel, |
| | | IconCheck, |
| | | IconCollapseClose, |
| | |
| | | <TabPane tabId={'1'}> |
| | | <FileListPanel |
| | | repoId={this.state.repoId} |
| | | archiveId={archive.id} |
| | | archive={archive} |
| | | archiveShortInfoList={archive.archiveShortInfoList} |
| | | /> |
| | | </TabPane> |
| | |
| | | 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 |
| | |
| | | |
| | | render = () => { |
| | | const entry = this.props.entry; |
| | | let downloadArchiveId = this.props.archiveId; |
| | | let displayPath = entry.displayPath; |
| | | let pathCss = 'tt'; |
| | | |
| | |
| | | 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'; |
| | |
| | | } |
| | | } |
| | | if (pathtooltipText) { |
| | | pathId = `path-${entry.fileNumber}`; |
| | | pathId = `path-${entry.fileNumber}-${entry.diffStatus}`; |
| | | pathTooltip = |
| | | <UncontrolledTooltip target={pathId}> |
| | | {pathtooltipText} |
| | |
| | | } 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} |
| | |
| | | entry: PropTypes.shape({}).isRequired, |
| | | search: PropTypes.string, |
| | | mode: PropTypes.string, |
| | | diffArchiveId: PropTypes.string, |
| | | changeCurrentDirectory: PropTypes.func.isRequired |
| | | }; |
| | | |
| | |
| | | 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, |
| | |
| | | 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} |
| | |
| | | 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> |
| | |
| | | <tbody> |
| | | {entries |
| | | .map((entry, index) => <FileListEntry |
| | | archiveId={archiveId} |
| | | archive={archive} |
| | | diffArchiveId={diffArchiveId} |
| | | entry={entry} |
| | | search={lowercaseSearch} |
| | |
| | | } |
| | | |
| | | FileListTable.propTypes = { |
| | | archiveId: PropTypes.string, |
| | | diffArchiveId: PropTypes.string, |
| | | entries: PropTypes.array, |
| | | search: PropTypes.string, |
| | |
| | | failed: false, |
| | | port: 9042, |
| | | webdevelopmentMode: false, |
| | | showDemoRepos: true, |
| | | maxArchiveContentCacheCapacityMb: 100, |
| | | redirect: false, |
| | | confirmModal: false |
| | |
| | | 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', |
| | |
| | | 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'} |
| | |
| | | <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 |
| | |
| | | <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> |