From 9093ed105bd99dd88fad4238570150faf35934af Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Wed, 14 Apr 2021 07:59:50 +0000
Subject: [PATCH] Kotlin and YAML introduced.

---
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/JCSCache.java                    |    2 
 .gitignore                                                                                   |    1 
 borgbutler-core/build.gradle                                                                 |   40 ++
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java                     |    2 
 gradle/wrapper/gradle-wrapper.jar                                                            |    0 
 borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/YamlUtils.kt                 |   61 ++++
 gradle/wrapper/gradle-wrapper.properties                                                     |    3 
 borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java                           |    2 
 borgbutler-core/src/test/java/de/micromata/borgbutler/cache/CacheTest.java                   |    4 
 borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgInstallationTest.java     |    2 
 gradlew.bat                                                                                  |   43 +-
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/ServerConfiguration.java      |    4 
 borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java                    |    2 
 borgbutler-server/build.gradle                                                               |   49 ++-
 build.gradle                                                                                 |   32 ++
 borgbutler-core/src/main/java/de/micromata/borgbutler/json/JsonUtils.java                    |    4 
 borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/Configuration.kt             |  133 ++++++++++
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.java |    2 
 gradlew                                                                                      |   53 ++-
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java         |    4 
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ConfigurationRest.java   |    2 
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java        |    2 
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java            |    2 
 /dev/null                                                                                    |  138 ----------
 borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/ConfigurationHandler.kt      |  158 ++++++++++++
 borgbutler-core/src/test/java/de/micromata/borgbutler/config/ConfigHandlerTest.java          |    1 
 borgbutler-core/src/main/java/de/micromata/borgbutler/cache/ButlerCache.java                 |    4 
 27 files changed, 527 insertions(+), 223 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6aba3e3..97799dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,4 @@
 borgbutler-webapp/build
 borgbutler-webapp/node_modules
 borgbutler-docker/app/target
+borgbutler-server-0.3-SNAPSHOT
diff --git a/borgbutler-core/build.gradle b/borgbutler-core/build.gradle
index 17fb801..7a89458 100644
--- a/borgbutler-core/build.gradle
+++ b/borgbutler-core/build.gradle
@@ -1,22 +1,29 @@
 plugins {
     id 'java'
+        id "org.jetbrains.kotlin.jvm" version "1.4.32"
 }
 
 description = 'borgbutler-core'
 
 dependencies {
-    compile group: 'commons-io', name: 'commons-io', version: '2.6'
-    compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
-    compile group: 'org.apache.commons', name: 'commons-exec', version: '1.3'
-    compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.2'
-    compile group: 'org.apache.commons', name: 'commons-compress', version: '1.18'
-    compile group: 'org.apache.commons', name: 'commons-jcs-core', version: '2.2.1'
+    implementation group: 'commons-io', name: 'commons-io', version: '2.8.0'
+    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
+    implementation group: 'org.apache.commons', name: 'commons-exec', version: '1.3'
+    implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.2'
+    implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.18'
+    implementation group: 'org.apache.commons', name: 'commons-jcs-core', version: '2.2.1'
     // https://mvnrepository.com/artifact/com.esotericsoftware/kryo
-    compile group: 'com.esotericsoftware', name: 'kryo', version: '5.0.0-RC1'
+    implementation group: 'com.esotericsoftware', name: 'kryo', version: '5.0.0-RC1'
     // Serialization (faster than Java built-in)
+    implementation 'io.github.microutils:kotlin-logging-jvm:2.0.6'
 
-    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
-    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.8'
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.3'
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.12.3'
+    // https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310
+    implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.12.3'
+
+
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
 }
 
 repositories {
@@ -24,8 +31,23 @@
     jcenter()
 }
 
+sourceSets {
+    main.kotlin.srcDirs += 'src/main/kotlin'
+    main.java.srcDirs += 'src/main/java'
+}
+
 test {
     // set heap size for the test JVM(s)
     minHeapSize = "128m"
     maxHeapSize = "1500m"
 }
+compileKotlin {
+    kotlinOptions {
+        jvmTarget = "1.8"
+    }
+}
+compileTestKotlin {
+    kotlinOptions {
+        jvmTarget = "1.9"
+    }
+}
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 e02592f..b661974 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
@@ -1,7 +1,7 @@
 package de.micromata.borgbutler;
 
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.data.Archive;
 import de.micromata.borgbutler.demo.DemoRepos;
 import de.micromata.borgbutler.jobs.AbstractCommandLineJob;
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 9ed4852..ce585cc 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
@@ -3,8 +3,8 @@
 import de.micromata.borgbutler.BorgCommandResult;
 import de.micromata.borgbutler.BorgCommands;
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.Configuration;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.Configuration;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.data.Archive;
 import de.micromata.borgbutler.data.ArchiveShortInfo;
 import de.micromata.borgbutler.data.FileSystemFilter;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/JCSCache.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/JCSCache.java
