diff --git a/ressourcen/libs/antlr-runtime.jar.dep.json b/ressourcen/libs/antlr-runtime.jar.dep.json
new file mode 100644
index 0000000000..62aeb7ff5b
--- /dev/null
+++ b/ressourcen/libs/antlr-runtime.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.antlr/antlr-runtime",
+ "files":["antlr-runtime.jar"],
+ "installedVersion":"3.4",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"BSD",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":null,
+ "version":"3.4",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/bcpkix-jdk15on.jar b/ressourcen/libs/bcpkix-jdk15on.jar
index 2f8d6b6212..1df6c4adee 100644
Binary files a/ressourcen/libs/bcpkix-jdk15on.jar and b/ressourcen/libs/bcpkix-jdk15on.jar differ
diff --git a/ressourcen/libs/bcpkix-jdk15on.jar.dep.json b/ressourcen/libs/bcpkix-jdk15on.jar.dep.json
new file mode 100644
index 0000000000..578c8d4981
--- /dev/null
+++ b/ressourcen/libs/bcpkix-jdk15on.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.bouncycastle/bcpkix-jdk15to18",
+ "files":["bcpkix-jdk15on.jar"],
+ "installedVersion":"1.76",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n Bouncy Castle Licence\n http://www.bouncycastle.org/licence.html\n repo\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":{"jdk15to18":"jdk15on"},
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/bcprov-jdk15on.jar b/ressourcen/libs/bcprov-jdk15on.jar
index 814c945a99..58310a56e8 100644
Binary files a/ressourcen/libs/bcprov-jdk15on.jar and b/ressourcen/libs/bcprov-jdk15on.jar differ
diff --git a/ressourcen/libs/bcprov-jdk15on.jar.dep.json b/ressourcen/libs/bcprov-jdk15on.jar.dep.json
new file mode 100644
index 0000000000..0ffb21d6a7
--- /dev/null
+++ b/ressourcen/libs/bcprov-jdk15on.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.bouncycastle/bcprov-jdk15to18",
+ "files":["bcprov-jdk15on.jar"],
+ "installedVersion":"1.76",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n Bouncy Castle Licence\n http://www.bouncycastle.org/licence.html\n repo\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":{"jdk15to18":"jdk15on"},
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/bctls-jdk15on.jar b/ressourcen/libs/bctls-jdk15on.jar
index 4cb6cd08c9..7df4281a1e 100644
Binary files a/ressourcen/libs/bctls-jdk15on.jar and b/ressourcen/libs/bctls-jdk15on.jar differ
diff --git a/ressourcen/libs/bctls-jdk15on.jar.dep.json b/ressourcen/libs/bctls-jdk15on.jar.dep.json
new file mode 100644
index 0000000000..73a56185d0
--- /dev/null
+++ b/ressourcen/libs/bctls-jdk15on.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.bouncycastle/bctls-jdk15to18",
+ "files":["bctls-jdk15on.jar"],
+ "installedVersion":"1.76",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n Bouncy Castle Licence\n http://www.bouncycastle.org/licence.html\n repo\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":{"jdk15to18":"jdk15on"},
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/bcutil-jdk15on.jar b/ressourcen/libs/bcutil-jdk15on.jar
index 847e5242a1..06189ed3ea 100644
Binary files a/ressourcen/libs/bcutil-jdk15on.jar and b/ressourcen/libs/bcutil-jdk15on.jar differ
diff --git a/ressourcen/libs/bcutil-jdk15on.jar.dep.json b/ressourcen/libs/bcutil-jdk15on.jar.dep.json
new file mode 100644
index 0000000000..269d1950ad
--- /dev/null
+++ b/ressourcen/libs/bcutil-jdk15on.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.bouncycastle/bcutil-jdk15to18",
+ "files":["bcutil-jdk15on.jar"],
+ "installedVersion":"1.76",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n Bouncy Castle Licence\n http://www.bouncycastle.org/licence.html\n repo\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":{"jdk15to18":"jdk15on"},
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/jna.jar.dep.json b/ressourcen/libs/jna.jar.dep.json
new file mode 100644
index 0000000000..b9cec1ede7
--- /dev/null
+++ b/ressourcen/libs/jna.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"net.java.dev.jna/jna",
+ "files":["jna.jar"],
+ "installedVersion":"5.13.0",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n LGPL-2.1-or-later\n https://www.gnu.org/licenses/old-licenses/lgpl-2.1\n repo\n \n Java Native Access (JNA) is licensed under the LGPL, version 2.1 or\n later, or the Apache License, version 2.0. You can freely decide which\n license you want to apply to the project.\n \n \n \n Apache-2.0\n https://www.apache.org/licenses/LICENSE-2.0.txt\n repo\n \n Java Native Access (JNA) is licensed under the LGPL, version 2.1 or\n later, or the Apache License, version 2.0. You can freely decide which\n license you want to apply to the project.\n \n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":null,
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/jna_platform.jar.dep.json b/ressourcen/libs/jna_platform.jar.dep.json
new file mode 100644
index 0000000000..a8be96191a
--- /dev/null
+++ b/ressourcen/libs/jna_platform.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"net.java.dev.jna/jna-platform",
+ "files":["jna_platform.jar"],
+ "installedVersion":"5.13.0",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n LGPL-2.1-or-later\n https://www.gnu.org/licenses/old-licenses/lgpl-2.1\n repo\n \n Java Native Access (JNA) is licensed under the LGPL, version 2.1 or\n later, or the Apache License, version 2.0. You can freely decide which\n license you want to apply to the project.\n \n \n \n Apache-2.0\n https://www.apache.org/licenses/LICENSE-2.0.txt\n repo\n \n Java Native Access (JNA) is licensed under the LGPL, version 2.1 or\n later, or the Apache License, version 2.0. You can freely decide which\n license you want to apply to the project.\n \n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":{"jna-platform.jar":"jna_platform.jar"},
+ "version":"mvnLatest",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/sequence-library.jar.dep.json b/ressourcen/libs/sequence-library.jar.dep.json
new file mode 100644
index 0000000000..37b4a89519
--- /dev/null
+++ b/ressourcen/libs/sequence-library.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"de.regnis.q.sequence/sequence-library",
+ "files":["sequence-library.jar"],
+ "installedVersion":"1.0.2",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n Sequence Library License (BSD-like)\n https://svn.tmatesoft.com/repos/3rdparty/de.regnis.q.sequnce/trunk/LICENSE.txt\n repos\n Sequence Library License (BSD-like)\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":null,
+ "version":"1.0.2",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/sqljet.jar.dep.json b/ressourcen/libs/sqljet.jar.dep.json
new file mode 100644
index 0000000000..dc1d2312c3
--- /dev/null
+++ b/ressourcen/libs/sqljet.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.tmatesoft.sqljet/sqljet",
+ "files":["sqljet.jar"],
+ "installedVersion":"1.1.10",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n GNU General Public License (GPL)\n http://www.gnu.org/licenses/gpl.html\n repos\n GPL license with a dual-licensing option for closed source usage\n \n \n GNU General Public License Version 3 (GPL v3)\n https://www.gnu.org/licenses/gpl-3.0.txt\n repos\n GPL Version 3 license with a dual-licensing option for closed source usage\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":null,
+ "version":"1.1.10",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/ressourcen/libs/svnkit.jar.dep.json b/ressourcen/libs/svnkit.jar.dep.json
new file mode 100644
index 0000000000..8bbbb573b0
--- /dev/null
+++ b/ressourcen/libs/svnkit.jar.dep.json
@@ -0,0 +1,12 @@
+{
+ "artefact":"org.tmatesoft.svnkit/svnkit",
+ "files":["svnkit.jar"],
+ "installedVersion":"1.8.10",
+ "lastUpdate":"2023-08-31T11:52:39 CEST",
+ "license":"\n \n TMate Open Source License\n https://svnkit.com/license.html\n repos\n GPL-like license with a dual-licensing option for closed source usage\n \n ",
+ "minJRE":null,
+ "provider":"maven",
+ "renames":null,
+ "version":"1.8.10",
+ "confirm":true
+}
\ No newline at end of file
diff --git a/src/org/appwork/utils/svn/ExportEditor.java b/src/org/appwork/utils/svn/ExportEditor.java
new file mode 100644
index 0000000000..1e18b5c541
--- /dev/null
+++ b/src/org/appwork/utils/svn/ExportEditor.java
@@ -0,0 +1,250 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+import org.tmatesoft.svn.core.SVNCommitInfo;
+import org.tmatesoft.svn.core.SVNErrorCode;
+import org.tmatesoft.svn.core.SVNErrorMessage;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNPropertyValue;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+import org.tmatesoft.svn.core.io.diff.SVNDeltaProcessor;
+import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
+
+/**
+ * ISVNEditor implementation that will add directories and files into the target
+ * directory accordingly to update instructions sent by the server.
+ */
+public class ExportEditor implements ISVNEditor {
+
+ private File myRootDirectory;
+ private SVNDeltaProcessor myDeltaProcessor;
+
+ /**
+ * root - the local directory where the node tree is to be exported into.
+ */
+ public ExportEditor(File root) {
+ myRootDirectory = root;
+ /*
+ * Utility class that will help us to transform 'deltas' sent by the
+ * server to the new file contents.
+ */
+ myDeltaProcessor = new SVNDeltaProcessor();
+ }
+
+ /**
+ * Server reports revision to which application of the further instructions
+ * will update working copy to.
+ */
+ public void targetRevision(long revision) throws SVNException {
+ }
+
+ /**
+ * Called before sending other instructions.
+ */
+ public void openRoot(long revision) throws SVNException {
+ }
+
+ /**
+ * Called when a new directory has to be added.
+ *
+ * For each 'addDir' call server will call 'closeDir' method after all
+ * children of the added directory are added.
+ *
+ * This implementation creates corresponding directory below root directory.
+ */
+ public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
+ File newDir = new File(myRootDirectory, path);
+ if (!newDir.exists()) {
+ if (!newDir.mkdirs()) {
+ SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: failed to add the directory ''{0}''.", newDir);
+ throw new SVNException(err);
+ }
+ }
+ org.appwork.loggingv3.LogV3.fine("dir added: " + path);
+ }
+
+ /**
+ * Called when there is an existing directory that has to be 'opened' either
+ * to modify this directory properties or to process other files and
+ * directories inside this directory.
+ *
+ * In case of export this method will never be called because we reported
+ * that our 'working copy' is empty and so server knows that there are no
+ * 'existing' directories.
+ */
+ public void openDir(String path, long revision) throws SVNException {
+ }
+
+ /**
+ * Instructs to change opened or added directory property.
+ *
+ * This method is called to update properties set by the user as well as
+ * those created automatically, like "svn:committed-rev". See SVNProperty
+ * class for default property names.
+ *
+ * When property has to be deleted value will be 'null'.
+ */
+
+ public void changeDirProperty(String name, SVNPropertyValue property) throws SVNException {
+ }
+
+ /**
+ * Called when a new file has to be created.
+ *
+ * For each 'addFile' call server will call 'closeFile' method after sending
+ * file properties and contents.
+ *
+ * This implementation creates empty file below root directory, file
+ * contents will be updated later, and for empty files may not be sent at
+ * all.
+ */
+ public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
+ File file = new File(myRootDirectory, path);
+ if (file.exists()) {
+ SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: exported file ''{0}'' already exists!", file);
+ throw new SVNException(err);
+ }
+ try {
+ file.createNewFile();
+ } catch (IOException e) {
+ SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "error: cannot create new file ''{0}''", file);
+ throw new SVNException(err);
+ }
+ }
+
+ /**
+ * Called when there is an existing files that has to be 'opened' either to
+ * modify file contents or properties.
+ *
+ * In case of export this method will never be called because we reported
+ * that our 'working copy' is empty and so server knows that there are no
+ * 'existing' files.
+ */
+ public void openFile(String path, long revision) throws SVNException {
+ }
+
+ /**
+ * Instructs to add, modify or delete file property. In this example we skip
+ * this instruction, but 'real' export operation may inspect 'svn:eol-style'
+ * or 'svn:mime-type' property values to transfor file contents propertly
+ * after receiving.
+ */
+ public void changeFileProperty(String path, String name, SVNPropertyValue property) throws SVNException {
+ }
+
+ /**
+ * Called before sending 'delta' for a file. Delta may include instructions
+ * on how to create a file or how to modify existing file. In this example
+ * delta will always contain instructions on how to create a new file and so
+ * we set up deltaProcessor with 'null' base file and target file to which
+ * we would like to store the result of delta application.
+ */
+ public void applyTextDelta(String path, String baseChecksum) throws SVNException {
+ myDeltaProcessor.applyTextDelta((File) null, new File(myRootDirectory, path), false);
+ }
+
+ /**
+ * Server sends deltas in form of 'diff windows'. Depending on the file size
+ * there may be several diff windows. Utility class SVNDeltaProcessor
+ * processes these windows for us.
+ */
+ public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
+ return myDeltaProcessor.textDeltaChunk(diffWindow);
+ }
+
+ /**
+ * Called when all diff windows (delta) is transferred.
+ */
+ public void textDeltaEnd(String path) throws SVNException {
+ myDeltaProcessor.textDeltaEnd();
+ }
+
+ /**
+ * Called when file update is completed. This call always matches addFile or
+ * openFile call.
+ */
+ public void closeFile(String path, String textChecksum) throws SVNException {
+ }
+
+ /**
+ * Called when all child files and directories are processed. This call
+ * always matches addDir, openDir or openRoot call.
+ */
+ public void closeDir() throws SVNException {
+ }
+
+ /**
+ * Insturcts to delete an entry in the 'working copy'. Of course will not be
+ * called during export operation.
+ */
+ public void deleteEntry(String path, long revision) throws SVNException {
+ }
+
+ /**
+ * Called when directory at 'path' should be somehow processed, but
+ * authenticated user (or anonymous user) doesn't have enough access rights
+ * to get information on this directory (properties, children).
+ */
+ public void absentDir(String path) throws SVNException {
+ }
+
+ /**
+ * Called when file at 'path' should be somehow processed, but authenticated
+ * user (or anonymous user) doesn't have enough access rights to get
+ * information on this file (contents, properties).
+ */
+ public void absentFile(String path) throws SVNException {
+ }
+
+ /**
+ * Called when update is completed.
+ */
+ public SVNCommitInfo closeEdit() throws SVNException {
+ return null;
+ }
+
+ /**
+ * Called when update is completed with an error or server requests client
+ * to abort update operation.
+ */
+ public void abortEdit() throws SVNException {
+ }
+
+}
diff --git a/src/org/appwork/utils/svn/ExportReporterBaton.java b/src/org/appwork/utils/svn/ExportReporterBaton.java
new file mode 100644
index 0000000000..41baff4c7a
--- /dev/null
+++ b/src/org/appwork/utils/svn/ExportReporterBaton.java
@@ -0,0 +1,70 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.io.ISVNReporter;
+import org.tmatesoft.svn.core.io.ISVNReporterBaton;
+
+public class ExportReporterBaton implements ISVNReporterBaton {
+
+ private long exportRevision;
+
+ public ExportReporterBaton(long revision) {
+ exportRevision = revision;
+ }
+
+ public void report(ISVNReporter reporter) throws SVNException {
+ try {
+ /*
+ * Here empty working copy is reported.
+ *
+ * ISVNReporter includes methods that allows to report mixed-rev
+ * working copy and even let server know that some files or
+ * directories are locally missing or locked.
+ */
+ reporter.setPath("", null, exportRevision, SVNDepth.INFINITY, true);
+
+ /*
+ * Don't forget to finish the report!
+ */
+ reporter.finishReport();
+ } catch (SVNException svne) {
+ reporter.abortReport();
+ org.appwork.loggingv3.LogV3.fine("Report failed.");
+ }
+ }
+}
diff --git a/src/org/appwork/utils/svn/FilePathFilter.java b/src/org/appwork/utils/svn/FilePathFilter.java
new file mode 100644
index 0000000000..3024135d36
--- /dev/null
+++ b/src/org/appwork/utils/svn/FilePathFilter.java
@@ -0,0 +1,45 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+import org.tmatesoft.svn.core.SVNDirEntry;
+
+/**
+ * @author Thomas
+ *
+ */
+public interface FilePathFilter {
+
+ public boolean accept(SVNDirEntry path);
+}
diff --git a/src/org/appwork/utils/svn/InfoEventHandler.java b/src/org/appwork/utils/svn/InfoEventHandler.java
new file mode 100644
index 0000000000..33df53580a
--- /dev/null
+++ b/src/org/appwork/utils/svn/InfoEventHandler.java
@@ -0,0 +1,95 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+
+import org.tmatesoft.svn.core.SVNNodeKind;
+import org.tmatesoft.svn.core.wc.ISVNInfoHandler;
+import org.tmatesoft.svn.core.wc.SVNInfo;
+
+public class InfoEventHandler implements ISVNInfoHandler {
+
+ public void handleInfo(SVNInfo info) {
+ org.appwork.loggingv3.LogV3.fine("-----------------INFO-----------------");
+ org.appwork.loggingv3.LogV3.fine("Local Path: " + info.getPath());
+ org.appwork.loggingv3.LogV3.fine("URL: " + info.getURL());
+
+ if (info.isRemote() && info.getRepositoryRootURL() != null) {
+ org.appwork.loggingv3.LogV3.fine("Repository Root URL: " + info.getRepositoryRootURL());
+ }
+
+ if (info.getRepositoryUUID() != null) {
+ org.appwork.loggingv3.LogV3.fine("Repository UUID: " + info.getRepositoryUUID());
+ }
+
+ org.appwork.loggingv3.LogV3.fine("Revision: " + info.getRevision().getNumber());
+ org.appwork.loggingv3.LogV3.fine("Node Kind: " + info.getKind().toString());
+
+ if (!info.isRemote()) {
+ org.appwork.loggingv3.LogV3.fine("Schedule: " + (info.getSchedule() != null ? info.getSchedule() : "normal"));
+ }
+
+ org.appwork.loggingv3.LogV3.fine("Last Changed Author: " + info.getAuthor());
+ org.appwork.loggingv3.LogV3.fine("Last Changed Revision: " + info.getCommittedRevision().getNumber());
+ org.appwork.loggingv3.LogV3.fine("Last Changed Date: " + info.getCommittedDate());
+
+ if (info.getPropTime() != null) {
+ org.appwork.loggingv3.LogV3.fine("Properties Last Updated: " + info.getPropTime());
+ }
+
+ if (info.getKind() == SVNNodeKind.FILE && info.getChecksum() != null) {
+ if (info.getTextTime() != null) {
+ org.appwork.loggingv3.LogV3.fine("Text Last Updated: " + info.getTextTime());
+ }
+ org.appwork.loggingv3.LogV3.fine("Checksum: " + info.getChecksum());
+ }
+
+ if (info.getLock() != null) {
+ if (info.getLock().getID() != null) {
+ org.appwork.loggingv3.LogV3.fine("Lock Token: " + info.getLock().getID());
+ }
+
+ org.appwork.loggingv3.LogV3.fine("Lock Owner: " + info.getLock().getOwner());
+ org.appwork.loggingv3.LogV3.fine("Lock Created: " + info.getLock().getCreationDate());
+
+ if (info.getLock().getExpirationDate() != null) {
+ org.appwork.loggingv3.LogV3.fine("Lock Expires: " + info.getLock().getExpirationDate());
+ }
+
+ if (info.getLock().getComment() != null) {
+ org.appwork.loggingv3.LogV3.fine("Lock Comment: " + info.getLock().getComment());
+ }
+ }
+ }
+}
diff --git a/src/org/appwork/utils/svn/LocaleRunnable.java b/src/org/appwork/utils/svn/LocaleRunnable.java
new file mode 100644
index 0000000000..8e8ac3e92a
--- /dev/null
+++ b/src/org/appwork/utils/svn/LocaleRunnable.java
@@ -0,0 +1,56 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+import java.util.Locale;
+
+public abstract class LocaleRunnable {
+ private static final Object LOCK = new Object();
+
+ protected abstract T run() throws E;
+
+ public T runEnglish() throws E {
+ synchronized (LOCK) {
+
+ Locale bef = Locale.getDefault();
+ Locale.setDefault(Locale.ENGLISH);
+ try {
+ return run();
+ } finally {
+ Locale.setDefault(bef);
+ }
+ }
+ }
+
+}
diff --git a/src/org/appwork/utils/svn/ResolveHandler.java b/src/org/appwork/utils/svn/ResolveHandler.java
new file mode 100644
index 0000000000..8937f6b294
--- /dev/null
+++ b/src/org/appwork/utils/svn/ResolveHandler.java
@@ -0,0 +1,44 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+import java.io.File;
+
+import org.tmatesoft.svn.core.wc.SVNInfo;
+
+public interface ResolveHandler {
+
+ String resolveConflict(SVNInfo info, File file, String contents, int startMine, int endMine, int startTheirs, int endTheirs);
+
+}
diff --git a/src/org/appwork/utils/svn/StatusEventHandler.java b/src/org/appwork/utils/svn/StatusEventHandler.java
new file mode 100644
index 0000000000..abf14bbeb1
--- /dev/null
+++ b/src/org/appwork/utils/svn/StatusEventHandler.java
@@ -0,0 +1,249 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+
+import org.tmatesoft.svn.core.SVNCancelException;
+import org.tmatesoft.svn.core.SVNLock;
+import org.tmatesoft.svn.core.wc.ISVNEventHandler;
+import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
+import org.tmatesoft.svn.core.wc.SVNEvent;
+import org.tmatesoft.svn.core.wc.SVNEventAction;
+import org.tmatesoft.svn.core.wc.SVNStatus;
+import org.tmatesoft.svn.core.wc.SVNStatusType;
+
+public class StatusEventHandler implements ISVNStatusHandler, ISVNEventHandler {
+ private final boolean myIsRemote;
+
+ public StatusEventHandler(final boolean isRemote) {
+ this.myIsRemote = isRemote;
+ }
+
+ public void checkCancelled() throws SVNCancelException {
+ }
+
+ public void handleEvent(final SVNEvent event, final double progress) {
+ final SVNEventAction action = event.getAction();
+ /*
+ * Print out the revision against which the status was performed. This
+ * event is dispatched when the SVNStatusClient.doStatus() was invoked
+ * with the flag remote set to true - that is for a local status it
+ * won't be dispatched.
+ */
+ if (action == SVNEventAction.STATUS_COMPLETED) {
+ org.appwork.loggingv3.LogV3.fine("Status against revision: " + event.getRevision());
+ }
+
+ }
+
+ public void handleStatus(final SVNStatus status) {
+ /*
+ * Gets the status of file/directory/symbolic link text contents. It is
+ * SVNStatusType who contains information on the state of an item.
+ */
+ final SVNStatusType contentsStatus = status.getContentsStatus();
+
+ String pathChangeType = " ";
+
+ final boolean isAddedWithHistory = status.isCopied();
+ if (contentsStatus == SVNStatusType.STATUS_MODIFIED) {
+ /*
+ * The contents of the file have been Modified.
+ */
+ pathChangeType = "M";
+ } else if (contentsStatus == SVNStatusType.STATUS_CONFLICTED) {
+ /*
+ * The item is in a state of Conflict.
+ */
+ pathChangeType = "C";
+ } else if (contentsStatus == SVNStatusType.STATUS_DELETED) {
+ /*
+ * The item has been scheduled for Deletion from the repository.
+ */
+ pathChangeType = "D";
+ } else if (contentsStatus == SVNStatusType.STATUS_ADDED) {
+ /*
+ * The item has been scheduled for Addition to the repository.
+ */
+ pathChangeType = "A";
+ } else if (contentsStatus == SVNStatusType.STATUS_UNVERSIONED) {
+ /*
+ * The item is not under version control.
+ */
+ pathChangeType = "?";
+ } else if (contentsStatus == SVNStatusType.STATUS_EXTERNAL) {
+ /*
+ * The item is unversioned, but is used by an eXternals definition.
+ */
+ pathChangeType = "X";
+ } else if (contentsStatus == SVNStatusType.STATUS_IGNORED) {
+ /*
+ * The item is Ignored.
+ */
+ pathChangeType = "I";
+ } else if (contentsStatus == SVNStatusType.STATUS_MISSING || contentsStatus == SVNStatusType.STATUS_INCOMPLETE) {
+ /*
+ * The file, directory or symbolic link item is under version
+ * control but is missing or somehow incomplete.
+ */
+ pathChangeType = "!";
+ } else if (contentsStatus == SVNStatusType.STATUS_OBSTRUCTED) {
+ /*
+ * The item is in the repository as one kind of object, but what's
+ * actually in the user's working copy is some other kind.
+ */
+ pathChangeType = "~";
+ } else if (contentsStatus == SVNStatusType.STATUS_REPLACED) {
+ /*
+ * The item was Replaced in the user's working copy; that is, the
+ * item was deleted, and a new item with the same name was added
+ * (within a single revision).
+ */
+ pathChangeType = "R";
+ } else if (contentsStatus == SVNStatusType.STATUS_NONE || contentsStatus == SVNStatusType.STATUS_NORMAL) {
+ /*
+ * The item was not modified (normal).
+ */
+ pathChangeType = " ";
+ }
+
+ /*
+ * If SVNStatusClient.doStatus(..) is invoked with remote = true the
+ * following code finds out whether the current item has been changed in
+ * the repository
+ */
+ String remoteChangeType = " ";
+
+ if (status.getRemotePropertiesStatus() != SVNStatusType.STATUS_NONE || status.getRemoteContentsStatus() != SVNStatusType.STATUS_NONE) {
+ /*
+ * the local item is out of date
+ */
+ remoteChangeType = "*";
+ }
+
+ /*
+ * Now getting the status of properties of an item. SVNStatusType also
+ * contains information on the properties state.
+ */
+ final SVNStatusType propertiesStatus = status.getPropertiesStatus();
+
+ /*
+ * Default - properties are normal (unmodified).
+ */
+ String propertiesChangeType = " ";
+ if (propertiesStatus == SVNStatusType.STATUS_MODIFIED) {
+ /*
+ * Properties were modified.
+ */
+ propertiesChangeType = "M";
+ } else if (propertiesStatus == SVNStatusType.STATUS_CONFLICTED) {
+ /*
+ * Properties are in conflict with the repository.
+ */
+ propertiesChangeType = "C";
+ }
+
+ /*
+ * Whether the item was locked in the .svn working area (for example,
+ * during a commit or maybe the previous operation was interrupted, in
+ * this case the lock needs to be cleaned up).
+ */
+ final boolean isLocked = status.isLocked();
+ /*
+ * Whether the item is switched to a different URL (branch).
+ */
+ final boolean isSwitched = status.isSwitched();
+ /*
+ * If the item is a file it may be locked.
+ */
+ final SVNLock localLock = status.getLocalLock();
+ /*
+ * If doStatus() was run with remote = true and the item is a file,
+ * checks whether a remote lock presents.
+ */
+ final SVNLock remoteLock = status.getRemoteLock();
+ String lockLabel = " ";
+
+ if (localLock != null) {
+ /*
+ * at first suppose the file is locKed
+ */
+ lockLabel = "K";
+ if (remoteLock != null) {
+ /*
+ * if the lock-token of the local lock differs from the lock-
+ * token of the remote lock - the lock was sTolen!
+ */
+ if (!remoteLock.getID().equals(localLock.getID())) {
+ lockLabel = "T";
+ }
+ } else {
+ if (this.myIsRemote) {
+ /*
+ * the local lock presents but there's no lock in the
+ * repository - the lock was Broken. This is true only if
+ * doStatus() was invoked with remote=true.
+ */
+ lockLabel = "B";
+ }
+ }
+ } else if (remoteLock != null) {
+ /*
+ * the file is not locally locked but locked in the repository - the
+ * lock token is in some Other working copy.
+ */
+ lockLabel = "O";
+ }
+
+ /*
+ * Obtains the working revision number of the item.
+ */
+ final long workingRevision = status.getRevision().getNumber();
+ /*
+ * Obtains the number of the revision when the item was last changed.
+ */
+ final long lastChangedRevision = status.getCommittedRevision().getNumber();
+ final String offset = " ";
+ final String[] offsets = new String[3];
+ offsets[0] = offset.substring(0, 6 - String.valueOf(workingRevision).length());
+ offsets[1] = offset.substring(0, 6 - String.valueOf(lastChangedRevision).length());
+ offsets[2] = offset.substring(0, offset.length() - (status.getAuthor() != null ? status.getAuthor().length() : 1));
+ /*
+ * status is shown in the manner of the native Subversion command line
+ * client's command "svn status"
+ */
+
+ org.appwork.loggingv3.LogV3.fine(pathChangeType + propertiesChangeType + (isLocked ? "L" : " ") + (isAddedWithHistory ? "+" : " ") + (isSwitched ? "S" : " ") + lockLabel + " " + remoteChangeType + " " + workingRevision + offsets[0] + (lastChangedRevision >= 0 ? String.valueOf(lastChangedRevision) : "?") + offsets[1] + (status.getAuthor() != null ? status.getAuthor() : "?") + offsets[2] + status.getFile().getPath());
+ }
+}
diff --git a/src/org/appwork/utils/svn/Subversion.java b/src/org/appwork/utils/svn/Subversion.java
new file mode 100644
index 0000000000..d22eed7ed5
--- /dev/null
+++ b/src/org/appwork/utils/svn/Subversion.java
@@ -0,0 +1,1077 @@
+/**
+ *
+ * ====================================================================================================================================================
+ * "AppWork Utilities" License
+ * The "AppWork Utilities" will be called [The Product] from now on.
+ * ====================================================================================================================================================
+ * Copyright (c) 2009-2015, AppWork GmbH
+ * Schwabacher Straße 117
+ * 90763 Fürth
+ * Germany
+ * === Preamble ===
+ * This license establishes the terms under which the [The Product] Source Code & Binary files may be used, copied, modified, distributed, and/or redistributed.
+ * The intent is that the AppWork GmbH is able to provide their utilities library for free to non-commercial projects whereas commercial usage is only permitted after obtaining a commercial license.
+ * These terms apply to all files that have the [The Product] License header (IN the file), a .license or .info (like mylib.jar.info) file that contains a reference to this license.
+ *
+ * === 3rd Party Licences ===
+ * Some parts of the [The Product] use or reference 3rd party libraries and classes. These parts may have different licensing conditions. Please check the *.license and *.info files of included libraries
+ * to ensure that they are compatible to your use-case. Further more, some *.java have their own license. In this case, they have their license terms in the java file header.
+ *
+ * === Definition: Commercial Usage ===
+ * If anybody or any organization is generating income (directly or indirectly) by using [The Product] or if there's any commercial interest or aspect in what you are doing, we consider this as a commercial usage.
+ * If your use-case is neither strictly private nor strictly educational, it is commercial. If you are unsure whether your use-case is commercial or not, consider it as commercial or contact us.
+ * === Dual Licensing ===
+ * === Commercial Usage ===
+ * If you want to use [The Product] in a commercial way (see definition above), you have to obtain a paid license from AppWork GmbH.
+ * Contact AppWork for further details:
+ * === Non-Commercial Usage ===
+ * If there is no commercial usage (see definition above), you may use [The Product] under the terms of the
+ * "GNU Affero General Public License" (http://www.gnu.org/licenses/agpl-3.0.en.html).
+ *
+ * If the AGPL does not fit your needs, please contact us. We'll find a solution.
+ * ====================================================================================================================================================
+ * ==================================================================================================================================================== */
+package org.appwork.utils.svn;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.appwork.exceptions.WTFException;
+import org.appwork.utils.Application;
+import org.appwork.utils.FileHandler;
+import org.appwork.utils.Files;
+import org.appwork.utils.IO;
+import org.tmatesoft.svn.core.SVNCancelException;
+import org.tmatesoft.svn.core.SVNCommitInfo;
+import org.tmatesoft.svn.core.SVNDepth;
+import org.tmatesoft.svn.core.SVNDirEntry;
+import org.tmatesoft.svn.core.SVNErrorCode;
+import org.tmatesoft.svn.core.SVNErrorMessage;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNLogEntry;
+import org.tmatesoft.svn.core.SVNNodeKind;
+import org.tmatesoft.svn.core.SVNProperty;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
+import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
+import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
+import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+import org.tmatesoft.svn.core.io.ISVNReporterBaton;
+import org.tmatesoft.svn.core.io.SVNRepository;
+import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
+import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
+import org.tmatesoft.svn.core.wc.ISVNCommitParameters;
+import org.tmatesoft.svn.core.wc.ISVNEventHandler;
+import org.tmatesoft.svn.core.wc.ISVNInfoHandler;
+import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
+import org.tmatesoft.svn.core.wc.SVNClientManager;
+import org.tmatesoft.svn.core.wc.SVNCommitClient;
+import org.tmatesoft.svn.core.wc.SVNCommitPacket;
+import org.tmatesoft.svn.core.wc.SVNEvent;
+import org.tmatesoft.svn.core.wc.SVNEventAction;
+import org.tmatesoft.svn.core.wc.SVNInfo;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNStatus;
+import org.tmatesoft.svn.core.wc.SVNStatusClient;
+import org.tmatesoft.svn.core.wc.SVNStatusType;
+import org.tmatesoft.svn.core.wc.SVNUpdateClient;
+import org.tmatesoft.svn.core.wc.SVNWCClient;
+import org.tmatesoft.svn.core.wc.SVNWCUtil;
+
+public class Subversion implements ISVNEventHandler {
+ /**
+ * checks wether logins are correct or not
+ *
+ * @param url
+ * @param user
+ * @param pass
+ * @return
+ */
+ public static boolean checkLogin(final String url, final String user, final String pass) {
+ return Boolean.TRUE.equals(new LocaleRunnable() {
+ @Override
+ protected Boolean run() throws RuntimeException {
+ Subversion subversion = null;
+ try {
+ subversion = new Subversion(url, user, pass);
+ return true;
+ } catch (final SVNException e) {
+ } finally {
+ try {
+ subversion.dispose();
+ } catch (final Throwable e) {
+ }
+ }
+ return false;
+ }
+ }.runEnglish());
+ }
+
+ private SVNRepository repository;
+ private SVNURL svnurl;
+ private ISVNAuthenticationManager authManager;
+ private SVNClientManager clientManager;
+ private SVNUpdateClient updateClient;
+ private SVNCommitClient commitClient;
+ private SVNWCClient wcClient;
+ private SVNStatusClient statusClient;
+
+ public Subversion() {
+ }
+
+ public Subversion(final String url) throws SVNException {
+ try {
+ setupType(url);
+ checkRoot();
+ } catch (final SVNException e) {
+ dispose();
+ throw e;
+ }
+ }
+
+ // public static void listEntries(final SVNRepository repository, final File root, final int i, final String path) throws SVNException,
+ // IOException {
+ // Locale bef = Locale.getDefault();
+ // Locale.setDefault(Locale.ENGLISH);
+ // try {
+ // final Collection entries = repository.getDir(path, i, null, (Collection) null);
+ // final File revroot = new File(root, i + "");
+ // revroot.mkdirs();
+ // final Iterator iterator = entries.iterator();
+ // while (iterator.hasNext()) {
+ // final SVNDirEntry entry = (SVNDirEntry) iterator.next();
+ // final File file = new File(revroot, (path.equals("") ? "" : path + "/") + entry.getName());
+ // if (entry.getKind() == SVNNodeKind.DIR) {
+ // file.mkdirs();
+ // } else {
+ // file.delete();
+ // IO.writeStringToFile(file, "author=" + entry.getAuthor() + "\r\nrevision=" + entry.getRevision() + "\r\ndate=" + entry.getDate());
+ // }
+ // if (entry.getKind() == SVNNodeKind.DIR) {
+ // listEntries(repository, root, i, (path.equals("")) ? entry.getName() : path + "/" + entry.getName());
+ // }
+ // }
+ // } finally {
+ // Locale.setDefault(bef);
+ // }
+ // }
+ public Subversion(final String url, final String user, final String pass) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Boolean run() throws SVNException {
+ try {
+ setupType(url);
+ authManager = SVNWCUtil.createDefaultAuthenticationManager(user, pass);
+ ((DefaultSVNAuthenticationManager) authManager).setAuthenticationForced(true);
+ repository.setAuthenticationManager(authManager);
+ checkRoot();
+ return null;
+ } catch (final SVNException e) {
+ dispose();
+ throw e;
+ }
+ }
+ }.runEnglish();
+ }
+
+ /**
+ * WCClient
+ */
+ @Override
+ public void checkCancelled() throws SVNCancelException {
+ }
+
+ public long checkout(final File file, final SVNRevision revision, final SVNDepth i) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ file.mkdirs();
+ final SVNUpdateClient updateClient = getUpdateClient();
+ updateClient.setIgnoreExternals(false);
+ SVNRevision rev = revision;
+ if (rev == null) {
+ rev = SVNRevision.HEAD;
+ }
+ return updateClient.doCheckout(svnurl, file, rev, rev, i, true);
+ }
+ }.runEnglish().longValue();
+ }
+
+ private void checkRoot() throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ final SVNNodeKind nodeKind = repository.checkPath("", -1);
+ if (nodeKind == SVNNodeKind.NONE) {
+ final SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "No entry at URL ''{0}''", svnurl);
+ throw new SVNException(err);
+ } else if (nodeKind == SVNNodeKind.FILE) {
+ final SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "Entry at URL ''{0}'' is a file while directory was expected", svnurl);
+ throw new SVNException(err);
+ }
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ /**
+ * Cleans up the file or doirectory
+ *
+ * @param dstPath
+ * @param deleteWCProperties
+ * @throws SVNException
+ */
+ public void cleanUp(final File dstPath, final boolean deleteWCProperties) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ getWCClient().doCleanup(dstPath, deleteWCProperties);
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ /**
+ * Commits the wholepath and KEEPS locks
+ *
+ * @param dstPath
+ * @param message
+ * @return
+ * @throws SVNException
+ */
+ public SVNCommitInfo commit(final File dstPath, final String message) throws SVNException {
+ return commit(message, dstPath);
+ }
+
+ public SVNCommitInfo commit(final String message, final SVNCommitPacket packet) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected SVNCommitInfo run() throws SVNException {
+ if (packet == SVNCommitPacket.EMPTY) {
+ return null;
+ }
+ return getCommitClient().doCommit(packet, true, false, message, null);
+ }
+ }.runEnglish();
+ }
+
+ public SVNCommitInfo commit(final String message, final File... dstPathes) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected SVNCommitInfo run() throws SVNException {
+ for (File f : dstPathes) {
+ getWCClient().doAdd(f, true, false, true, SVNDepth.INFINITY, false, false);
+ }
+ org.appwork.loggingv3.LogV3.finer("Create CommitPacket");
+ final SVNCommitPacket packet = getCommitClient().doCollectCommitItems(dstPathes, false, false, SVNDepth.INFINITY, null);
+ org.appwork.loggingv3.LogV3.finer("Transfer Package");
+ if (packet == SVNCommitPacket.EMPTY) {
+ return null;
+ }
+ return getCommitClient().doCommit(packet, true, false, message, null);
+ }
+ }.runEnglish();
+ }
+
+ public void dispose() {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws RuntimeException {
+ try {
+ repository.closeSession();
+ } catch (final Throwable e) {
+ }
+ getClientManager().dispose();
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ public long downloadFile(final String url, final File resource, final SVNRevision head) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ return getUpdateClient().doExport(SVNURL.parseURIDecoded(url), resource, head, head, null, true, null);
+ }
+ }.runEnglish().longValue();
+ }
+
+ public long export(final File file) throws SVNException, IOException {
+ try {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws Exception {
+ Files.deleteRecursiv(file);
+ file.mkdirs();
+ final ISVNEditor exportEditor = new ExportEditor(file);
+ final long rev = latestRevision();
+ final ISVNReporterBaton reporterBaton = new ExportReporterBaton(rev);
+ repository.update(rev, null, true, reporterBaton, exportEditor);
+ return rev;
+ }
+ }.runEnglish().longValue();
+ } catch (SVNException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new WTFException(e);
+ }
+ }
+
+ /**
+ * Returns all changesets between revision start and end
+ *
+ * @param start
+ * @param end
+ * @return
+ * @throws SVNException
+ */
+ @SuppressWarnings("unchecked")
+ public java.util.List getChangeset(final long start, final long end) throws SVNException {
+ return new LocaleRunnable, SVNException>() {
+ @Override
+ public List run() throws SVNException {
+ final Collection log = repository.log(new String[] { "" }, null, start, end, true, true);
+ final java.util.List list = new ArrayList();
+ list.addAll(log);
+ return list;
+ }
+ }.runEnglish();
+ }
+
+ public synchronized SVNClientManager getClientManager() {
+ if (clientManager == null) {
+ final DefaultSVNOptions options = new DefaultSVNOptions(null, true) {
+ private String[] ignorePatterns;
+ {
+ ignorePatterns = new String[] {};
+ }
+
+ @Override
+ public String[] getIgnorePatterns() {
+ return ignorePatterns;
+ }
+ };
+ options.setIgnorePatterns(null);
+ clientManager = SVNClientManager.newInstance(options, authManager);
+ }
+ return clientManager;
+ }
+
+ public SVNCommitClient getCommitClient() {
+ if (commitClient == null) {
+ commitClient = getClientManager().getCommitClient();
+ commitClient.setEventHandler(this);
+ commitClient.setCommitParameters(new ISVNCommitParameters() {
+ @Override
+ public boolean onDirectoryDeletion(final File directory) {
+ return false;
+ }
+
+ @Override
+ public boolean onFileDeletion(final File file) {
+ return false;
+ }
+
+ @Override
+ public Action onMissingDirectory(final File file) {
+ return ISVNCommitParameters.DELETE;
+ }
+
+ @Override
+ public Action onMissingFile(final File file) {
+ return ISVNCommitParameters.DELETE;
+ }
+ });
+ }
+ return commitClient;
+ }
+
+ /**
+ * Returns an ArrayLIst with Info for all files found in file.
+ *
+ * @param file
+ * @return
+ */
+ public java.util.List getInfo(final File file) {
+ return new LocaleRunnable, RuntimeException>() {
+ @Override
+ protected List run() throws RuntimeException {
+ final java.util.List ret = new ArrayList();
+ try {
+ getWCClient().doInfo(file, SVNRevision.UNDEFINED, SVNRevision.WORKING, SVNDepth.getInfinityOrEmptyDepth(true), null, new ISVNInfoHandler() {
+ @Override
+ public void handleInfo(final SVNInfo info) {
+ ret.add(info);
+ }
+ });
+ } catch (final SVNException e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+ }.runEnglish();
+ }
+
+ public SVNDirEntry getRemoteEntry(final String resource, final long revision) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected SVNDirEntry run() throws SVNException {
+ final SVNDirEntry de = getRepository().getDir(resource, revision, false, null);
+ return de;
+ }
+ }.runEnglish();
+ }
+
+ public long getRemoteRevision(final String resource) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ final SVNDirEntry de = getRepository().getDir(resource, -1, false, null);
+ return de.getRevision();
+ }
+ }.runEnglish().longValue();
+ }
+
+ /**
+ * Return repo for external actions
+ *
+ * @return
+ */
+ public SVNRepository getRepository() {
+ return repository;
+ }
+
+ public long getRevision(final File resource) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ final long[] ret = new long[] { -1 };
+ getWCClient().doInfo(resource, SVNRevision.UNDEFINED, SVNRevision.WORKING, SVNDepth.EMPTY, null, new ISVNInfoHandler() {
+ @Override
+ public void handleInfo(final SVNInfo info) {
+ final long rev = info.getCommittedRevision().getNumber();
+ if (rev > ret[0]) {
+ ret[0] = rev;
+ }
+ }
+ });
+ return ret[0];
+ }
+ }.runEnglish().longValue();
+ }
+
+ public long getRevisionNoException(final File resource) throws SVNException {
+ try {
+ return getRevision(resource);
+ } catch (final SVNException e) {
+ org.appwork.loggingv3.LogV3.log(e);
+ }
+ return -1;
+ }
+
+ public SVNStatusClient getStatusClient() {
+ if (statusClient == null) {
+ statusClient = getClientManager().getStatusClient();
+ statusClient.setEventHandler(this);
+ }
+ return statusClient;
+ }
+
+ public SVNUpdateClient getUpdateClient() {
+ if (updateClient == null) {
+ updateClient = getClientManager().getUpdateClient();
+ updateClient.setEventHandler(this);
+ }
+ return updateClient;
+ }
+
+ public SVNWCClient getWCClient() {
+ if (wcClient == null) {
+ wcClient = getClientManager().getWCClient();
+ wcClient.setEventHandler(this);
+ }
+ return wcClient;
+ }
+
+ /**
+ * WCClientHanlder
+ *
+ * @param event
+ * @param progress
+ * @throws SVNException
+ */
+ @Override
+ public void handleEvent(final SVNEvent event, final double progress) throws SVNException {
+ /* WCCLient */
+ final String nullString = " ";
+ final SVNEventAction action = event.getAction();
+ String pathChangeType = nullString;
+ if (action == SVNEventAction.ADD) {
+ /*
+ * The item is scheduled for addition.
+ */
+ org.appwork.loggingv3.LogV3.fine("A " + event.getFile());
+ return;
+ } else if (action == SVNEventAction.COPY) {
+ /*
+ * The item is scheduled for addition with history (copied, in other words).
+ */
+ org.appwork.loggingv3.LogV3.fine("A + " + event.getFile());
+ return;
+ } else if (action == SVNEventAction.DELETE) {
+ /*
+ * The item is scheduled for deletion.
+ */
+ org.appwork.loggingv3.LogV3.fine("D " + event.getFile());
+ return;
+ } else if (action == SVNEventAction.LOCKED) {
+ /*
+ * The item is locked.
+ */
+ org.appwork.loggingv3.LogV3.fine("L " + event.getFile());
+ return;
+ } else if (action == SVNEventAction.LOCK_FAILED) {
+ /*
+ * Locking operation failed.
+ */
+ org.appwork.loggingv3.LogV3.fine("failed to lock " + event.getFile());
+ return;
+ }
+ /* Updatehandler */
+ if (action == SVNEventAction.UPDATE_ADD) {
+ /*
+ * the item was added
+ */
+ pathChangeType = "A";
+ } else if (action == SVNEventAction.UPDATE_DELETE) {
+ /*
+ * the item was deleted
+ */
+ pathChangeType = "D";
+ } else if (action == SVNEventAction.UPDATE_UPDATE) {
+ /*
+ * Find out in details what state the item is (after having been updated).
+ *
+ * Gets the status of file/directory item contents. It is SVNStatusType who contains information on the state of an item.
+ */
+ final SVNStatusType contentsStatus = event.getContentsStatus();
+ if (contentsStatus == SVNStatusType.CHANGED) {
+ /*
+ * the item was modified in the repository (got the changes from the repository
+ */
+ pathChangeType = "U";
+ } else if (contentsStatus == SVNStatusType.CONFLICTED) {
+ /*
+ * The file item is in a state of Conflict. That is, changes received from the repository during an update, overlap with
+ * local changes the user has in his working copy.
+ */
+ pathChangeType = "C";
+ } else if (contentsStatus == SVNStatusType.MERGED) {
+ /*
+ * The file item was merGed (those changes that came from the repository did not overlap local changes and were merged into
+ * the file).
+ */
+ pathChangeType = "G";
+ }
+ } else if (action == SVNEventAction.UPDATE_EXTERNAL) {
+ /*
+ * for externals definitions
+ */
+ org.appwork.loggingv3.LogV3.fine("Fetching external item into '" + event.getFile().getAbsolutePath() + "'");
+ org.appwork.loggingv3.LogV3.fine("External at revision " + event.getRevision());
+ return;
+ } else if (action == SVNEventAction.UPDATE_COMPLETED) {
+ /*
+ * Working copy update is completed. Prints out the revision.
+ */
+ org.appwork.loggingv3.LogV3.fine("At revision " + event.getRevision());
+ return;
+ }
+ /*
+ * Status of properties of an item. SVNStatusType also contains information on the properties state.
+ */
+ final SVNStatusType propertiesStatus = event.getPropertiesStatus();
+ String propertiesChangeType = nullString;
+ if (propertiesStatus == SVNStatusType.CHANGED) {
+ /*
+ * Properties were updated.
+ */
+ propertiesChangeType = "U";
+ } else if (propertiesStatus == SVNStatusType.CONFLICTED) {
+ /*
+ * Properties are in conflict with the repository.
+ */
+ propertiesChangeType = "C";
+ } else if (propertiesStatus == SVNStatusType.MERGED) {
+ /*
+ * Properties that came from the repository were merged with the local ones.
+ */
+ propertiesChangeType = "G";
+ }
+ /*
+ * Gets the status of the lock.
+ */
+ String lockLabel = nullString;
+ final SVNStatusType lockType = event.getLockStatus();
+ if (lockType == SVNStatusType.LOCK_UNLOCKED) {
+ /*
+ * The lock is broken by someone.
+ */
+ lockLabel = "B";
+ }
+ if (pathChangeType != nullString || propertiesChangeType != nullString || lockLabel != nullString) {
+ org.appwork.loggingv3.LogV3.fine(pathChangeType + propertiesChangeType + lockLabel + " " + event.getFile());
+ }
+ /*
+ * Comitghandler
+ */
+ if (action == SVNEventAction.COMMIT_MODIFIED) {
+ org.appwork.loggingv3.LogV3.fine("Sending " + event.getFile());
+ } else if (action == SVNEventAction.COMMIT_DELETED) {
+ org.appwork.loggingv3.LogV3.fine("Deleting " + event.getFile());
+ } else if (action == SVNEventAction.COMMIT_REPLACED) {
+ org.appwork.loggingv3.LogV3.fine("Replacing " + event.getFile());
+ } else if (action == SVNEventAction.COMMIT_DELTA_SENT) {
+ org.appwork.loggingv3.LogV3.fine("Transmitting file data....");
+ } else if (action == SVNEventAction.COMMIT_ADDED) {
+ /*
+ * Gets the MIME-type of the item.
+ */
+ final String mimeType = event.getMimeType();
+ if (SVNProperty.isBinaryMimeType(mimeType)) {
+ /*
+ * If the item is a binary file
+ */
+ org.appwork.loggingv3.LogV3.fine("Adding (bin) " + event.getFile());
+ } else {
+ org.appwork.loggingv3.LogV3.fine("Adding " + event.getFile());
+ }
+ }
+ }
+
+ public long latestRevision() throws SVNException {
+ return repository.getLatestRevision();
+ }
+
+ /**
+ * @param filePathFilter
+ * @return
+ * @throws SVNException
+ * @throws InterruptedException
+ */
+ public List listFiles(final FilePathFilter filePathFilter, final String path) throws SVNException, InterruptedException {
+ final java.util.List ret = new ArrayList();
+ final Collection entries = new LocaleRunnable() {
+ @Override
+ protected Collection run() throws SVNException {
+ return repository.getDir(path, -1, null, (Collection) null);
+ }
+ }.runEnglish();
+ final Iterator iterator = entries.iterator();
+ while (iterator.hasNext()) {
+ final SVNDirEntry entry = (SVNDirEntry) iterator.next();
+ if (Thread.currentThread().isInterrupted()) {
+ throw new InterruptedException();
+ }
+ if (filePathFilter.accept(entry)) {
+ entry.setRelativePath((path.equals("") ? "" : path + "/") + entry.getName());
+ ret.add(entry);
+ System.out.println("/" + (path.equals("") ? "" : path + "/") + entry.getName() + " ( author: '" + entry.getAuthor() + "'; revision: " + entry.getRevision() + "; date: " + entry.getDate() + ")");
+ }
+ ;
+ if (entry.getKind() == SVNNodeKind.DIR) {
+ ret.addAll(listFiles(filePathFilter, path.equals("") ? entry.getName() : path + "/" + entry.getName()));
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Locks a file or directory as long as it it not locked by someone else
+ *
+ * @param dstPath
+ * @param message
+ * @throws SVNException
+ */
+ public void lock(final File dstPath, final String message) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ getWCClient().doLock(new File[] { dstPath }, false, message);
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ public void resolveConflictedFile(final SVNInfo info, final File file, final ResolveHandler handler) throws Exception {
+ final String mine = "<<<<<<< .mine";
+ final String delim = "=======";
+ final String theirs = ">>>>>>> .r";
+ String txt = IO.readFileToString(file);
+ String pre, post;
+ while (true) {
+ int mineStart = txt.indexOf(mine);
+ if (mineStart < 0) {
+ break;
+ }
+ mineStart += mine.length();
+ final int delimStart = txt.indexOf(delim, mineStart);
+ final int theirsEnd = txt.indexOf(theirs, delimStart + delim.length());
+ int end = theirsEnd + theirs.length();
+ while (end < txt.length() && txt.charAt(end) != '\r' && txt.charAt(end) != '\n') {
+ end++;
+ }
+ pre = txt.substring(0, mineStart - mine.length());
+ post = txt.substring(end);
+ while (pre.endsWith("\r") || pre.endsWith("\n")) {
+ pre = pre.substring(0, pre.length() - 1);
+ }
+ while (post.startsWith("\r") || post.startsWith("\n")) {
+ post = post.substring(1);
+ }
+ pre += "\r\n";
+ post = "\r\n" + post;
+ if (pre.trim().length() == 0) {
+ pre = pre.trim();
+ }
+ if (post.trim().length() == 0) {
+ post = post.trim();
+ }
+ final String ftxt = txt;
+ final int fmineStart = mineStart;
+ final String solve = new LocaleRunnable() {
+ @Override
+ protected String run() throws SVNException {
+ return handler.resolveConflict(info, file, ftxt, fmineStart, delimStart, delimStart + delim.length(), theirsEnd);
+ }
+ }.runEnglish();
+ if (solve == null) {
+ throw new Exception("Could not resolve");
+ }
+ txt = pre + solve.trim() + post;
+ }
+ file.delete();
+ IO.writeStringToFile(file, txt);
+ }
+
+ public void resolveConflicts(final File file, final ResolveHandler handler) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ getWCClient().doInfo(file, SVNRevision.UNDEFINED, SVNRevision.WORKING, SVNDepth.getInfinityOrEmptyDepth(true), null, new ISVNInfoHandler() {
+ @Override
+ public void handleInfo(final SVNInfo info) {
+ final File file = info.getConflictWrkFile();
+ if (file != null) {
+ try {
+ Subversion.this.resolveConflictedFile(info, info.getFile(), handler);
+ Subversion.this.getWCClient().doResolve(info.getFile(), SVNDepth.INFINITY, null);
+ org.appwork.loggingv3.LogV3.fine(file + " resolved");
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ public void revert(final File dstPath) throws SVNException {
+ revert(dstPath, false);
+ }
+
+ /**
+ * Reverts the file or directory
+ *
+ * @param dstPath
+ * @throws SVNException
+ */
+ public void revert(final File dstPath, final boolean deleteUnversionedFiles) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ try {
+ if (deleteUnversionedFiles) {
+ getStatusClient().doStatus(dstPath, SVNRevision.HEAD, SVNDepth.INFINITY, false, true, false, false, new ISVNStatusHandler() {
+ @Override
+ public void handleStatus(SVNStatus status) throws SVNException {
+ SVNStatusType statusType = status.getContentsStatus();
+ if (statusType == SVNStatusType.STATUS_NONE) {
+ try {
+ Files.deleteRecursiv(status.getFile(), true);
+ } catch (IOException e) {
+ throw new WTFException(e);
+ }
+ }
+ }
+ }, null);
+ }
+ getWCClient().doRevert(new File[] { dstPath }, SVNDepth.INFINITY, null);
+ } catch (final RuntimeException e) {
+ cleanUp(dstPath, false);
+ throw e;
+ } catch (final SVNException e) {
+ cleanUp(dstPath, false);
+ throw e;
+ }
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ private void setupType(final String url) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ svnurl = SVNURL.parseURIDecoded(url);
+ if (url.startsWith("http")) {
+ DAVRepositoryFactory.setup();
+ repository = SVNRepositoryFactory.create(svnurl);
+ } else if (url.startsWith("svn")) {
+ SVNRepositoryFactoryImpl.setup();
+ repository = SVNRepositoryFactory.create(svnurl);
+ } else {
+ FSRepositoryFactory.setup();
+ repository = SVNRepositoryFactory.create(svnurl);
+ }
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ public void showInfo(final File wcPath, final SVNRevision revision, final boolean isRecursive) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ if (revision == null) {
+ getWCClient().doInfo(wcPath, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNDepth.getInfinityOrEmptyDepth(isRecursive), null, new InfoEventHandler());
+ } else {
+ getWCClient().doInfo(wcPath, SVNRevision.UNDEFINED, revision, SVNDepth.getInfinityOrEmptyDepth(isRecursive), null, new InfoEventHandler());
+ }
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ public void showStatus(final File wcPath, final boolean isRecursive, final boolean isRemote, final boolean isReportAll, final boolean isIncludeIgnored, final boolean isCollectParentExternals) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ getClientManager().getStatusClient().doStatus(wcPath, SVNRevision.HEAD, SVNDepth.fromRecurse(isRecursive), isRemote, isReportAll, isIncludeIgnored, isCollectParentExternals, new StatusEventHandler(isRemote), null);
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ /**
+ * Unlocks this file only if it is locked by you
+ *
+ * @param dstPath
+ * @param message
+ * @throws SVNException
+ */
+ public void unlock(final File dstPath) throws SVNException {
+ new LocaleRunnable() {
+ @Override
+ protected Void run() throws SVNException {
+ getWCClient().doUnlock(new File[] { dstPath }, false);
+ return null;
+ }
+ }.runEnglish();
+ }
+
+ /**
+ * Updates the repo to file. if there is no repo at file, a checkout is performed
+ *
+ * @param file
+ * @param revision
+ * @throws SVNException
+ * @return revision
+ */
+ public long update(final File file, final SVNRevision revision) throws SVNException {
+ return this.update(file, revision, SVNDepth.INFINITY);
+ }
+
+ public long update(final File file, final SVNRevision revision, final SVNDepth i) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ SVNDepth fi = i;
+ if (fi == null) {
+ fi = SVNDepth.INFINITY;
+ }
+ // JDIO.removeDirectoryOrFile(file);
+ file.mkdirs();
+ final SVNUpdateClient updateClient = getUpdateClient();
+ updateClient.setIgnoreExternals(false);
+ SVNRevision frevision = revision;
+ if (frevision == null) {
+ frevision = SVNRevision.HEAD;
+ }
+ try {
+ // getWCClient().doAdd(path, force, mkdir, climbUnversionedParents,
+ // depth, includeIgnored, makeParents);
+ // long ret = updateClient.doCheckout(svnurl, file, frevision,
+ // frevision, i, true);
+ org.appwork.loggingv3.LogV3.info("SVN Update at " + file + " to Revision " + frevision + " depths:" + fi + " " + svnurl);
+ long ret = updateClient.doUpdate(file, frevision, fi, false, true);
+ if (ret < 0) {
+ // no working copy?
+ ret = updateClient.doCheckout(svnurl, file, frevision, frevision, fi, true);
+ }
+ return ret;
+ } catch (final Exception e) {
+ org.appwork.loggingv3.LogV3.info(e.getMessage());
+ org.appwork.loggingv3.LogV3.info("SVN Checkout at " + file + " " + svnurl);
+ return updateClient.doCheckout(svnurl, file, frevision, frevision, fi, true);
+ } finally {
+ org.appwork.loggingv3.LogV3.info("SVN Update finished");
+ }
+ }
+ }.runEnglish().longValue();
+ }
+
+ /**
+ * @param string
+ * @param string2
+ * @param bs
+ * @throws IOException
+ * @throws SVNException
+ */
+ public void write(final String path, final String commitmessage, final byte[] content) throws SVNException, IOException {
+ this.write(path, commitmessage, new ByteArrayInputStream(content));
+ }
+
+ public SVNCommitInfo write(final String path, final String commitmessage, final ByteArrayInputStream is) throws SVNException, IOException {
+ try {
+ return new LocaleRunnable() {
+ @Override
+ protected SVNCommitInfo run() throws Exception {
+ final File file = new File(Application.getTempResource("svnwrite_" + System.currentTimeMillis()), path);
+ downloadFile(svnurl + (svnurl.toString().endsWith("/") ? "" : "/") + path, file, SVNRevision.HEAD);
+ final SVNDeltaGenerator generator = new SVNDeltaGenerator();
+ final ISVNEditor commitEditor = getRepository().getCommitEditor(commitmessage, null);
+ try {
+ commitEditor.openRoot(-1);
+ commitEditor.openFile(path, -1);
+ commitEditor.applyTextDelta(path, null);
+ final String checksum = generator.sendDelta(path, is, commitEditor, true);
+ commitEditor.closeFile(path, checksum);
+ commitEditor.closeDir();
+ final SVNCommitInfo info = commitEditor.closeEdit();
+ return info;
+ } finally {
+ if (commitEditor != null) {
+ commitEditor.abortEdit();
+ }
+ Files.deleteRecursiv(file.getParentFile());
+ }
+ }
+ }.runEnglish();
+ } catch (SVNException e) {
+ throw e;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new WTFException(e);
+ }
+ }
+
+ /**
+ * @param date
+ * @throws SVNException
+ */
+ public long getRevisionByDate(final Date date) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected Long run() throws SVNException {
+ return repository.getDatedRevision(date);
+ }
+ }.runEnglish().longValue();
+ }
+
+ /**
+ * @param s
+ * @return
+ * @throws SVNException
+ */
+ public SVNCommitPacket getCommitDelta(final File... dstPathes) throws SVNException {
+ return new LocaleRunnable() {
+ @Override
+ protected SVNCommitPacket run() throws SVNException {
+ try {
+ // for (File f : dstPathes) {
+ // unlock(f);
+ // }
+ for (final File folder : dstPathes) {
+ cleanUp(folder, false);
+ Files.walkThroughStructure(new FileHandler() {
+ @Override
+ public void intro(File f) throws SVNException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public boolean onFile(File f, int depths) throws SVNException {
+ String rel = Files.getRelativePath(folder, f);
+ if ("bin".equals(rel)) {
+ return false;
+ }
+ if ("dist".equals(rel)) {
+ return false;
+ }
+ if ("update".equals(rel)) {
+ return false;
+ }
+ if (f.getName().equals(".svn")) {
+ return false;
+ }
+ try {
+ System.out.println(f);
+ getWCClient().doAdd(f, false, false, true, SVNDepth.IMMEDIATES, false, false);
+ } catch (SVNException e) {
+ if (e.getMessage().contains("E150002")) {
+ // already version controlled
+ return true;
+ }
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void outro(File f) throws RuntimeException {
+ // TODO Auto-generated method stub
+ }
+ }, folder);
+ }
+ // getWCClient().doSetProperty(new File(path), "sv:ignore", "bin", true, false, null);
+ org.appwork.loggingv3.LogV3.finer("calculate Changes");
+ final SVNCommitPacket packet = getCommitClient().doCollectCommitItems(dstPathes, true, false, SVNDepth.INFINITY, null);
+ if (packet == SVNCommitPacket.EMPTY) {
+ return null;
+ }
+ return packet;
+ } finally {
+ for (File f : dstPathes) {
+ cleanUp(f, false);
+ }
+ }
+ }
+ }.runEnglish();
+ }
+}
diff --git a/src/org/jdownloader/startup/ParameterHandler.java b/src/org/jdownloader/startup/ParameterHandler.java
index 6a01db52f1..8f1f745b87 100644
--- a/src/org/jdownloader/startup/ParameterHandler.java
+++ b/src/org/jdownloader/startup/ParameterHandler.java
@@ -6,8 +6,6 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import jd.SecondLevelLaunch;
-
import org.appwork.app.launcher.parameterparser.CommandSwitch;
import org.appwork.app.launcher.parameterparser.ParameterParser;
import org.appwork.utils.Application;
@@ -34,6 +32,8 @@ import org.jdownloader.startup.commands.SetConfigCommand;
import org.jdownloader.startup.commands.ThreadDump;
import org.jdownloader.updatev2.RestartController;
+import jd.SecondLevelLaunch;
+
public class ParameterHandler implements InstanceMessageListener {
private final HashMap commandMap;
private final LogSource logger;
@@ -93,7 +93,7 @@ public class ParameterHandler implements InstanceMessageListener {
@Override
@Deprecated
- /**kept to avoid JDownloader.jar <-> Core.jar update compatibility issues. can be removed in future**/
+ /** kept to avoid JDownloader.jar <-> Core.jar update compatibility issues. can be removed in future **/
public void parseMessage(String[] args) {
onIncommingMessage(null, args);
}
diff --git a/themes/themes/standard/org/jdownloader/images/nonpinned.png b/themes/themes/standard/org/jdownloader/images/nonpinned.png
new file mode 100644
index 0000000000..77a2b47370
Binary files /dev/null and b/themes/themes/standard/org/jdownloader/images/nonpinned.png differ
diff --git a/themes/themes/standard/org/jdownloader/images/pinned.png b/themes/themes/standard/org/jdownloader/images/pinned.png
new file mode 100644
index 0000000000..fa8808b7b4
Binary files /dev/null and b/themes/themes/standard/org/jdownloader/images/pinned.png differ
diff --git a/themes/themes/standard/org/jdownloader/images/pinned.svg b/themes/themes/standard/org/jdownloader/images/pinned.svg
new file mode 100644
index 0000000000..45596dccbf
--- /dev/null
+++ b/themes/themes/standard/org/jdownloader/images/pinned.svg
@@ -0,0 +1 @@
+
\ No newline at end of file