3 import java
.io
.IOException
;
4 import java
.nio
.file
.FileVisitResult
;
5 import java
.nio
.file
.Files
;
6 import java
.nio
.file
.Path
;
7 import java
.nio
.file
.SimpleFileVisitor
;
8 import java
.nio
.file
.StandardCopyOption
;
9 import java
.nio
.file
.attribute
.BasicFileAttributes
;
10 import java
.nio
.file
.attribute
.FileTime
;
12 import org
.argeo
.sync
.SyncResult
;
14 /** Synchronises two directory structures. */
15 public class BasicSyncFileVisitor
extends SimpleFileVisitor
<Path
> {
16 // TODO make it configurable
17 private boolean trace
= false;
19 private final Path sourceBasePath
;
20 private final Path targetBasePath
;
21 private final boolean delete
;
22 private final boolean recursive
;
24 private SyncResult
<Path
> syncResult
= new SyncResult
<>();
26 public BasicSyncFileVisitor(Path sourceBasePath
, Path targetBasePath
, boolean delete
, boolean recursive
) {
27 this.sourceBasePath
= sourceBasePath
;
28 this.targetBasePath
= targetBasePath
;
30 this.recursive
= recursive
;
34 public FileVisitResult
preVisitDirectory(Path sourceDir
, BasicFileAttributes attrs
) throws IOException
{
35 if (!recursive
&& !sourceDir
.equals(sourceBasePath
))
36 return FileVisitResult
.SKIP_SUBTREE
;
37 Path targetDir
= toTargetPath(sourceDir
);
38 Files
.createDirectories(targetDir
);
39 return FileVisitResult
.CONTINUE
;
43 public FileVisitResult
postVisitDirectory(Path sourceDir
, IOException exc
) throws IOException
{
45 Path targetDir
= toTargetPath(sourceDir
);
46 for (Path targetPath
: Files
.newDirectoryStream(targetDir
)) {
47 Path sourcePath
= sourceDir
.resolve(targetPath
.getFileName());
48 if (!Files
.exists(sourcePath
)) {
50 FsUtils
.delete(targetPath
);
52 } catch (Exception e
) {
53 deleteFailed(targetPath
, exc
);
58 return FileVisitResult
.CONTINUE
;
62 public FileVisitResult
visitFile(Path sourceFile
, BasicFileAttributes attrs
) throws IOException
{
63 Path targetFile
= toTargetPath(sourceFile
);
65 if (!Files
.exists(targetFile
)) {
66 Files
.copy(sourceFile
, targetFile
);
67 added(sourceFile
, targetFile
);
69 if (shouldOverwrite(sourceFile
, targetFile
)) {
70 Files
.copy(sourceFile
, targetFile
, StandardCopyOption
.REPLACE_EXISTING
);
73 } catch (Exception e
) {
74 copyFailed(sourceFile
, targetFile
, e
);
76 return FileVisitResult
.CONTINUE
;
79 protected boolean shouldOverwrite(Path sourceFile
, Path targetFile
) throws IOException
{
80 long sourceSize
= Files
.size(sourceFile
);
81 long targetSize
= Files
.size(targetFile
);
82 if (sourceSize
!= targetSize
) {
85 FileTime sourceLastModif
= Files
.getLastModifiedTime(sourceFile
);
86 FileTime targetLastModif
= Files
.getLastModifiedTime(targetFile
);
87 if (sourceLastModif
.compareTo(targetLastModif
) > 0)
89 return shouldOverwriteLaterSameSize(sourceFile
, targetFile
);
92 protected boolean shouldOverwriteLaterSameSize(Path sourceFile
, Path targetFile
) {
97 // public FileVisitResult visitFileFailed(Path sourceFile, IOException exc) throws IOException {
98 // error("Cannot sync " + sourceFile, exc);
99 // return FileVisitResult.CONTINUE;
102 private Path
toTargetPath(Path sourcePath
) {
103 Path relativePath
= sourceBasePath
.relativize(sourcePath
);
104 Path targetPath
= targetBasePath
.resolve(relativePath
.toString());
108 public Path
getSourceBasePath() {
109 return sourceBasePath
;
112 public Path
getTargetBasePath() {
113 return targetBasePath
;
116 protected void added(Path sourcePath
, Path targetPath
) {
117 syncResult
.getAdded().add(targetPath
);
118 if (isTraceEnabled())
119 trace("Added " + sourcePath
+ " as " + targetPath
);
122 protected void modified(Path sourcePath
, Path targetPath
) {
123 syncResult
.getModified().add(targetPath
);
124 if (isTraceEnabled())
125 trace("Overwritten from " + sourcePath
+ " to " + targetPath
);
128 protected void copyFailed(Path sourcePath
, Path targetPath
, Exception e
) {
129 syncResult
.addError(sourcePath
, targetPath
, e
);
130 if (isTraceEnabled())
131 error("Cannot copy " + sourcePath
+ " to " + targetPath
, e
);
134 protected void deleted(Path targetPath
) {
135 syncResult
.getDeleted().add(targetPath
);
136 if (isTraceEnabled())
137 trace("Deleted " + targetPath
);
140 protected void deleteFailed(Path targetPath
, Exception e
) {
141 syncResult
.addError(null, targetPath
, e
);
142 if (isTraceEnabled())
143 error("Cannot delete " + targetPath
, e
);
147 protected void error(Object obj
, Throwable e
) {
148 System
.err
.println(obj
);
152 protected boolean isTraceEnabled() {
156 protected void trace(Object obj
) {
157 System
.out
.println(obj
);
160 public SyncResult
<Path
> getSyncResult() {