import org.argeo.cms.cli.DescribedCommand;
import org.argeo.jackrabbit.client.ClientDavexRepositoryFactory;
import org.argeo.jcr.JcrUtils;
-import org.argeo.sync.SyncResult;
+import org.argeo.util.SyncResult;
public class JcrSync implements DescribedCommand<SyncResult<Node>> {
public final static String DEFAULT_LOCALFS_CONFIG = "repository-localfs.xml";
import java.nio.file.Files;
import java.nio.file.Path;
+import org.argeo.util.FsUtils;
+
/** {@link FsUtils} tests. */
public class FsUtilsTest {
final static String FILE00 = "file00";
+++ /dev/null
-package org.argeo.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.StandardCopyOption;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileTime;
-
-import org.argeo.sync.SyncResult;
-
-/** Synchronises two directory structures. */
-public class BasicSyncFileVisitor extends SimpleFileVisitor<Path> {
- // TODO make it configurable
- private boolean trace = false;
-
- private final Path sourceBasePath;
- private final Path targetBasePath;
- private final boolean delete;
- private final boolean recursive;
-
- private SyncResult<Path> syncResult = new SyncResult<>();
-
- public BasicSyncFileVisitor(Path sourceBasePath, Path targetBasePath, boolean delete, boolean recursive) {
- this.sourceBasePath = sourceBasePath;
- this.targetBasePath = targetBasePath;
- this.delete = delete;
- this.recursive = recursive;
- }
-
- @Override
- public FileVisitResult preVisitDirectory(Path sourceDir, BasicFileAttributes attrs) throws IOException {
- if (!recursive && !sourceDir.equals(sourceBasePath))
- return FileVisitResult.SKIP_SUBTREE;
- Path targetDir = toTargetPath(sourceDir);
- Files.createDirectories(targetDir);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult postVisitDirectory(Path sourceDir, IOException exc) throws IOException {
- if (delete) {
- Path targetDir = toTargetPath(sourceDir);
- for (Path targetPath : Files.newDirectoryStream(targetDir)) {
- Path sourcePath = sourceDir.resolve(targetPath.getFileName());
- if (!Files.exists(sourcePath)) {
- try {
- FsUtils.delete(targetPath);
- deleted(targetPath);
- } catch (Exception e) {
- deleteFailed(targetPath, exc);
- }
- }
- }
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException {
- Path targetFile = toTargetPath(sourceFile);
- try {
- if (!Files.exists(targetFile)) {
- Files.copy(sourceFile, targetFile);
- added(sourceFile, targetFile);
- } else {
- if (shouldOverwrite(sourceFile, targetFile)) {
- Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING);
- }
- }
- } catch (Exception e) {
- copyFailed(sourceFile, targetFile, e);
- }
- return FileVisitResult.CONTINUE;
- }
-
- protected boolean shouldOverwrite(Path sourceFile, Path targetFile) throws IOException {
- long sourceSize = Files.size(sourceFile);
- long targetSize = Files.size(targetFile);
- if (sourceSize != targetSize) {
- return true;
- }
- FileTime sourceLastModif = Files.getLastModifiedTime(sourceFile);
- FileTime targetLastModif = Files.getLastModifiedTime(targetFile);
- if (sourceLastModif.compareTo(targetLastModif) > 0)
- return true;
- return shouldOverwriteLaterSameSize(sourceFile, targetFile);
- }
-
- protected boolean shouldOverwriteLaterSameSize(Path sourceFile, Path targetFile) {
- return false;
- }
-
-// @Override
-// public FileVisitResult visitFileFailed(Path sourceFile, IOException exc) throws IOException {
-// error("Cannot sync " + sourceFile, exc);
-// return FileVisitResult.CONTINUE;
-// }
-
- private Path toTargetPath(Path sourcePath) {
- Path relativePath = sourceBasePath.relativize(sourcePath);
- Path targetPath = targetBasePath.resolve(relativePath.toString());
- return targetPath;
- }
-
- public Path getSourceBasePath() {
- return sourceBasePath;
- }
-
- public Path getTargetBasePath() {
- return targetBasePath;
- }
-
- protected void added(Path sourcePath, Path targetPath) {
- syncResult.getAdded().add(targetPath);
- if (isTraceEnabled())
- trace("Added " + sourcePath + " as " + targetPath);
- }
-
- protected void modified(Path sourcePath, Path targetPath) {
- syncResult.getModified().add(targetPath);
- if (isTraceEnabled())
- trace("Overwritten from " + sourcePath + " to " + targetPath);
- }
-
- protected void copyFailed(Path sourcePath, Path targetPath, Exception e) {
- syncResult.addError(sourcePath, targetPath, e);
- if (isTraceEnabled())
- error("Cannot copy " + sourcePath + " to " + targetPath, e);
- }
-
- protected void deleted(Path targetPath) {
- syncResult.getDeleted().add(targetPath);
- if (isTraceEnabled())
- trace("Deleted " + targetPath);
- }
-
- protected void deleteFailed(Path targetPath, Exception e) {
- syncResult.addError(null, targetPath, e);
- if (isTraceEnabled())
- error("Cannot delete " + targetPath, e);
- }
-
- /** Log error. */
- protected void error(Object obj, Throwable e) {
- System.err.println(obj);
- e.printStackTrace();
- }
-
- protected boolean isTraceEnabled() {
- return trace;
- }
-
- protected void trace(Object obj) {
- System.out.println(obj);
- }
-
- public SyncResult<Path> getSyncResult() {
- return syncResult;
- }
-
-}
+++ /dev/null
-package org.argeo.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;
-
-/** Utilities around the standard Java file abstractions. */
-public class FsUtils {
- /** Sync a source path with a target path. */
- public static void sync(Path sourceBasePath, Path targetBasePath) {
- sync(sourceBasePath, targetBasePath, false);
- }
-
- /** Sync a source path with a target path. */
- public static void sync(Path sourceBasePath, Path targetBasePath, boolean delete) {
- sync(new BasicSyncFileVisitor(sourceBasePath, targetBasePath, delete, true));
- }
-
- public static void sync(BasicSyncFileVisitor syncFileVisitor) {
- try {
- Files.walkFileTree(syncFileVisitor.getSourceBasePath(), syncFileVisitor);
- } catch (Exception e) {
- throw new RuntimeException("Cannot sync " + syncFileVisitor.getSourceBasePath() + " with "
- + syncFileVisitor.getTargetBasePath(), e);
- }
- }
-
- /** Deletes this path, recursively if needed. */
- public static void delete(Path path) {
- try {
- Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
- @Override
- public FileVisitResult postVisitDirectory(Path directory, IOException e) throws IOException {
- if (e != null)
- throw e;
- Files.delete(directory);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- Files.delete(file);
- return FileVisitResult.CONTINUE;
- }
- });
- } catch (IOException e) {
- throw new RuntimeException("Cannot delete " + path, e);
- }
- }
-
- /** Singleton. */
- private FsUtils() {
- }
-
-}
+++ /dev/null
-/** Generic file system utilities. */
-package org.argeo.fs;
\ No newline at end of file
import org.apache.commons.cli.Options;
import org.argeo.cms.cli.CommandArgsException;
import org.argeo.cms.cli.DescribedCommand;
-import org.argeo.sync.SyncResult;
+import org.argeo.util.SyncResult;
public class FileSync implements DescribedCommand<SyncResult<Path>> {
final static Option deleteOption = Option.builder().longOpt("delete").desc("delete from target").build();
import java.nio.file.spi.FileSystemProvider;
import java.util.concurrent.Callable;
-import org.argeo.sync.SyncResult;
+import org.argeo.util.SyncResult;
/** Synchronises two paths. */
public class PathSync implements Callable<SyncResult<Path>> {
import java.nio.file.Path;
import org.argeo.api.cms.CmsLog;
-import org.argeo.fs.BasicSyncFileVisitor;
+import org.argeo.util.BasicSyncFileVisitor;
/** Synchronises two directory structures. */
public class SyncFileVisitor extends BasicSyncFileVisitor {
+++ /dev/null
-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);
- }
-}
+++ /dev/null
-package org.argeo.sync;
-
-import java.time.Instant;
-import java.util.Set;
-import java.util.TreeSet;
-
-/** Describes what happendend during a sync operation. */
-public class SyncResult<T> {
- private final Set<T> added = new TreeSet<>();
- private final Set<T> modified = new TreeSet<>();
- private final Set<T> deleted = new TreeSet<>();
- private final Set<Error> errors = new TreeSet<>();
-
- public Set<T> getAdded() {
- return added;
- }
-
- public Set<T> getModified() {
- return modified;
- }
-
- public Set<T> getDeleted() {
- return deleted;
- }
-
- public Set<Error> getErrors() {
- return errors;
- }
-
- public void addError(T sourcePath, T targetPath, Exception e) {
- Error error = new Error(sourcePath, targetPath, e);
- errors.add(error);
- }
-
- public boolean noModification() {
- return modified.isEmpty() && deleted.isEmpty() && added.isEmpty();
- }
-
- @Override
- public String toString() {
- if (noModification())
- return "No modification.";
- StringBuffer sb = new StringBuffer();
- for (T p : modified)
- sb.append("MOD ").append(p).append('\n');
- for (T p : deleted)
- sb.append("DEL ").append(p).append('\n');
- for (T p : added)
- sb.append("ADD ").append(p).append('\n');
- for (Error error : errors)
- sb.append(error).append('\n');
- return sb.toString();
- }
-
- public class Error implements Comparable<Error> {
- private final T sourcePath;// if null this is a failed delete
- private final T targetPath;
- private final Exception exception;
- private final Instant timestamp = Instant.now();
-
- public Error(T sourcePath, T targetPath, Exception e) {
- super();
- this.sourcePath = sourcePath;
- this.targetPath = targetPath;
- this.exception = e;
- }
-
- public T getSourcePath() {
- return sourcePath;
- }
-
- public T getTargetPath() {
- return targetPath;
- }
-
- public Exception getException() {
- return exception;
- }
-
- public Instant getTimestamp() {
- return timestamp;
- }
-
- @Override
- public int compareTo(Error o) {
- return timestamp.compareTo(o.timestamp);
- }
-
- @Override
- public int hashCode() {
- return timestamp.hashCode();
- }
-
- @Override
- public String toString() {
- return "ERR " + timestamp + (sourcePath == null ? "Deletion failed" : "Copy failed " + sourcePath) + " "
- + targetPath + " " + exception.getMessage();
- }
-
- }
-}
+++ /dev/null
-/** Synchrnoisation related utilities. */
-package org.argeo.sync;
\ No newline at end of file