index 7cea260..ea85a0a 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/JCSCache.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/cache/JCSCache.java
@@ -1,6 +1,6 @@
 package de.micromata.borgbutler.cache;
 
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import org.apache.commons.jcs.JCS;
 import org.apache.commons.jcs.access.CacheAccess;
 import org.slf4j.Logger;
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
deleted file mode 100644
index b13063d..0000000
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package de.micromata.borgbutler.config;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import de.micromata.borgbutler.demo.DemoRepos;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Representation of ~/.borgbutler/borgbutler-config.json.
- */
-public class Configuration {
-    private Logger log = LoggerFactory.getLogger(Configuration.class);
-    /**
-     * Default dir name for restoring archives.
-     */
-    private static final String RESTORE_DIRNAME = "restore";
-
-    @JsonIgnore
-    private File workingDir;
-    /**
-     * The path of the borg command to use (optional).
-     */
-    private String borgCommand;
-
-    /**
-     * The borg version to install from github (optional).
-     */
-    private String borgVersion;
-
-    /**
-     * Default is 100 MB (approximately).
-     */
-    private int maxArchiveContentCacheCapacityMb = 100;
-
-    private boolean showDemoRepos = true;
-
-    /**
-     * Default is restore inside BorgButler's home dir (~/.borgbutler/restore).
-     */
-    @JsonProperty("restoreDir")
-    private String restoreDirPath;
-    @JsonIgnore
-    private File restoreHomeDir;
-
-    @JsonProperty
-    private List<BorgRepoConfig> repoConfigs = new ArrayList<>();
-
-    public void add(BorgRepoConfig repoConfig) {
-        synchronized (repoConfigs) {
-            repoConfigs.add(repoConfig);
-        }
-    }
-
-    public boolean remove(String idOrName) {
-        if (idOrName == null) {
-            return false;
-        }
-        synchronized (repoConfigs) {
-            for (BorgRepoConfig repoConfig : getAllRepoConfigs()) {
-                if (StringUtils.equals(idOrName, repoConfig.getRepo()) || StringUtils.equals(idOrName, repoConfig.getId())) {
-                    repoConfigs.remove(repoConfig);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public BorgRepoConfig getRepoConfig(String idOrName) {
-        if (idOrName == null) {
-            return null;
-        }
-        for (BorgRepoConfig repoConfig : getAllRepoConfigs()) {
-            if (StringUtils.equals(idOrName, repoConfig.getRepo()) || StringUtils.equals(idOrName, repoConfig.getId())) {
-                return repoConfig;
-            }
-        }
-        return null;
-    }
-
-    public File getRestoreHomeDir() {
-        if (restoreHomeDir == null) {
-            if (StringUtils.isNotBlank(restoreDirPath)) {
-                restoreHomeDir = new File(restoreDirPath);
-            } else {
-                restoreHomeDir = new File(workingDir, RESTORE_DIRNAME);
-            }
-            if (!restoreHomeDir.exists()) {
-                log.info("Creating dir '" + restoreHomeDir.getAbsolutePath() + "' for restoring backup files and directories.");
-            }
-        }
-        return restoreHomeDir;
-    }
-
-    public void copyFrom(Configuration other) {
-        this.borgCommand = other.borgCommand;
-        this.maxArchiveContentCacheCapacityMb = other.maxArchiveContentCacheCapacityMb;
-        this.showDemoRepos = other.showDemoRepos;
-    }
-
-    @JsonIgnore
-    public List<BorgRepoConfig> getAllRepoConfigs() {
-        return DemoRepos.getAllRepos(repoConfigs);
-    }
-
-    List<BorgRepoConfig> getRepoConfigs() {
-        return repoConfigs;
-    }
-
-    /**
-     * Optional borg command to use.
-     */
-    public String getBorgCommand() {
-        return this.borgCommand;
-    }
-
-    public String getBorgVersion() {
-        return borgVersion;
-    }
-
-    public int getMaxArchiveContentCacheCapacityMb() {
-        return this.maxArchiveContentCacheCapacityMb;
-    }
-
-    public boolean isShowDemoRepos() {
-        return this.showDemoRepos;
-    }
-
-    public String getRestoreDirPath() {
-        return this.restoreDirPath;
-    }
-
-    Configuration setWorkingDir(File workingDir) {
-        this.workingDir = workingDir;
-        return this;
-    }
-
-    public Configuration setBorgCommand(String borgCommand) {
-        this.borgCommand = borgCommand;
-        return this;
-    }
-
-    public void setBorgVersion(String borgVersion) {
-        this.borgVersion = borgVersion;
-    }
-
-    public Configuration setShowDemoRepos(boolean showDemoRepos) {
-        this.showDemoRepos = showDemoRepos;
-        return this;
-    }
-}
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
deleted file mode 100644
index e6c82e9..0000000
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package de.micromata.borgbutler.config;
-
-import de.micromata.borgbutler.json.JsonUtils;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class ConfigurationHandler {
-    private static Logger log = LoggerFactory.getLogger(ConfigurationHandler.class);
-    private static ConfigurationHandler instance;
-    private static final String BUTLER_HOME_DIR = ".borgbutler";
-    private static final String CONFIG_FILENAME = "borgbutler-config.json";
-    private static final String CONFIG_BACKUP_DIR = "backup";
-    private File configFile;
-    private File configBackupDir;
-    private File workingDir;
-    private File butlerHomeDir;
-    private Configuration configuration;
-    private static Class<? extends Configuration> configClazz = Configuration.class;
-
-    public static void init(String butlerHomeDir) {
-        if (instance != null) {
-            throw new RuntimeException("ConfigurationHandler already initialized");
-        }
-        instance = new ConfigurationHandler(butlerHomeDir);
-    }
-
-    public static ConfigurationHandler getInstance() {
-        if (instance == null) instance = new ConfigurationHandler();
-        return instance;
-    }
-
-    public static Configuration getConfiguration() {
-        return getInstance().configuration;
-    }
-
-    public static void setConfigClazz(Class<? extends Configuration> configClazz) {
-        ConfigurationHandler.configClazz = configClazz;
-    }
-
-    private void read() {
-        log.info("Reading config file '" + configFile.getAbsolutePath() + "'");
-        try {
-            String json = "{}";
-            if (configFile.exists()) {
-                json = FileUtils.readFileToString(configFile, Definitions.STD_CHARSET);
-                // Migrate from first version:
-                if (json.contains("repo-configs")) {
-                    json = json.replace("repo-configs", "repoConfigs");
-                    json = json.replace("display_name", "displayName");
-                }
-            }
-            this.configuration = JsonUtils.fromJson(configClazz, json);
-            if (this.configuration == null) {
-                try {
-                    this.configuration = configClazz.getDeclaredConstructor().newInstance();
-                } catch (Exception ex) {
-                    log.error("Internal error: Can't instantiate object of type '" + configClazz + "': " + ex.getMessage(), ex);
-                    return;
-                }
-            }
-            if (this.configuration.getRepoConfigs() != null) {
-                for (BorgRepoConfig repoConfig : this.configuration.getRepoConfigs()) {
-                    if (StringUtils.isBlank(repoConfig.getDisplayName())) {
-                        repoConfig.setDisplayName(repoConfig.getRepo());
-                    }
-                }
-            }
-            this.configuration.setWorkingDir(workingDir);
-        } catch (IOException ex) {
-            log.error("Error while trying to read from config file: " + configFile.getAbsolutePath() + ": " + ex.getMessage(), ex);
-            return;
-        }
-    }
-
-    public void save() {
-        if (this.configuration.getRepoConfigs() != null) {
-            for (BorgRepoConfig repoConfig : this.configuration.getRepoConfigs()) {
-                if (StringUtils.isNotBlank(repoConfig.getPassphrase())) {
-                    log.info("Removing password command from config because password command is given: " + repoConfig.getPasswordCommand());
-                    repoConfig.setPassphrase(null); // Don't use password (anymore) if password command is available.
-                }
-            }
-        }
-        String json = JsonUtils.toJson(configuration, true);
-        try {
-            if (configFile.exists()) {
-                // Create backup-file first:
-                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss'-'");
-                File configBackupFile = new File(configBackupDir, formatter.format(new Date()) + CONFIG_FILENAME);
-                log.info("Creating backup file first: '" + configBackupFile.getAbsolutePath() + "'");
-                FileUtils.copyFile(configFile, configBackupFile);
-            }
-            log.info("Writing config file '" + configFile.getAbsolutePath() + "'");
-            FileUtils.write(configFile, json, Definitions.STD_CHARSET);
-        } catch (IOException ex) {
-            log.error("Error while trying to write config file: " + configFile.getAbsolutePath() + ": " + ex.getMessage(), ex);
-        }
-    }
-
-    private ConfigurationHandler() {
-        this(null);
-    }
-
-    private ConfigurationHandler(String butlerHomeDir) {
-        if (butlerHomeDir != null) {
-            workingDir = new File(butlerHomeDir);
-        } else {
-            workingDir = new File(System.getProperty("user.home"), BUTLER_HOME_DIR);
-        }
-        log.info("Using directory '" + workingDir.getAbsolutePath() + "' as BorgButler's home directory.");
-        if (!workingDir.exists()) {
-            log.info("Creating borg-butlers working directory: " + workingDir.getAbsolutePath());
-            workingDir.mkdirs();
-        }
-        configFile = new File(workingDir, CONFIG_FILENAME);
-        configBackupDir = new File(workingDir, CONFIG_BACKUP_DIR);
-        if (!configBackupDir.exists()) {
-            log.info("Creating borg-butlers backup directory: " + configBackupDir.getAbsolutePath());
-            configBackupDir.mkdirs();
-        }
-        read();
-    }
-
-    public File getConfigFile() {
-        return this.configFile;
-    }
-
-    public File getWorkingDir() {
-        return this.workingDir;
-    }
-}
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
index df4865d..c94d2bf 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/demo/DemoRepos.java
@@ -3,7 +3,7 @@
 import de.micromata.borgbutler.BorgCommand;
 import de.micromata.borgbutler.BorgJob;
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.config.Definitions;
 import de.micromata.borgbutler.data.Repository;
 import de.micromata.borgbutler.jobs.JobResult;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/JsonUtils.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/JsonUtils.java
index c27a978..5263f72 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/JsonUtils.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/JsonUtils.java
@@ -1,8 +1,8 @@
 package de.micromata.borgbutler.json;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.io.JsonStringEncoder;
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.core.util.BufferRecyclers;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
@@ -45,7 +45,7 @@
 
     public static String toJson(String str) {
         if (str == null) return "";
-        return new String(BufferRecyclers.getJsonStringEncoder().quoteAsString(str));
+        return new String(JsonStringEncoder.getInstance().quoteAsString(str));
     }
 
     public static <T> T fromJson(Class<T> clazz, String json) {
diff --git a/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/Configuration.kt b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/Configuration.kt
new file mode 100644
index 0000000..07bbd39
--- /dev/null
+++ b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/Configuration.kt
@@ -0,0 +1,133 @@
+package org.micromata.borgbutler.config
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+import com.fasterxml.jackson.annotation.JsonProperty
+import de.micromata.borgbutler.config.BorgRepoConfig
+import de.micromata.borgbutler.demo.DemoRepos
+import org.apache.commons.lang3.StringUtils
+import org.slf4j.LoggerFactory
+import java.io.File
+
+/**
+ * Representation of ~/.borgbutler/borgbutler-config.json.
+ */
+open class Configuration {
+    private val log = LoggerFactory.getLogger(Configuration::class.java)
+
+    @JsonIgnore
+    private var workingDir: File? = null
+    /**
+     * Optional borg command to use.
+     */
+    /**
+     * The path of the borg command to use (optional).
+     */
+    var borgCommand: String? = null
+        private set
+
+    /**
+     * The borg version to install from github (optional).
+     */
+    var borgVersion: String? = null
+
+    /**
+     * Default is 100 MB (approximately).
+     */
+    var maxArchiveContentCacheCapacityMb = 100
+        private set
+    var isShowDemoRepos = true
+        private set
+
+    /**
+     * Default is restore inside BorgButler's home dir (~/.borgbutler/restore).
+     */
+    @JsonProperty("restoreDir")
+    val restoreDirPath: String? = null
+
+    @JsonIgnore
+    private var restoreHomeDir: File? = null
+
+    @JsonProperty
+    private val repoConfigs = mutableListOf<BorgRepoConfig>()
+
+    fun add(repoConfig: BorgRepoConfig) {
+        synchronized(repoConfigs) { repoConfigs.add(repoConfig) }
+    }
+
+    fun remove(idOrName: String?): Boolean {
+        if (idOrName == null) {
+            return false
+        }
+        synchronized(repoConfigs) {
+            for (repoConfig in allRepoConfigs) {
+                if (StringUtils.equals(idOrName, repoConfig.repo) || StringUtils.equals(idOrName, repoConfig.id)) {
+                    repoConfigs.remove(repoConfig)
+                    return true
+                }
+            }
+        }
+        return false
+    }
+
+    fun getRepoConfig(idOrName: String?): BorgRepoConfig? {
+        if (idOrName == null) {
+            return null
+        }
+        for (repoConfig in allRepoConfigs) {
+            if (StringUtils.equals(idOrName, repoConfig.repo) || StringUtils.equals(idOrName, repoConfig.id)) {
+                return repoConfig
+            }
+        }
+        return null
+    }
+
+    fun getRestoreHomeDir(): File {
+        if (restoreHomeDir == null) {
+            restoreDirPath?.let {
+                restoreHomeDir = File(it)
+            } ?: run {
+                restoreHomeDir = File(workingDir, RESTORE_DIRNAME)
+            }
+            if (!restoreHomeDir!!.exists()) {
+                log.info("Creating dir '" + restoreHomeDir?.absolutePath + "' for restoring backup files and directories.")
+            }
+        }
+        return restoreHomeDir!!
+    }
+
+    fun copyFrom(other: Configuration) {
+        borgCommand = other.borgCommand
+        maxArchiveContentCacheCapacityMb = other.maxArchiveContentCacheCapacityMb
+        isShowDemoRepos = other.isShowDemoRepos
+    }
+
+    @get:JsonIgnore
+    val allRepoConfigs: List<BorgRepoConfig>
+        get() = DemoRepos.getAllRepos(repoConfigs)
+
+    fun getRepoConfigs(): List<BorgRepoConfig> {
+        return repoConfigs
+    }
+
+    fun setWorkingDir(workingDir: File?): Configuration {
+        this.workingDir = workingDir
+        return this
+    }
+
+    fun setBorgCommand(borgCommand: String?): Configuration {
+        this.borgCommand = borgCommand
+        return this
+    }
+
+    fun setShowDemoRepos(showDemoRepos: Boolean): Configuration {
+        isShowDemoRepos = showDemoRepos
+        return this
+    }
+
+    companion object {
+        /**
+         * Default dir name for restoring archives.
+         */
+        private const val RESTORE_DIRNAME = "restore"
+    }
+}
diff --git a/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/ConfigurationHandler.kt b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/ConfigurationHandler.kt
new file mode 100644
index 0000000..beddcb8
--- /dev/null
+++ b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/ConfigurationHandler.kt
@@ -0,0 +1,158 @@
+package org.micromata.borgbutler.config
+
+import de.micromata.borgbutler.config.Definitions
+import de.micromata.borgbutler.json.JsonUtils
+import org.apache.commons.io.FileUtils
+import org.slf4j.LoggerFactory
+import java.io.File
+import java.io.IOException
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * Reads and writes config file borgbutler-config.json/borgbutler-config.yaml
+ */
+class ConfigurationHandler private constructor(butlerHomeDir: String? = null) {
+    val configFile: File
+    private val configBackupDir: File
+    var workingDir: File
+        private set
+    private val butlerHomeDir: File? = null
+    private var configuration: Configuration? = null
+
+    private fun read() {
+        if (configFile.canRead()) {
+            log.info("Reading config file '" + configFile.absolutePath + "'")
+        } else {
+            readOldJson()
+        }
+        try {
+            if (configuration == null) {
+                try {
+                    configuration = configClazz.getDeclaredConstructor().newInstance()
+                } catch (ex: Exception) {
+                    log.error(
+                        "Internal error: Can't instantiate object of type '" + configClazz + "': " + ex.message,
+                        ex
+                    )
+                    return
+                }
+            }
+            configuration?.getRepoConfigs()?.filter { it.displayName.isNullOrBlank() }?.forEach { repoConfig ->
+                repoConfig.displayName = repoConfig.repo
+            }
+            configuration?.setWorkingDir(workingDir)
+        } catch (ex: IOException) {
+            log.error("Error while trying to read from config file: " + configFile.absolutePath + ": " + ex.message, ex)
+            return
+        }
+    }
+
+    /**
+     * Backward compability
+     */
+    private fun readOldJson() {
+        val jsonConfigFile = File(workingDir, OLD_JSON_CONFIG_FILENAME)
+        if (!jsonConfigFile.canRead()) {
+            // Nothing to do
+            return
+        }
+        var json: String? = null
+        if (jsonConfigFile.exists()) {
+            json = FileUtils.readFileToString(jsonConfigFile, Definitions.STD_CHARSET)
+            // Migrate from first version:
+            if (json.contains("repo-configs")) {
+                json = json.replace("repo-configs", "repoConfigs")
+                json = json.replace("display_name", "displayName")
+            }
+            val formatter = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss'-'")
+            val backupFilename = "${formatter.format(Date())}-old-${jsonConfigFile.name}"
+            log.info("Migrating old json config file to yaml file. Renaming old json file '${jsonConfigFile.absolutePath}' to '$backupFilename'.")
+            FileUtils.moveFile(jsonConfigFile, File(jsonConfigFile.parent, backupFilename))
+        }
+        val newConfig = JsonUtils.fromJson(configClazz, json)
+            ?: // Nothing to do
+            return
+        configuration = newConfig
+        save()
+    }
+
+    fun save() {
+        configuration?.getRepoConfigs()?.filter { !it.passphrase.isNullOrBlank() }?.forEach { repoConfig ->
+            log.info("Removing password command from config because password command is given: " + repoConfig.passwordCommand)
+            repoConfig.passphrase = null // Don't use password (anymore) if password command is available.
+        }
+        val yaml = YamlUtils.toYaml(configuration)
+        try {
+            if (configFile.exists()) {
+                // Create backup-file first:
+                makeBackup(configFile)
+            }
+            log.info("Writing config file '" + configFile.absolutePath + "'")
+            FileUtils.write(configFile, yaml, Definitions.STD_CHARSET)
+        } catch (ex: IOException) {
+            log.error("Error while trying to write config file: " + configFile.absolutePath + ": " + ex.message, ex)
+        }
+    }
+
+    private fun makeBackup(file: File) {
+        val formatter = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss'-'")
+        val backupFile = File(configBackupDir, formatter.format(Date()) + file.name)
+        log.info("Creating backup file first: '" + backupFile.absolutePath + "'")
+        FileUtils.copyFile(file, backupFile)
+    }
+
+    companion object {
+        private val log = LoggerFactory.getLogger(ConfigurationHandler::class.java)
+        private var instance: ConfigurationHandler? = null
+        private const val BUTLER_HOME_DIR = ".borgbutler"
+        private const val OLD_JSON_CONFIG_FILENAME = "borgbutler-config.json"
+        private const val CONFIG_FILENAME = "borgbutler.config"
+        private const val CONFIG_BACKUP_DIR = "backup"
+        private var configClazz: Class<out Configuration> = Configuration::class.java
+
+        @kotlin.jvm.JvmStatic
+        fun init(butlerHomeDir: String?) {
+            if (instance != null) {
+                throw RuntimeException("ConfigurationHandler already initialized")
+            }
+            instance = ConfigurationHandler(butlerHomeDir)
+        }
+
+        @kotlin.jvm.JvmStatic
+        fun getInstance(): ConfigurationHandler? {
+            if (instance == null) instance = ConfigurationHandler()
+            return instance
+        }
+
+        @kotlin.jvm.JvmStatic
+        fun getConfiguration(): Configuration? {
+            return getInstance()!!.configuration
+        }
+
+        @kotlin.jvm.JvmStatic
+        fun setConfigClazz(configClazz: Class<out Configuration>) {
+            Companion.configClazz = configClazz
+        }
+    }
+
+    init {
+        workingDir = if (butlerHomeDir != null) {
+            File(butlerHomeDir)
+        } else {
+            File(System.getProperty("user.home"), BUTLER_HOME_DIR)
+        }
+        log.info("Using directory '" + workingDir.getAbsolutePath() + "' as BorgButler's home directory.")
+        if (!workingDir.exists()) {
+            log.info("Creating borg-butlers working directory: " + workingDir.getAbsolutePath())
+            workingDir.mkdirs()
+        }
+        configFile = File(workingDir, CONFIG_FILENAME)
+        configBackupDir = File(workingDir, CONFIG_BACKUP_DIR)
+        if (!configBackupDir.exists()) {
+            log.info("Creating borg-butlers backup directory: " + configBackupDir.absolutePath)
+            configBackupDir.mkdirs()
+        }
+        read()
+    }
+}
diff --git a/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/YamlUtils.kt b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/YamlUtils.kt
new file mode 100644
index 0000000..fc8b5f4
--- /dev/null
+++ b/borgbutler-core/src/main/kotlin/org/micromata/borgbutler/config/YamlUtils.kt
@@ -0,0 +1,61 @@
+package org.micromata.borgbutler.config
+
+import com.fasterxml.jackson.annotation.JsonInclude
+import com.fasterxml.jackson.core.type.TypeReference
+import com.fasterxml.jackson.databind.DeserializationFeature
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator
+import com.fasterxml.jackson.dataformat.yaml.YAMLParser
+import mu.KotlinLogging
+import java.io.IOException
+import java.io.StringWriter
+
+private val log = KotlinLogging.logger {}
+
+object YamlUtils {
+    /**
+     * @param obj
+     * @return
+     */
+    fun toYaml(obj: Any?): String {
+        if (obj == null) {
+            return ""
+        }
+        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
+        return try {
+            val writer = StringWriter()
+            objectMapper.writeValue(writer, obj)
+            writer.toString()
+        } catch (ex: IOException) {
+            log.error(ex.message, ex)
+            ""
+        }
+    }
+
+    fun <T> fromYaml(clazz: Class<T>?, json: String?): T? {
+        return try {
+            objectMapper.readValue(json, clazz)
+        } catch (ex: IOException) {
+            log.error(ex.message, ex)
+            null
+        }
+    }
+
+    fun <T> fromYaml(type: TypeReference<T>?, json: String): T? {
+        try {
+            return objectMapper.readValue(json, type)
+        } catch (ex: Exception) {
+            log.error("Json: '" + json + "': " + ex.message, ex)
+        }
+        return null
+    }
+
+    private val objectMapper: ObjectMapper = ObjectMapper(YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER))
+
+    init {
+        objectMapper.findAndRegisterModules()
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
+    }
+}
diff --git a/borgbutler-core/src/test/java/de/micromata/borgbutler/cache/CacheTest.java b/borgbutler-core/src/test/java/de/micromata/borgbutler/cache/CacheTest.java
index ec173b6..f65bb69 100644
--- a/borgbutler-core/src/test/java/de/micromata/borgbutler/cache/CacheTest.java
+++ b/borgbutler-core/src/test/java/de/micromata/borgbutler/cache/CacheTest.java
@@ -1,8 +1,8 @@
 package de.micromata.borgbutler.cache;
 
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.Configuration;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.Configuration;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.data.Archive;
 import de.micromata.borgbutler.data.Repository;
 import de.micromata.borgbutler.json.borg.BorgFilesystemItem;
diff --git a/borgbutler-core/src/test/java/de/micromata/borgbutler/config/ConfigHandlerTest.java b/borgbutler-core/src/test/java/de/micromata/borgbutler/config/ConfigHandlerTest.java
index 161f0de..57e396a 100644
--- a/borgbutler-core/src/test/java/de/micromata/borgbutler/config/ConfigHandlerTest.java
+++ b/borgbutler-core/src/test/java/de/micromata/borgbutler/config/ConfigHandlerTest.java
@@ -2,6 +2,7 @@
 
 import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.Test;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/borgbutler-server/build.gradle b/borgbutler-server/build.gradle
index 3b6bf3c..62e4864 100644
--- a/borgbutler-server/build.gradle
+++ b/borgbutler-server/build.gradle
@@ -1,7 +1,11 @@
 buildscript {
+    ext.kotlin_version = '1.4.32'
     repositories {
         mavenCentral()
     }
+    dependencies {
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
 }
 
 plugins {
@@ -13,25 +17,29 @@
 dependencies {
     compile project(':borgbutler-core')
     // https://mvnrepository.com/artifact/org.apache.commons/commons-text
-    compile group: 'org.apache.commons', name: 'commons-text', version: '1.6'
-    compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.12.v20180830'
-    compile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.4.12.v20180830'
-    compile group: 'org.eclipse.jetty', name: 'jetty-servlets', version: '9.4.12.v20180830'
-    compile group: 'org.glassfish.jaxb', name: 'jaxb-core', version: '2.3.0.1'
-    compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'
-    compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.27'
-    compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.27'
-    compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
-    compile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27'
-    compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
-    compile group: 'javax.xml.ws', name: 'jaxws-api', version: '2.3.1'
-    compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25'
+    implementation group: 'org.apache.commons', name: 'commons-text', version: '1.6'
+    implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.2'
+    implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.18'
+    implementation group: 'commons-io', name: 'commons-io', version: '2.8.0'
+    implementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.12.v20180830'
+    implementation group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.4.12.v20180830'
+    implementation group: 'org.eclipse.jetty', name: 'jetty-servlets', version: '9.4.12.v20180830'
+    implementation group: 'org.glassfish.jaxb', name: 'jaxb-core', version: '2.3.0.1'
+    implementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'
+    implementation group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.27'
+    implementation group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.27'
+    implementation group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
+    implementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27'
+    implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
+    implementation group: 'javax.xml.ws', name: 'jaxws-api', version: '2.3.1'
+    implementation group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25'
     // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
-    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'
+    implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'
 
     // https://mvnrepository.com/artifact/commons-cli/commons-cli
-    compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
+    implementation group: 'commons-cli', name: 'commons-cli', version: '1.4'
     testCompile group: 'org.mockito', name: 'mockito-core', version: '2.21.0'
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
 }
 
 repositories {
@@ -40,6 +48,7 @@
 }
 
 apply plugin: 'application'
+apply plugin: 'kotlin'
 mainClassName = "de.micromata.borgbutler.server.Main"
 
 run() {
@@ -100,3 +109,13 @@
 distZip.dependsOn ':borgbutler-webapp:npmBuild'
 //distZip.dependsOn ':borgbutler-docs:buildWebDoc'
 task(dist).dependsOn distZip
+compileKotlin {
+    kotlinOptions {
+        jvmTarget = "1.8"
+    }
+}
+compileTestKotlin {
+    kotlinOptions {
+        jvmTarget = "1.9"
+    }
+}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
index 2f288ff..520e818 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
@@ -1,8 +1,8 @@
 package de.micromata.borgbutler.server;
 
 import de.micromata.borgbutler.BorgCommands;
-import de.micromata.borgbutler.config.Configuration;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.Configuration;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpResponse;
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
index 036d7fe..f783ebc 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
@@ -1,7 +1,7 @@
 package de.micromata.borgbutler.server;
 
 import de.micromata.borgbutler.cache.ButlerCache;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.json.borg.BorgFilesystemItem;
 import de.micromata.borgbutler.server.jetty.JettyServer;
 import de.micromata.borgbutler.server.user.SingleUserManager;
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 ce67240..8cb5aef 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
@@ -2,8 +2,8 @@
 
 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 org.micromata.borgbutler.config.Configuration;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
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 90fe225..0897c94 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
@@ -3,7 +3,7 @@
 import de.micromata.borgbutler.BorgCommands;
 import de.micromata.borgbutler.cache.ButlerCache;
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.data.Archive;
 import de.micromata.borgbutler.data.DiffFileSystemFilter;
 import de.micromata.borgbutler.data.FileSystemFilter;
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.java
index adfe573..408d55a 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.java
@@ -4,7 +4,7 @@
 import de.micromata.borgbutler.BorgCommands;
 import de.micromata.borgbutler.cache.ButlerCache;
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.data.Repository;
 import de.micromata.borgbutler.jobs.JobResult;
 import de.micromata.borgbutler.json.JsonUtils;
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ConfigurationRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ConfigurationRest.java
index a5b2ad4..9a1d5d8 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ConfigurationRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ConfigurationRest.java
@@ -1,7 +1,7 @@
 package de.micromata.borgbutler.server.rest;
 
 import de.micromata.borgbutler.cache.ButlerCache;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.json.JsonUtils;
 import de.micromata.borgbutler.server.BorgInstallation;
 import de.micromata.borgbutler.server.ServerConfiguration;
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
index be744f0..151dfbf 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
@@ -3,7 +3,7 @@
 import de.micromata.borgbutler.BorgJob;
 import de.micromata.borgbutler.BorgQueueExecutor;
 import de.micromata.borgbutler.config.BorgRepoConfig;
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import de.micromata.borgbutler.jobs.AbstractJob;
 import de.micromata.borgbutler.json.JsonUtils;
 import de.micromata.borgbutler.json.borg.ProgressInfo;
diff --git a/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgInstallationTest.java b/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgInstallationTest.java
index dc97e98..490506f 100644
--- a/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgInstallationTest.java
+++ b/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgInstallationTest.java
@@ -1,6 +1,6 @@
 package de.micromata.borgbutler.server;
 
-import de.micromata.borgbutler.config.ConfigurationHandler;
+import org.micromata.borgbutler.config.ConfigurationHandler;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/build.gradle b/build.gradle
index d92fa1f..69def2a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,11 +42,41 @@
         )
     }
 
+    subprojects {
+        ext.depVersions = ['commonsio': '2.8.0', dep2: '2.0']
+    }
+
     test {
         useJUnitPlatform()
     }
 }
 
 wrapper {
-    gradleVersion = '4.10.2'
+    gradleVersion = '6.8.3'
 }
+//buildscript {
+//    ext.kotlin_version = '1.4.32-release-371'
+//    repositories {
+//        mavenCentral()
+//    }
+//    dependencies {
+//        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+//    }
+//}
+//apply plugin: 'kotlin'
+//repositories {
+//    mavenCentral()
+//}
+//dependencies {
+//    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+//}
+//compileKotlin {
+//    kotlinOptions {
+//        jvmTarget = "1.8"
+//    }
+//}
+//compileTestKotlin {
+//    kotlinOptions {
+//        jvmTarget = "1.8"
+//    }
+//}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 457aad0..e708b1c 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0bf2789..442d913 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Dec 07 23:41:31 CET 2018
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip
diff --git a/gradlew b/gradlew
index af6708f..4f906e0 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,21 @@
 #!/usr/bin/env sh
 
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 ##############################################################################
 ##
 ##  Gradle start up script for UN*X
@@ -28,7 +44,7 @@
 APP_BASE_NAME=`basename "$0"`
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m"'
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD="maximum"
@@ -66,6 +82,7 @@
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@
     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 fi
 
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
     JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@
         else
             eval `echo args$i`="\"$arg\""
         fi
-        i=$((i+1))
+        i=`expr $i + 1`
     done
     case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
     esac
 fi
 
@@ -159,14 +177,9 @@
     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
     echo " "
 }
-APP_ARGS=$(save "$@")
+APP_ARGS=`save "$@"`
 
 # Collect all arguments for the java command, following the shell quoting and substitution rules
 eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
 
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
-  cd "$(dirname "$0")"
-fi
-
 exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 0f8d593..ac1b06f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
 @if "%DEBUG%" == "" @echo off
 @rem ##########################################################################
 @rem
@@ -13,15 +29,18 @@
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m"
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@
 set JAVA_HOME=%JAVA_HOME:"=%
 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@
 
 goto fail
 
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
 :execute
 @rem Setup the command line
 
 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
+
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
 
 :end
 @rem End local scope for the variables with windows NT shell

--
Gitblit v1.10.0