package jdrivesync.fs;
import jdrivesync.cli.Options;
import jdrivesync.logging.LoggerFactory;
import jdrivesync.model.SyncDirectory;
import jdrivesync.model.SyncFile;
import jdrivesync.model.SyncItem;
import jdrivesync.report.ReportEntry;
import jdrivesync.report.ReportFactory;
import jdrivesync.util.FileUtil;
import jdrivesync.walker.Walker;
import jdrivesync.walker.WalkerVisitor;
import java.io.File;
import java.util.Iterator;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FileSystemWalker implements Walker {
private static final Logger LOGGER = LoggerFactory.getLogger();
private final File startDirectory;
private final Options options;
private FileSystemAdapter fileSystemAdapter;
public FileSystemWalker(Options options, FileSystemAdapter fileSystemAdapter) {
this.startDirectory = options.getLocalRootDir().get();
this.options = options;
this.fileSystemAdapter = fileSystemAdapter;
}
public void walk(WalkerVisitor fileSystemVisitor) {
SyncDirectory rootDirectory = new SyncDirectory(Optional.of(this.startDirectory), Optional.empty(), "/", Optional.empty());
walkInternal(rootDirectory, fileSystemVisitor, fileSystemAdapter);
}
private void walkInternal(SyncDirectory syncDirectory, WalkerVisitor fileSystemVisitor, FileSystemAdapter fileSystemAdapter) {
if (syncDirectory.getLocalFile().isPresent()) {
File directory = syncDirectory.getLocalFile().get();
if (fileSystemAdapter.exists(directory)) {
if (fileSystemAdapter.canRead(directory)) {
File[] files = fileSystemAdapter.listFiles(directory);
if (files != null) {
for (File file : files) {
String relativePath = FileUtil.toRelativePath(file, options);
if (fileSystemAdapter.isDirectory(file)) {
if (!fileShouldBeIgnored(relativePath, true, file)) {
SyncDirectory subSyncDirectory = new SyncDirectory(Optional.of(file), Optional.empty(), relativePath, Optional.of(syncDirectory));
syncDirectory.addChild(subSyncDirectory);
}
} else {
if (!fileShouldBeIgnored(relativePath, false, file)) {
SyncFile syncFile = new SyncFile(Optional.of(file), Optional.empty(), relativePath, Optional.of(syncDirectory));
syncDirectory.addChild(syncFile);
}
}
}
WalkerVisitor.WalkerVisitorResult result = fileSystemVisitor.visitDirectory(syncDirectory);
if (result == WalkerVisitor.WalkerVisitorResult.Continue) {
Iterator<SyncItem> childrenIterator = syncDirectory.getChildrenIterator();
while (childrenIterator.hasNext()) {
SyncItem syncItem = childrenIterator.next();
if (syncItem instanceof SyncDirectory) {
SyncDirectory subSyncDir = (SyncDirectory) syncItem;
walkInternal(subSyncDir, fileSystemVisitor, fileSystemAdapter);
}
childrenIterator.remove(); //free memory
}
}
} else {
LOGGER.log(Level.FINE, "Skipping directory '" + directory.getAbsolutePath() + "' because list of files is null/zero.");
ReportFactory.getInstance(options).log(new ReportEntry(FileUtil.toRelativePath(directory, options), ReportEntry.Status.Synchronized, ReportEntry.Action.Skipped));
}
} else {
LOGGER.log(Level.FINE, "Skipping directory '" + directory.getAbsolutePath() + "' because read permission is missing.");
ReportFactory.getInstance(options).log(new ReportEntry(FileUtil.toRelativePath(directory, options), ReportEntry.Status.Error, ReportEntry.Action.Skipped, "Missing read permission."));
}
} else {
LOGGER.log(Level.FINE, "Skipping directory '" + directory.getAbsolutePath() + "' because it does not exist.");
ReportFactory.getInstance(options).log(new ReportEntry(FileUtil.toRelativePath(directory, options), ReportEntry.Status.Error, ReportEntry.Action.Skipped, "Does not exist."));
}
} else {
LOGGER.log(Level.FINE, "Skipping directory '" + syncDirectory.getPath() + "' because no local directory is set.");
}
}
private boolean fileShouldBeIgnored(String path, boolean isDirectory, File file) {
boolean matches = options.getIgnoreFiles().matches(path, isDirectory);
if (matches && LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Ignoring '" + path + "' because the name matches the ignore list.");
}
if (!matches && options.getMaxFileSize().isPresent()) {
if (file.isFile()) {
long maxFileSize = options.getMaxFileSize().get();
long fileSize = file.length();
if (fileSize > maxFileSize) {
matches = true;
LOGGER.log(Level.FINE, "Ignoring '" + path + "' because file is bigger than maxFileSize (file: " + fileSize + ", maxFileSize: " + maxFileSize + ").");
}
}
}
return matches;
}
}