From 98cb11c643f2f4de160061e64cc93df120130f8d Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 12 Mar 2019 16:46:03 +0100 Subject: [PATCH] Introduce Argeo Sync --- org.argeo.sync/.classpath | 8 ++ org.argeo.sync/.gitignore | 2 + org.argeo.sync/.project | 28 +++++ .../.settings/org.eclipse.jdt.core.prefs | 101 ++++++++++++++++++ org.argeo.sync/META-INF/.gitignore | 1 + org.argeo.sync/bnd.bnd | 1 + org.argeo.sync/build.properties | 8 ++ org.argeo.sync/lib/.gitignore | 1 + org.argeo.sync/pom.xml | 23 ++++ .../src/org/argeo/sync/SyncException.java | 18 ++++ .../src/org/argeo/sync/cli/Sync.java | 35 ++++++ .../src/org/argeo/sync/fs/PathSync.java | 54 ++++------ .../src/org/argeo/sync/fs}/SshSync.java | 40 ++++--- .../org/argeo/sync/fs}/SyncFileVisitor.java | 2 +- pom.xml | 1 + 15 files changed, 273 insertions(+), 50 deletions(-) create mode 100644 org.argeo.sync/.classpath create mode 100644 org.argeo.sync/.gitignore create mode 100644 org.argeo.sync/.project create mode 100644 org.argeo.sync/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.argeo.sync/META-INF/.gitignore create mode 100644 org.argeo.sync/bnd.bnd create mode 100644 org.argeo.sync/build.properties create mode 100644 org.argeo.sync/lib/.gitignore create mode 100644 org.argeo.sync/pom.xml create mode 100644 org.argeo.sync/src/org/argeo/sync/SyncException.java create mode 100644 org.argeo.sync/src/org/argeo/sync/cli/Sync.java rename org.argeo.cms/src/org/argeo/cms/cmd/Sync.java => org.argeo.sync/src/org/argeo/sync/fs/PathSync.java (52%) rename {org.argeo.maintenance/src/org/argeo/maintenance/backup => org.argeo.sync/src/org/argeo/sync/fs}/SshSync.java (82%) rename {org.argeo.cms/src/org/argeo/cms/cmd => org.argeo.sync/src/org/argeo/sync/fs}/SyncFileVisitor.java (98%) 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.cms/src/org/argeo/cms/cmd/Sync.java b/org.argeo.sync/src/org/argeo/sync/fs/PathSync.java similarity index 52% rename from org.argeo.cms/src/org/argeo/cms/cmd/Sync.java rename to org.argeo.sync/src/org/argeo/sync/fs/PathSync.java index 515ef6c55..1dc30db65 100644 --- a/org.argeo.cms/src/org/argeo/cms/cmd/Sync.java +++ b/org.argeo.sync/src/org/argeo/sync/fs/PathSync.java @@ -1,54 +1,38 @@ -package org.argeo.cms.cmd; +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 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.sync.SyncException; import org.argeo.util.LangUtils; -public class Sync { - private final static Log log = LogFactory.getLog(Sync.class); +public class PathSync implements Runnable { + private final static Log log = LogFactory.getLog(PathSync.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? - } - } + private final URI sourceUri, targetUri; + + public PathSync(URI sourceUri, URI targetUri) { + this.sourceUri = sourceUri; + this.targetUri = targetUri; + } + @Override + public void run() { 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); + 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); @@ -61,12 +45,12 @@ public class Sync { private static FileSystemProvider createFsProvider(URI uri) { FileSystemProvider fsProvider; - if (uri.getScheme().equals("file")) + if (uri.getScheme() == null || 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); + throw new SyncException("URI scheme not supported for " + uri); return fsProvider; } diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java b/org.argeo.sync/src/org/argeo/sync/fs/SshSync.java similarity index 82% rename from org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java rename to org.argeo.sync/src/org/argeo/sync/fs/SshSync.java index 618e227ee..e89ba85dc 100644 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/SshSync.java +++ b/org.argeo.sync/src/org/argeo/sync/fs/SshSync.java @@ -1,15 +1,14 @@ -package org.argeo.maintenance.backup; +package org.argeo.sync.fs; 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.security.PublicKey; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.Set; @@ -17,6 +16,8 @@ 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; @@ -29,18 +30,28 @@ 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(); + 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); @@ -50,7 +61,7 @@ public class SshSync { try { - session.addPasswordIdentity(new String(password)); +// session.addPasswordIdentity(new String(password)); session.auth().verify(1000l); SftpFileSystemProvider fsProvider = new SftpFileSystemProvider(client); @@ -68,7 +79,7 @@ public class SshSync { e.printStackTrace(); } } - + static void test(Path testBase) { try { Path testPath = testBase.resolve("ssh-test.txt"); @@ -93,7 +104,8 @@ public class SshSync { 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)) { + try (OutputStream out = Files.newOutputStream(copiedFile); + InputStream in = Files.newInputStream(testPath)) { IOUtils.copy(in, out); } log.debug("Copied " + testPath + " to " + copiedFile); @@ -120,7 +132,7 @@ public class SshSync { } } - + static void openShell(ClientSession session) { try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) { channel.setIn(new NoCloseInputStream(System.in)); diff --git a/org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java b/org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java similarity index 98% rename from org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java rename to org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java index 6ec75f407..de8032004 100644 --- a/org.argeo.cms/src/org/argeo/cms/cmd/SyncFileVisitor.java +++ b/org.argeo.sync/src/org/argeo/sync/fs/SyncFileVisitor.java @@ -1,4 +1,4 @@ -package org.argeo.cms.cmd; +package org.argeo.sync.fs; import java.io.IOException; import java.nio.file.FileVisitResult; 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 -- 2.30.2