From: Mathieu Baudier Date: Tue, 12 Mar 2019 15:46:03 +0000 (+0100) Subject: Introduce Argeo Sync X-Git-Tag: argeo-commons-2.1.77~28 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=98cb11c643f2f4de160061e64cc93df120130f8d Introduce Argeo Sync --- diff --git a/org.argeo.cms/src/org/argeo/cms/cmd/Sync.java b/org.argeo.cms/src/org/argeo/cms/cmd/Sync.java deleted file mode 100644 index 515ef6c55..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cmd/Sync.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.argeo.cms.cmd; - -import java.net.URI; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.spi.FileSystemProvider; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsException; -import org.argeo.jackrabbit.fs.DavexFsProvider; -import org.argeo.util.LangUtils; - -public class Sync { - private final static Log log = LogFactory.getLog(Sync.class); - - public static void main(String args[]) { - Map arguments = new HashMap<>(); - boolean skipNext = false; - String currValue = null; - for (int i = 0; i < args.length; i++) { - if (skipNext) { - skipNext = false; - currValue = null; - continue; - } - String arg = args[i]; - if (arg.startsWith("-")) { - if (i + 1 < args.length) { - if (!args[i + 1].startsWith("-")) { - currValue = args[i + 1]; - skipNext = true; - } - } - arguments.put(arg, currValue); - } else { - // TODO add multiple? - } - } - - try { - URI sourceUri = new URI(arguments.get("-i")); - URI targetUri = new URI(arguments.get("-o")); - FileSystemProvider sourceFsProvider = createFsProvider(sourceUri); - FileSystemProvider targetFsProvider = createFsProvider(targetUri); - Path sourceBasePath = sourceFsProvider.getPath(sourceUri); - Path targetBasePath = targetFsProvider.getPath(targetUri); - SyncFileVisitor syncFileVisitor = new SyncFileVisitor(sourceBasePath, targetBasePath); - ZonedDateTime begin = ZonedDateTime.now(); - Files.walkFileTree(sourceBasePath, syncFileVisitor); - if (log.isDebugEnabled()) - log.debug("Sync from " + sourceBasePath + " to " + targetBasePath + " took " + LangUtils.since(begin)); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static FileSystemProvider createFsProvider(URI uri) { - FileSystemProvider fsProvider; - if (uri.getScheme().equals("file")) - fsProvider = FileSystems.getDefault().provider(); - else if (uri.getScheme().equals("davex")) - fsProvider = new DavexFsProvider(); - else - throw new CmsException("URI scheme not supported for " + uri); - return fsProvider; - } - - static enum Arg { - to, from; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java b/org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java deleted file mode 100644 index 6ec75f407..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.argeo.cms.cmd; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** Synchronises two directory structures. */ -public class SyncFileVisitor extends SimpleFileVisitor { - private final static Log log = LogFactory.getLog(SyncFileVisitor.class); - - private final Path sourceBasePath; - private final Path targetBasePath; - - public SyncFileVisitor(Path sourceBasePath, Path targetBasePath) { - this.sourceBasePath = sourceBasePath; - this.targetBasePath = targetBasePath; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path targetPath = toTargetPath(dir); - Files.createDirectories(targetPath); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Path targetPath = toTargetPath(file); - try { - Files.copy(file, targetPath); - if (log.isDebugEnabled()) - log.debug("Copied " + targetPath); - } catch (Exception e) { - log.error("Cannot copy " + file + " to " + targetPath, e); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - log.error("Cannot sync " + file, exc); - return FileVisitResult.CONTINUE; - } - - private Path toTargetPath(Path sourcePath) { - Path relativePath = sourceBasePath.relativize(sourcePath); - Path targetPath = targetBasePath.resolve(relativePath.toString()); - return targetPath; - } -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java deleted file mode 100644 index 618e227ee..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.argeo.maintenance.backup; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.sshd.client.SshClient; -import org.apache.sshd.client.channel.ClientChannel; -import org.apache.sshd.client.channel.ClientChannelEvent; -import org.apache.sshd.client.future.ConnectFuture; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.client.subsystem.sftp.SftpFileSystem; -import org.apache.sshd.client.subsystem.sftp.SftpFileSystemProvider; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.NoCloseOutputStream; - -public class SshSync { - private final static Log log = LogFactory.getLog(SshSync.class); - - public static void main(String[] args) { - - String login = System.getProperty("user.name"); - Scanner s = new Scanner(System.in); - String password = s.next(); - String host = "localhost"; - int port = 22; - - try (SshClient client = SshClient.setUpDefaultClient()) { - client.start(); - -// SimpleClient simpleClient= AbstractSimpleClientSessionCreator.wrap(client, null); -// simpleClient.sessionLogin(host, login, password); - - ConnectFuture connectFuture = client.connect(login, host, port); - connectFuture.await(); - ClientSession session = connectFuture.getSession(); - - try { - - session.addPasswordIdentity(new String(password)); - session.auth().verify(1000l); - - SftpFileSystemProvider fsProvider = new SftpFileSystemProvider(client); - - SftpFileSystem fs = fsProvider.newFileSystem(session); - Path testPath = fs.getPath("/home/" + login + "/tmp"); - Files.list(testPath).forEach(System.out::println); - test(testPath); - - } finally { - client.stop(); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - static void test(Path testBase) { - try { - Path testPath = testBase.resolve("ssh-test.txt"); - Files.createFile(testPath); - log.debug("Created file " + testPath); - Files.delete(testPath); - log.debug("Deleted " + testPath); - String txt = "TEST\nTEST2\n"; - byte[] arr = txt.getBytes(); - Files.write(testPath, arr); - log.debug("Wrote " + testPath); - byte[] read = Files.readAllBytes(testPath); - log.debug("Read " + testPath); - Path testDir = testBase.resolve("testDir"); - log.debug("Resolved " + testDir); - // Copy - Files.createDirectory(testDir); - log.debug("Created directory " + testDir); - Path subsubdir = Files.createDirectories(testDir.resolve("subdir/subsubdir")); - log.debug("Created sub directories " + subsubdir); - Path copiedFile = testDir.resolve("copiedFile.txt"); - log.debug("Resolved " + copiedFile); - Path relativeCopiedFile = testDir.relativize(copiedFile); - log.debug("Relative copied file " + relativeCopiedFile); - try (OutputStream out = Files.newOutputStream(copiedFile); InputStream in = Files.newInputStream(testPath)) { - IOUtils.copy(in, out); - } - log.debug("Copied " + testPath + " to " + copiedFile); - Files.delete(testPath); - log.debug("Deleted " + testPath); - byte[] copiedRead = Files.readAllBytes(copiedFile); - log.debug("Read " + copiedFile); - // Browse directories - DirectoryStream files = Files.newDirectoryStream(testDir); - int fileCount = 0; - Path listedFile = null; - for (Path file : files) { - fileCount++; - if (!Files.isDirectory(file)) - listedFile = file; - } - log.debug("Listed " + testDir); - // Generic attributes - Map attrs = Files.readAttributes(copiedFile, "*"); - log.debug("Read attributes of " + copiedFile + ": " + attrs.keySet()); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - - static void openShell(ClientSession session) { - try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) { - channel.setIn(new NoCloseInputStream(System.in)); - channel.setOut(new NoCloseOutputStream(System.out)); - channel.setErr(new NoCloseOutputStream(System.err)); - channel.open(); - - Set events = new HashSet<>(); - events.add(ClientChannelEvent.CLOSED); - channel.waitFor(events, 0); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } finally { - session.close(false); - } - } -} diff --git a/org.argeo.sync/.classpath b/org.argeo.sync/.classpath new file mode 100644 index 000000000..a7acb8257 --- /dev/null +++ b/org.argeo.sync/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.argeo.sync/.gitignore b/org.argeo.sync/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.argeo.sync/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.sync/.project b/org.argeo.sync/.project new file mode 100644 index 000000000..38af86992 --- /dev/null +++ b/org.argeo.sync/.project @@ -0,0 +1,28 @@ + + + org.argeo.sync + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.sync/.settings/org.eclipse.jdt.core.prefs b/org.argeo.sync/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..7e2e11935 --- /dev/null +++ b/org.argeo.sync/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,101 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning diff --git a/org.argeo.sync/META-INF/.gitignore b/org.argeo.sync/META-INF/.gitignore new file mode 100644 index 000000000..4854a41b9 --- /dev/null +++ b/org.argeo.sync/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.sync/bnd.bnd b/org.argeo.sync/bnd.bnd new file mode 100644 index 000000000..3ae5c176e --- /dev/null +++ b/org.argeo.sync/bnd.bnd @@ -0,0 +1 @@ +Main-Class: org.argeo.sync.cli.Sync diff --git a/org.argeo.sync/build.properties b/org.argeo.sync/build.properties new file mode 100644 index 000000000..f3e2c2ccb --- /dev/null +++ b/org.argeo.sync/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . +additional.bundles = org.apache.sshd.common,\ + org.slf4j.log4j12,\ + org.slf4j.api,\ + org.apache.sshd.core diff --git a/org.argeo.sync/lib/.gitignore b/org.argeo.sync/lib/.gitignore new file mode 100644 index 000000000..2142dc129 --- /dev/null +++ b/org.argeo.sync/lib/.gitignore @@ -0,0 +1 @@ +/tomcat-jni-*.jar diff --git a/org.argeo.sync/pom.xml b/org.argeo.sync/pom.xml new file mode 100644 index 000000000..4e07d4334 --- /dev/null +++ b/org.argeo.sync/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + org.argeo.commons + argeo-commons + 2.1.77-SNAPSHOT + .. + + org.argeo.sync + Commons Sync Utility + + + org.argeo.commons + org.argeo.util + 2.1.77-SNAPSHOT + + + org.argeo.commons + org.argeo.jcr + 2.1.77-SNAPSHOT + + + \ No newline at end of file diff --git a/org.argeo.sync/src/org/argeo/sync/SyncException.java b/org.argeo.sync/src/org/argeo/sync/SyncException.java new file mode 100644 index 000000000..89bf869a2 --- /dev/null +++ b/org.argeo.sync/src/org/argeo/sync/SyncException.java @@ -0,0 +1,18 @@ +package org.argeo.sync; + +/** Commons exception for sync */ +public class SyncException extends RuntimeException { + private static final long serialVersionUID = -3371314343580218538L; + + public SyncException(String message) { + super(message); + } + + public SyncException(String message, Throwable cause) { + super(message, cause); + } + + public SyncException(Object source, Object target, Throwable cause) { + super("Cannot sync from " + source + " to " + target, cause); + } +} diff --git a/org.argeo.sync/src/org/argeo/sync/cli/Sync.java b/org.argeo.sync/src/org/argeo/sync/cli/Sync.java new file mode 100644 index 000000000..6bb098b19 --- /dev/null +++ b/org.argeo.sync/src/org/argeo/sync/cli/Sync.java @@ -0,0 +1,35 @@ +package org.argeo.sync.cli; + +import java.net.URI; +import java.util.List; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.argeo.sync.fs.PathSync; + +public class Sync { + + public static void main(String[] args) { + Options options = new Options(); + options.addOption("r", "recursive", false, "recurse into directories"); + options.addOption(Option.builder().longOpt("progress").hasArg(false).desc("").build()); + + CommandLineParser parser = new DefaultParser(); + try { + CommandLine line = parser.parse(options, args); + List remaining = line.getArgList(); + + URI sourceUri = new URI(remaining.get(0)); + URI targetUri = new URI(remaining.get(1)); + PathSync pathSync = new PathSync(sourceUri, targetUri); + pathSync.run(); + } catch (Exception exp) { + exp.printStackTrace(); + + } + } + +} diff --git a/org.argeo.sync/src/org/argeo/sync/fs/PathSync.java b/org.argeo.sync/src/org/argeo/sync/fs/PathSync.java new file mode 100644 index 000000000..1dc30db65 --- /dev/null +++ b/org.argeo.sync/src/org/argeo/sync/fs/PathSync.java @@ -0,0 +1,60 @@ +package org.argeo.sync.fs; + +import java.net.URI; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.spi.FileSystemProvider; +import java.time.ZonedDateTime; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jackrabbit.fs.DavexFsProvider; +import org.argeo.sync.SyncException; +import org.argeo.util.LangUtils; + +public class PathSync implements Runnable { + private final static Log log = LogFactory.getLog(PathSync.class); + + private final URI sourceUri, targetUri; + + public PathSync(URI sourceUri, URI targetUri) { + this.sourceUri = sourceUri; + this.targetUri = targetUri; + } + + @Override + public void run() { + try { + FileSystemProvider sourceFsProvider = createFsProvider(sourceUri); + FileSystemProvider targetFsProvider = createFsProvider(targetUri); + Path sourceBasePath = sourceUri.getScheme() != null ? sourceFsProvider.getPath(sourceUri) + : Paths.get(sourceUri.getPath()); + Path targetBasePath = targetUri.getScheme() != null ? targetFsProvider.getPath(targetUri) + : Paths.get(targetUri.getPath()); + SyncFileVisitor syncFileVisitor = new SyncFileVisitor(sourceBasePath, targetBasePath); + ZonedDateTime begin = ZonedDateTime.now(); + Files.walkFileTree(sourceBasePath, syncFileVisitor); + if (log.isDebugEnabled()) + log.debug("Sync from " + sourceBasePath + " to " + targetBasePath + " took " + LangUtils.since(begin)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static FileSystemProvider createFsProvider(URI uri) { + FileSystemProvider fsProvider; + if (uri.getScheme() == null || uri.getScheme().equals("file")) + fsProvider = FileSystems.getDefault().provider(); + else if (uri.getScheme().equals("davex")) + fsProvider = new DavexFsProvider(); + else + throw new SyncException("URI scheme not supported for " + uri); + return fsProvider; + } + + static enum Arg { + to, from; + } +} diff --git a/org.argeo.sync/src/org/argeo/sync/fs/SshSync.java b/org.argeo.sync/src/org/argeo/sync/fs/SshSync.java new file mode 100644 index 000000000..e89ba85dc --- /dev/null +++ b/org.argeo.sync/src/org/argeo/sync/fs/SshSync.java @@ -0,0 +1,153 @@ +package org.argeo.sync.fs; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.PublicKey; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.Set; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.sshd.agent.SshAgent; +import org.apache.sshd.agent.unix.UnixAgentFactory; +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ClientChannel; +import org.apache.sshd.client.channel.ClientChannelEvent; +import org.apache.sshd.client.future.ConnectFuture; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.subsystem.sftp.SftpFileSystem; +import org.apache.sshd.client.subsystem.sftp.SftpFileSystemProvider; +import org.apache.sshd.common.util.io.NoCloseInputStream; +import org.apache.sshd.common.util.io.NoCloseOutputStream; + +public class SshSync { + private final static Log log = LogFactory.getLog(SshSync.class); + + public static void main(String[] args) { + + + try (SshClient client = SshClient.setUpDefaultClient()) { + client.start(); + + UnixAgentFactory agentFactory = new UnixAgentFactory(); + client.setAgentFactory(agentFactory); +// SshAgent sshAgent = agentFactory.createClient(client); +// List> identities = sshAgent.getIdentities(); +// for (Map.Entry entry : identities) { +// System.out.println(entry.getValue() + " : " + entry.getKey()); +// } + + + String login = System.getProperty("user.name"); +// Scanner s = new Scanner(System.in); +// String password = s.next(); + String host = "localhost"; + int port = 22; + +// SimpleClient simpleClient= AbstractSimpleClientSessionCreator.wrap(client, null); +// simpleClient.sessionLogin(host, login, password); + + ConnectFuture connectFuture = client.connect(login, host, port); + connectFuture.await(); + ClientSession session = connectFuture.getSession(); + + try { + +// session.addPasswordIdentity(new String(password)); + session.auth().verify(1000l); + + SftpFileSystemProvider fsProvider = new SftpFileSystemProvider(client); + + SftpFileSystem fs = fsProvider.newFileSystem(session); + Path testPath = fs.getPath("/home/" + login + "/tmp"); + Files.list(testPath).forEach(System.out::println); + test(testPath); + + } finally { + client.stop(); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + static void test(Path testBase) { + try { + Path testPath = testBase.resolve("ssh-test.txt"); + Files.createFile(testPath); + log.debug("Created file " + testPath); + Files.delete(testPath); + log.debug("Deleted " + testPath); + String txt = "TEST\nTEST2\n"; + byte[] arr = txt.getBytes(); + Files.write(testPath, arr); + log.debug("Wrote " + testPath); + byte[] read = Files.readAllBytes(testPath); + log.debug("Read " + testPath); + Path testDir = testBase.resolve("testDir"); + log.debug("Resolved " + testDir); + // Copy + Files.createDirectory(testDir); + log.debug("Created directory " + testDir); + Path subsubdir = Files.createDirectories(testDir.resolve("subdir/subsubdir")); + log.debug("Created sub directories " + subsubdir); + Path copiedFile = testDir.resolve("copiedFile.txt"); + log.debug("Resolved " + copiedFile); + Path relativeCopiedFile = testDir.relativize(copiedFile); + log.debug("Relative copied file " + relativeCopiedFile); + try (OutputStream out = Files.newOutputStream(copiedFile); + InputStream in = Files.newInputStream(testPath)) { + IOUtils.copy(in, out); + } + log.debug("Copied " + testPath + " to " + copiedFile); + Files.delete(testPath); + log.debug("Deleted " + testPath); + byte[] copiedRead = Files.readAllBytes(copiedFile); + log.debug("Read " + copiedFile); + // Browse directories + DirectoryStream files = Files.newDirectoryStream(testDir); + int fileCount = 0; + Path listedFile = null; + for (Path file : files) { + fileCount++; + if (!Files.isDirectory(file)) + listedFile = file; + } + log.debug("Listed " + testDir); + // Generic attributes + Map attrs = Files.readAttributes(copiedFile, "*"); + log.debug("Read attributes of " + copiedFile + ": " + attrs.keySet()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + static void openShell(ClientSession session) { + try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) { + channel.setIn(new NoCloseInputStream(System.in)); + channel.setOut(new NoCloseOutputStream(System.out)); + channel.setErr(new NoCloseOutputStream(System.err)); + channel.open(); + + Set events = new HashSet<>(); + events.add(ClientChannelEvent.CLOSED); + channel.waitFor(events, 0); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + session.close(false); + } + } +} diff --git a/org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java b/org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java new file mode 100644 index 000000000..de8032004 --- /dev/null +++ b/org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java @@ -0,0 +1,56 @@ +package org.argeo.sync.fs; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** Synchronises two directory structures. */ +public class SyncFileVisitor extends SimpleFileVisitor { + private final static Log log = LogFactory.getLog(SyncFileVisitor.class); + + private final Path sourceBasePath; + private final Path targetBasePath; + + public SyncFileVisitor(Path sourceBasePath, Path targetBasePath) { + this.sourceBasePath = sourceBasePath; + this.targetBasePath = targetBasePath; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + Path targetPath = toTargetPath(dir); + Files.createDirectories(targetPath); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path targetPath = toTargetPath(file); + try { + Files.copy(file, targetPath); + if (log.isDebugEnabled()) + log.debug("Copied " + targetPath); + } catch (Exception e) { + log.error("Cannot copy " + file + " to " + targetPath, e); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + log.error("Cannot sync " + file, exc); + return FileVisitResult.CONTINUE; + } + + private Path toTargetPath(Path sourcePath) { + Path relativePath = sourceBasePath.relativize(sourcePath); + Path targetPath = targetBasePath.resolve(relativePath.toString()); + return targetPath; + } +} diff --git a/pom.xml b/pom.xml index fb14ca6d4..4efd8d8fc 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ org.argeo.util org.argeo.enterprise org.argeo.jcr + org.argeo.sync org.argeo.osgi.boot org.argeo.eclipse.ui