From: Mathieu Baudier Date: Wed, 20 Jul 2022 09:39:17 +0000 (+0200) Subject: Move CMS file utilities to a dedicated package X-Git-Tag: v2.3.10~103 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=99e83d6a8d55e291039fb50a464dc7434d48458d Move CMS file utilities to a dedicated package --- diff --git a/org.argeo.cms.cli/src/org/argeo/cms/cli/FileSync.java b/org.argeo.cms.cli/src/org/argeo/cms/cli/FileSync.java index ccd092430..dc4c689d0 100644 --- a/org.argeo.cms.cli/src/org/argeo/cms/cli/FileSync.java +++ b/org.argeo.cms.cli/src/org/argeo/cms/cli/FileSync.java @@ -11,8 +11,8 @@ import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.argeo.api.cli.CommandArgsException; import org.argeo.api.cli.DescribedCommand; -import org.argeo.cms.acr.fs.PathSync; -import org.argeo.cms.acr.fs.SyncResult; +import org.argeo.cms.file.PathSync; +import org.argeo.cms.file.SyncResult; public class FileSync implements DescribedCommand> { final static Option deleteOption = Option.builder().longOpt("delete").desc("delete from target").build(); diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/BasicSyncFileVisitor.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/BasicSyncFileVisitor.java deleted file mode 100644 index 7041c75d8..000000000 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/BasicSyncFileVisitor.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.argeo.cms.acr.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; - -/** Synchronises two directory structures. */ -public class BasicSyncFileVisitor extends SimpleFileVisitor { - // 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 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 { - FsSyncUtils.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 getSyncResult() { - return syncResult; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsSyncUtils.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/FsSyncUtils.java deleted file mode 100644 index c45e66c3a..000000000 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsSyncUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.argeo.cms.acr.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; - -public class FsSyncUtils { - /** 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. Does nothing if the path does not - * exist. - */ - public static void delete(Path path) { - try { - if (!Files.exists(path)) - return; - Files.walkFileTree(path, new SimpleFileVisitor() { - @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 FsSyncUtils() { - - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/PathSync.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/PathSync.java deleted file mode 100644 index 427044e9a..000000000 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/PathSync.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.argeo.cms.acr.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.util.concurrent.Callable; - -/** Synchronises two paths. */ -public class PathSync implements Callable> { - private final URI sourceUri, targetUri; - private final boolean delete; - private final boolean recursive; - - public PathSync(URI sourceUri, URI targetUri) { - this(sourceUri, targetUri, false, false); - } - - public PathSync(URI sourceUri, URI targetUri, boolean delete, boolean recursive) { - this.sourceUri = sourceUri; - this.targetUri = targetUri; - this.delete = delete; - this.recursive = recursive; - } - - @Override - public SyncResult call() { - try { - Path sourceBasePath = createPath(sourceUri); - Path targetBasePath = createPath(targetUri); - SyncFileVisitor syncFileVisitor = new SyncFileVisitor(sourceBasePath, targetBasePath, delete, recursive); - Files.walkFileTree(sourceBasePath, syncFileVisitor); - return syncFileVisitor.getSyncResult(); - } catch (Exception e) { - throw new IllegalStateException("Cannot sync " + sourceUri + " to " + targetUri, e); - } - } - - private Path createPath(URI uri) { - Path path; - if (uri.getScheme() == null) { - path = Paths.get(uri.getPath()); - } else if (uri.getScheme().equals("file")) { - FileSystemProvider fsProvider = FileSystems.getDefault().provider(); - path = fsProvider.getPath(uri); - } else if (uri.getScheme().equals("davex")) { - throw new UnsupportedOperationException(); -// FileSystemProvider fsProvider = new DavexFsProvider(); -// path = fsProvider.getPath(uri); -// } else if (uri.getScheme().equals("sftp")) { -// Sftp sftp = new Sftp(uri); -// path = sftp.getBasePath(); - } else - throw new IllegalArgumentException("URI scheme not supported for " + uri); - return path; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncFileVisitor.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncFileVisitor.java deleted file mode 100644 index 2a372878c..000000000 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncFileVisitor.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.argeo.cms.acr.fs; - -import java.nio.file.Path; -import java.util.Objects; - -import org.argeo.api.cms.CmsLog; - -/** Synchronises two directory structures. */ -public class SyncFileVisitor extends BasicSyncFileVisitor { - private final static CmsLog log = CmsLog.getLog(SyncFileVisitor.class); - - public SyncFileVisitor(Path sourceBasePath, Path targetBasePath, boolean delete, boolean recursive) { - super(sourceBasePath, targetBasePath, delete, recursive); - } - - @Override - protected void error(Object obj, Throwable e) { - log.error(Objects.toString(obj), e); - } - - @Override - protected boolean isTraceEnabled() { - return log.isTraceEnabled(); - } - - @Override - protected void trace(Object obj) { - log.error(Objects.toString(obj)); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncResult.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncResult.java deleted file mode 100644 index 709b485ff..000000000 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/SyncResult.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.argeo.cms.acr.fs; - -import java.time.Instant; -import java.util.Set; -import java.util.TreeSet; - -/** Describes what happendend during a sync operation. */ -public class SyncResult { - private final Set added = new TreeSet<>(); - private final Set modified = new TreeSet<>(); - private final Set deleted = new TreeSet<>(); - private final Set errors = new TreeSet<>(); - - public Set getAdded() { - return added; - } - - public Set getModified() { - return modified; - } - - public Set getDeleted() { - return deleted; - } - - public Set 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 { - 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(); - } - - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/file/BasicSyncFileVisitor.java b/org.argeo.cms/src/org/argeo/cms/file/BasicSyncFileVisitor.java new file mode 100644 index 000000000..ac81329a9 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/file/BasicSyncFileVisitor.java @@ -0,0 +1,162 @@ +package org.argeo.cms.file; + +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; + +/** Synchronises two directory structures. */ +public class BasicSyncFileVisitor extends SimpleFileVisitor { + // 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 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 { + FsSyncUtils.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 getSyncResult() { + return syncResult; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/file/FsSyncUtils.java b/org.argeo.cms/src/org/argeo/cms/file/FsSyncUtils.java new file mode 100644 index 000000000..68eb5abdc --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/file/FsSyncUtils.java @@ -0,0 +1,62 @@ +package org.argeo.cms.file; + +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; + +public class FsSyncUtils { + /** 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. Does nothing if the path does not + * exist. + */ + public static void delete(Path path) { + try { + if (!Files.exists(path)) + return; + Files.walkFileTree(path, new SimpleFileVisitor() { + @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 FsSyncUtils() { + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/file/PathSync.java b/org.argeo.cms/src/org/argeo/cms/file/PathSync.java new file mode 100644 index 000000000..dc26aa28b --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/file/PathSync.java @@ -0,0 +1,59 @@ +package org.argeo.cms.file; + +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.util.concurrent.Callable; + +/** Synchronises two paths. */ +public class PathSync implements Callable> { + private final URI sourceUri, targetUri; + private final boolean delete; + private final boolean recursive; + + public PathSync(URI sourceUri, URI targetUri) { + this(sourceUri, targetUri, false, false); + } + + public PathSync(URI sourceUri, URI targetUri, boolean delete, boolean recursive) { + this.sourceUri = sourceUri; + this.targetUri = targetUri; + this.delete = delete; + this.recursive = recursive; + } + + @Override + public SyncResult call() { + try { + Path sourceBasePath = createPath(sourceUri); + Path targetBasePath = createPath(targetUri); + SyncFileVisitor syncFileVisitor = new SyncFileVisitor(sourceBasePath, targetBasePath, delete, recursive); + Files.walkFileTree(sourceBasePath, syncFileVisitor); + return syncFileVisitor.getSyncResult(); + } catch (Exception e) { + throw new IllegalStateException("Cannot sync " + sourceUri + " to " + targetUri, e); + } + } + + private Path createPath(URI uri) { + Path path; + if (uri.getScheme() == null) { + path = Paths.get(uri.getPath()); + } else if (uri.getScheme().equals("file")) { + FileSystemProvider fsProvider = FileSystems.getDefault().provider(); + path = fsProvider.getPath(uri); + } else if (uri.getScheme().equals("davex")) { + throw new UnsupportedOperationException(); +// FileSystemProvider fsProvider = new DavexFsProvider(); +// path = fsProvider.getPath(uri); +// } else if (uri.getScheme().equals("sftp")) { +// Sftp sftp = new Sftp(uri); +// path = sftp.getBasePath(); + } else + throw new IllegalArgumentException("URI scheme not supported for " + uri); + return path; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/file/SyncFileVisitor.java b/org.argeo.cms/src/org/argeo/cms/file/SyncFileVisitor.java new file mode 100644 index 000000000..a69d2bf5e --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/file/SyncFileVisitor.java @@ -0,0 +1,30 @@ +package org.argeo.cms.file; + +import java.nio.file.Path; +import java.util.Objects; + +import org.argeo.api.cms.CmsLog; + +/** Synchronises two directory structures. */ +public class SyncFileVisitor extends BasicSyncFileVisitor { + private final static CmsLog log = CmsLog.getLog(SyncFileVisitor.class); + + public SyncFileVisitor(Path sourceBasePath, Path targetBasePath, boolean delete, boolean recursive) { + super(sourceBasePath, targetBasePath, delete, recursive); + } + + @Override + protected void error(Object obj, Throwable e) { + log.error(Objects.toString(obj), e); + } + + @Override + protected boolean isTraceEnabled() { + return log.isTraceEnabled(); + } + + @Override + protected void trace(Object obj) { + log.error(Objects.toString(obj)); + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/file/SyncResult.java b/org.argeo.cms/src/org/argeo/cms/file/SyncResult.java new file mode 100644 index 000000000..35ab3f96a --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/file/SyncResult.java @@ -0,0 +1,101 @@ +package org.argeo.cms.file; + +import java.time.Instant; +import java.util.Set; +import java.util.TreeSet; + +/** Describes what happendend during a sync operation. */ +public class SyncResult { + private final Set added = new TreeSet<>(); + private final Set modified = new TreeSet<>(); + private final Set deleted = new TreeSet<>(); + private final Set errors = new TreeSet<>(); + + public Set getAdded() { + return added; + } + + public Set getModified() { + return modified; + } + + public Set getDeleted() { + return deleted; + } + + public Set 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 { + 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(); + } + + } +}