+++ /dev/null
-package org.argeo.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import org.argeo.slc.sync.FsSyncUtils;
-
-/** {@link FsUtils} tests. */
-public class FsUtilsTest {
- final static String FILE00 = "file00";
- final static String FILE01 = "file01";
- final static String SUB_DIR = "subDir";
-
- public void testDelete() throws IOException {
- Path dir = createDir00();
- assert Files.exists(dir);
- FsSyncUtils.delete(dir);
- assert !Files.exists(dir);
- }
-
- public void testSync() throws IOException {
- Path source = createDir00();
- Path target = Files.createTempDirectory(getClass().getName());
- FsSyncUtils.sync(source, target);
- assert Files.exists(target.resolve(FILE00));
- assert Files.exists(target.resolve(SUB_DIR));
- assert Files.exists(target.resolve(SUB_DIR + File.separator + FILE01));
- FsSyncUtils.delete(source.resolve(SUB_DIR));
- FsSyncUtils.sync(source, target, true);
- assert Files.exists(target.resolve(FILE00));
- assert !Files.exists(target.resolve(SUB_DIR));
- assert !Files.exists(target.resolve(SUB_DIR + File.separator + FILE01));
-
- // clean up
- FsSyncUtils.delete(source);
- FsSyncUtils.delete(target);
-
- }
-
- Path createDir00() throws IOException {
- Path base = Files.createTempDirectory(getClass().getName());
- base.toFile().deleteOnExit();
- Files.createFile(base.resolve(FILE00)).toFile().deleteOnExit();
- Path subDir = Files.createDirectories(base.resolve(SUB_DIR));
- subDir.toFile().deleteOnExit();
- Files.createFile(subDir.resolve(FILE01)).toFile().deleteOnExit();
- return base;
- }
-}
+++ /dev/null
-package org.argeo.slc.cli;
-
-public class CommandArgsException extends IllegalArgumentException {
- private static final long serialVersionUID = -7271050747105253935L;
- private String commandName;
- private volatile CommandsCli commandsCli;
-
- public CommandArgsException(Exception cause) {
- super(cause.getMessage(), cause);
- }
-
- public CommandArgsException(String message) {
- super(message);
- }
-
- public String getCommandName() {
- return commandName;
- }
-
- public void setCommandName(String commandName) {
- this.commandName = commandName;
- }
-
- public CommandsCli getCommandsCli() {
- return commandsCli;
- }
-
- public void setCommandsCli(CommandsCli commandsCli) {
- this.commandsCli = commandsCli;
- }
-
-}
+++ /dev/null
-package org.argeo.slc.cli;
-
-import java.util.List;
-
-/** {@link RuntimeException} referring during a command run. */
-public class CommandRuntimeException extends RuntimeException {
- private static final long serialVersionUID = 5595999301269377128L;
-
- private final DescribedCommand<?> command;
- private final List<String> arguments;
-
- public CommandRuntimeException(Throwable e, DescribedCommand<?> command, List<String> arguments) {
- this(null, e, command, arguments);
- }
-
- public CommandRuntimeException(String message, DescribedCommand<?> command, List<String> arguments) {
- this(message, null, command, arguments);
- }
-
- public CommandRuntimeException(String message, Throwable e, DescribedCommand<?> command, List<String> arguments) {
- super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")"
- : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e);
- this.command = command;
- this.arguments = arguments;
- }
-
- public DescribedCommand<?> getCommand() {
- return command;
- }
-
- public List<String> getArguments() {
- return arguments;
- }
-
-}
+++ /dev/null
-package org.argeo.slc.cli;
-
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.function.Function;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-/** Base class for a CLI managing sub commands. */
-public abstract class CommandsCli implements DescribedCommand<Object> {
- public final static String HELP = "help";
-
- private final String commandName;
- private Map<String, Function<List<String>, ?>> commands = new TreeMap<>();
-
- protected final Options options = new Options();
-
- public CommandsCli(String commandName) {
- this.commandName = commandName;
- }
-
- @Override
- public Object apply(List<String> args) {
- String cmd = null;
- List<String> newArgs = new ArrayList<>();
- try {
- CommandLineParser clParser = new DefaultParser();
- CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true);
- List<String> leftOvers = commonCl.getArgList();
- for (String arg : leftOvers) {
- if (!arg.startsWith("-") && cmd == null) {
- cmd = arg;
- } else {
- newArgs.add(arg);
- }
- }
- } catch (ParseException e) {
- CommandArgsException cae = new CommandArgsException(e);
- throw cae;
- }
-
- Function<List<String>, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand();
- if (function == null)
- throw new IllegalArgumentException("Uknown command " + cmd);
- try {
- return function.apply(newArgs).toString();
- } catch (CommandArgsException e) {
- if (e.getCommandName() == null) {
- e.setCommandName(cmd);
- e.setCommandsCli(this);
- }
- throw e;
- } catch (IllegalArgumentException e) {
- CommandArgsException cae = new CommandArgsException(e);
- cae.setCommandName(cmd);
- throw cae;
- }
- }
-
- @Override
- public Options getOptions() {
- return options;
- }
-
- protected void addCommand(String cmd, Function<List<String>, ?> function) {
- commands.put(cmd, function);
-
- }
-
- @Override
- public String getUsage() {
- return "[command]";
- }
-
- protected void addCommandsCli(CommandsCli commandsCli) {
- addCommand(commandsCli.getCommandName(), commandsCli);
- commandsCli.addCommand(HELP, new HelpCommand(this, commandsCli));
- }
-
- public String getCommandName() {
- return commandName;
- }
-
- public Set<String> getSubCommands() {
- return commands.keySet();
- }
-
- public Function<List<String>, ?> getCommand(String command) {
- return commands.get(command);
- }
-
- public HelpCommand getHelpCommand() {
- return (HelpCommand) getCommand(HELP);
- }
-
- public Function<List<String>, String> getDefaultCommand() {
- return getHelpCommand();
- }
-
- /** In order to implement quickly a main method. */
- public static void mainImpl(CommandsCli cli, String[] args) {
- try {
- cli.addCommand(CommandsCli.HELP, new HelpCommand(null, cli));
- Object output = cli.apply(Arrays.asList(args));
- System.out.println(output);
- System.exit(0);
- } catch (CommandArgsException e) {
- System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage());
- if (e.getCommandName() != null) {
- StringWriter out = new StringWriter();
- HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out);
- System.err.println(out.toString());
- } else {
- e.printStackTrace();
- }
- System.exit(1);
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
-}
+++ /dev/null
-package org.argeo.slc.cli;
-
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Function;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-/** A command that can be described. */
-public interface DescribedCommand<T> extends Function<List<String>, T> {
- default Options getOptions() {
- return new Options();
- }
-
- String getDescription();
-
- default String getUsage() {
- return null;
- }
-
- default String getExamples() {
- return null;
- }
-
- default CommandLine toCommandLine(List<String> args) {
- try {
- DefaultParser parser = new DefaultParser();
- return parser.parse(getOptions(), args.toArray(new String[args.size()]));
- } catch (ParseException e) {
- throw new CommandArgsException(e);
- }
- }
-
- /** In order to implement quickly a main method. */
- public static void mainImpl(DescribedCommand<?> command, String[] args) {
- try {
- Object output = command.apply(Arrays.asList(args));
- System.out.println(output);
- System.exit(0);
- } catch (IllegalArgumentException e) {
- StringWriter out = new StringWriter();
- HelpCommand.printHelp(command, out);
- System.err.println(out.toString());
- System.exit(1);
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
-
-}
+++ /dev/null
-package org.argeo.slc.cli;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.List;
-import java.util.function.Function;
-
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
-
-/** A special command that can describe {@link DescribedCommand}. */
-public class HelpCommand implements DescribedCommand<String> {
- private CommandsCli commandsCli;
- private CommandsCli parentCommandsCli;
-
- // Help formatting
- private static int helpWidth = 80;
- private static int helpLeftPad = 4;
- private static int helpDescPad = 20;
-
- public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) {
- super();
- this.parentCommandsCli = parentCommandsCli;
- this.commandsCli = commandsCli;
- }
-
- @Override
- public String apply(List<String> args) {
- StringWriter out = new StringWriter();
-
- if (args.size() == 0) {// overview
- printHelp(commandsCli, out);
- } else {
- String cmd = args.get(0);
- Function<List<String>, ?> function = commandsCli.getCommand(cmd);
- if (function == null)
- return "Command " + cmd + " not found.";
- Options options;
- String examples;
- DescribedCommand<?> command = null;
- if (function instanceof DescribedCommand) {
- command = (DescribedCommand<?>) function;
- options = command.getOptions();
- examples = command.getExamples();
- } else {
- options = new Options();
- examples = null;
- }
- String description = getShortDescription(function);
- String commandCall = getCommandUsage(cmd, command);
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad,
- helpDescPad, examples, false);
- }
- return out.toString();
- }
-
- private static String getShortDescription(Function<List<String>, ?> function) {
- if (function instanceof DescribedCommand) {
- return ((DescribedCommand<?>) function).getDescription();
- } else {
- return function.toString();
- }
- }
-
- public String getCommandUsage(String cmd, DescribedCommand<?> command) {
- String commandCall = getCommandCall(commandsCli) + " " + cmd;
- assert command != null;
- if (command != null && command.getUsage() != null) {
- commandCall = commandCall + " " + command.getUsage();
- }
- return commandCall;
- }
-
- @Override
- public String getDescription() {
- return "Shows this help or describes a command";
- }
-
- @Override
- public String getUsage() {
- return "[command]";
- }
-
- public CommandsCli getParentCommandsCli() {
- return parentCommandsCli;
- }
-
- protected String getCommandCall(CommandsCli commandsCli) {
- HelpCommand hc = commandsCli.getHelpCommand();
- if (hc.getParentCommandsCli() != null) {
- return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
- } else {
- return commandsCli.getCommandName();
- }
- }
-
- public static void printHelp(DescribedCommand<?> command, StringWriter out) {
- String usage = "java " + command.getClass().getName()
- + (command.getUsage() != null ? " " + command.getUsage() : "");
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
- helpLeftPad, helpDescPad, command.getExamples(), false);
-
- }
-
- public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
- DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
- String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
- helpLeftPad, helpDescPad, command.getExamples(), false);
-
- }
-
- public static void printHelp(CommandsCli commandsCli, StringWriter out) {
- out.append(commandsCli.getDescription()).append('\n');
- String leftPad = spaces(helpLeftPad);
- for (String cmd : commandsCli.getSubCommands()) {
- Function<List<String>, ?> function = commandsCli.getCommand(cmd);
- assert function != null;
- out.append(leftPad);
- out.append(cmd);
- // TODO deal with long commands
- out.append(spaces(helpDescPad - cmd.length()));
- out.append(getShortDescription(function));
- out.append('\n');
- }
- }
-
- private static String spaces(int count) {
- // Java 11
- // return " ".repeat(count);
- if (count <= 0)
- return "";
- else {
- StringBuilder sb = new StringBuilder(count);
- for (int i = 0; i < count; i++)
- sb.append(' ');
- return sb.toString();
- }
- }
-}
+++ /dev/null
-package org.argeo.slc.cli.fs;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.argeo.slc.cli.CommandArgsException;
-import org.argeo.slc.cli.DescribedCommand;
-import org.argeo.slc.sync.SyncResult;
-
-public class FileSync implements DescribedCommand<SyncResult<Path>> {
- final static Option deleteOption = Option.builder().longOpt("delete").desc("delete from target").build();
- final static Option recursiveOption = Option.builder("r").longOpt("recursive").desc("recurse into directories")
- .build();
- final static Option progressOption = Option.builder().longOpt("progress").hasArg(false).desc("show progress")
- .build();
-
- @Override
- public SyncResult<Path> apply(List<String> t) {
- try {
- CommandLine line = toCommandLine(t);
- List<String> remaining = line.getArgList();
- if (remaining.size() == 0) {
- throw new CommandArgsException("There must be at least one argument");
- }
- URI sourceUri = new URI(remaining.get(0));
- URI targetUri;
- if (remaining.size() == 1) {
- targetUri = Paths.get(System.getProperty("user.dir")).toUri();
- } else {
- targetUri = new URI(remaining.get(1));
- }
- boolean delete = line.hasOption(deleteOption.getLongOpt());
- boolean recursive = line.hasOption(recursiveOption.getLongOpt());
- PathSync pathSync = new PathSync(sourceUri, targetUri, delete, recursive);
- return pathSync.call();
- } catch (URISyntaxException e) {
- throw new CommandArgsException(e);
- }
- }
-
- @Override
- public Options getOptions() {
- Options options = new Options();
- options.addOption(recursiveOption);
- options.addOption(deleteOption);
- options.addOption(progressOption);
- return options;
- }
-
- @Override
- public String getUsage() {
- return "[source URI] [target URI]";
- }
-
- public static void main(String[] args) {
- DescribedCommand.mainImpl(new FileSync(), args);
-// Options options = new Options();
-// options.addOption("r", "recursive", false, "recurse into directories");
-// options.addOption(Option.builder().longOpt("progress").hasArg(false).desc("show progress").build());
-//
-// CommandLineParser parser = new DefaultParser();
-// try {
-// CommandLine line = parser.parse(options, args);
-// List<String> remaining = line.getArgList();
-// if (remaining.size() == 0) {
-// System.err.println("There must be at least one argument");
-// printHelp(options);
-// System.exit(1);
-// }
-// URI sourceUri = new URI(remaining.get(0));
-// URI targetUri;
-// if (remaining.size() == 1) {
-// targetUri = Paths.get(System.getProperty("user.dir")).toUri();
-// } else {
-// targetUri = new URI(remaining.get(1));
-// }
-// PathSync pathSync = new PathSync(sourceUri, targetUri);
-// pathSync.run();
-// } catch (Exception exp) {
-// exp.printStackTrace();
-// printHelp(options);
-// System.exit(1);
-// }
- }
-
-// public static void printHelp(Options options) {
-// HelpFormatter formatter = new HelpFormatter();
-// formatter.printHelp("sync SRC [DEST]", options, true);
-// }
-
- @Override
- public String getDescription() {
- return "Synchronises files";
- }
-
-}
+++ /dev/null
-package org.argeo.slc.cli.fs;
-
-import org.argeo.slc.cli.CommandsCli;
-
-/** File utilities. */
-public class FsCommands extends CommandsCli {
-
- public FsCommands(String commandName) {
- super(commandName);
- addCommand("sync", new FileSync());
- }
-
- @Override
- public String getDescription() {
- return "Utilities around files and file systems";
- }
-
-}
+++ /dev/null
-package org.argeo.slc.cli.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;
-
-import org.argeo.slc.sync.SyncResult;
-
-/** Synchronises two paths. */
-public class PathSync implements Callable<SyncResult<Path>> {
- 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<Path> 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;
- }
-}
+++ /dev/null
-package org.argeo.slc.cli.fs;
-
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.nio.file.Path;
-import java.util.Objects;
-
-import org.argeo.slc.sync.BasicSyncFileVisitor;
-
-/** Synchronises two directory structures. */
-public class SyncFileVisitor extends BasicSyncFileVisitor {
- private final static Logger logger = System.getLogger(SyncFileVisitor.class.getName());
-
- public SyncFileVisitor(Path sourceBasePath, Path targetBasePath, boolean delete, boolean recursive) {
- super(sourceBasePath, targetBasePath, delete, recursive);
- }
-
- @Override
- protected void error(Object obj, Throwable e) {
- logger.log(Level.ERROR, Objects.toString(obj), e);
- }
-
- @Override
- protected boolean isTraceEnabled() {
- return logger.isLoggable(Level.TRACE);
- }
-
- @Override
- protected void trace(Object obj) {
- logger.log(Level.TRACE, Objects.toString(obj));
- }
-}
+++ /dev/null
-/** File system CLI commands. */
-package org.argeo.slc.cli.fs;
\ No newline at end of file
+++ /dev/null
-/** Command line API. */
-package org.argeo.slc.cli;
\ No newline at end of file
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
-import org.argeo.slc.cli.DescribedCommand;
+import org.argeo.cms.cli.DescribedCommand;
public class Echo implements DescribedCommand<String> {
package org.argeo.slc.cli.posix;
-import org.argeo.slc.cli.CommandsCli;
+import org.argeo.cms.cli.CommandsCli;
/** POSIX commands. */
public class PosixCommands extends CommandsCli {
+++ /dev/null
-package org.argeo.slc.mail;
-
-import static java.lang.System.Logger.Level.DEBUG;
-import static java.lang.System.Logger.Level.ERROR;
-import static org.argeo.slc.mail.EmailUtils.describe;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.System.Logger;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.time.Instant;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Properties;
-
-import javax.mail.FetchProfile;
-import javax.mail.Folder;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Store;
-import javax.mail.URLName;
-import javax.mail.internet.InternetHeaders;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.search.HeaderTerm;
-import javax.mail.util.SharedFileInputStream;
-
-import com.sun.mail.imap.IMAPFolder;
-import com.sun.mail.mbox.MboxFolder;
-import com.sun.mail.mbox.MboxMessage;
-
-/** Migrates emails from one storage to the another one. */
-public class EmailMigration {
- private final static Logger logger = System.getLogger(EmailMigration.class.getName());
-
-// private String targetBaseDir;
-
- private String sourceServer;
- private String sourceUsername;
- private String sourcePassword;
-
- private String targetServer;
- private String targetUsername;
- private String targetPassword;
-
- public void process() throws MessagingException, IOException {
-// Path baseDir = Paths.get(targetBaseDir).resolve(sourceUsername).resolve("mbox");
-
- Store sourceStore = null;
- try {
- Properties sourceProperties = System.getProperties();
- sourceProperties.setProperty("mail.store.protocol", "imaps");
-
- Session sourceSession = Session.getInstance(sourceProperties, null);
- // session.setDebug(true);
- sourceStore = sourceSession.getStore("imaps");
- sourceStore.connect(sourceServer, sourceUsername, sourcePassword);
-
- Folder defaultFolder = sourceStore.getDefaultFolder();
-// migrateFolders(baseDir, defaultFolder);
-
- // Always start with Inbox
-// Folder inboxFolder = sourceStore.getFolder(EmailUtils.INBOX);
-// migrateFolder(baseDir, inboxFolder);
-
- Properties targetProperties = System.getProperties();
- targetProperties.setProperty("mail.imap.starttls.enable", "true");
- targetProperties.setProperty("mail.imap.auth", "true");
-
- Session targetSession = Session.getInstance(targetProperties, null);
- // session.setDebug(true);
- Store targetStore = targetSession.getStore("imap");
- targetStore.connect(targetServer, targetUsername, targetPassword);
-
-// Folder targetFolder = targetStore.getFolder(EmailUtils.INBOX);
-// logger.log(DEBUG, "Source message count " + inboxFolder.getMessageCount());
-// logger.log(DEBUG, "Target message count " + targetFolder.getMessageCount());
-
- migrateFolders(defaultFolder, targetStore);
- } finally {
- if (sourceStore != null)
- sourceStore.close();
-
- }
- }
-
- protected void migrateFolders(Folder sourceFolder, Store targetStore) throws MessagingException, IOException {
- folders: for (Folder folder : sourceFolder.list()) {
- String folderName = folder.getName();
-
- String folderFullName = folder.getFullName();
-
- // GMail specific
- if (folderFullName.equals("[Gmail]")) {
- migrateFolders(folder, targetStore);
- continue folders;
- }
- if (folderFullName.startsWith("[Gmail]")) {
- // Make it configurable
- switch (folderName) {
- case "All Mail":
- case "Important":
- case "Spam":
- continue folders;
- default:
- // does nothing
- }
- folderFullName = folder.getName();
- }
-
- int messageCount = (folder.getType() & Folder.HOLDS_MESSAGES) != 0 ? folder.getMessageCount() : 0;
- boolean hasSubFolders = (folder.getType() & Folder.HOLDS_FOLDERS) != 0 ? folder.list().length != 0 : false;
- Folder targetFolder;
- if (hasSubFolders) {// has sub-folders
- if (messageCount == 0) {
- targetFolder = targetStore.getFolder(folderFullName);
- if (!targetFolder.exists()) {
- targetFolder.create(Folder.HOLDS_FOLDERS);
- logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + targetFolder.getFullName());
- }
- } else {// also has messages
- Folder parentFolder = targetStore.getFolder(folderFullName);
- if (!parentFolder.exists()) {
- parentFolder.create(Folder.HOLDS_FOLDERS);
- logger.log(DEBUG, "Created HOLDS_FOLDERS folder " + parentFolder.getFullName());
- }
- String miscFullName = folderFullName + "/_Misc";
- targetFolder = targetStore.getFolder(miscFullName);
- if (!targetFolder.exists()) {
- targetFolder.create(Folder.HOLDS_MESSAGES);
- logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName());
- }
- }
- } else {// no sub-folders
- if (messageCount == 0) { // empty
- logger.log(DEBUG, "Skip empty folder " + folderFullName);
- continue folders;
- }
- targetFolder = targetStore.getFolder(folderFullName);
- if (!targetFolder.exists()) {
- targetFolder.create(Folder.HOLDS_MESSAGES);
- logger.log(DEBUG, "Created HOLDS_MESSAGES folder " + targetFolder.getFullName());
- }
- }
-
- if (messageCount != 0) {
-
- targetFolder.open(Folder.READ_WRITE);
- try {
- long begin = System.currentTimeMillis();
- folder.open(Folder.READ_ONLY);
- migrateFolder(folder, targetFolder);
- long duration = System.currentTimeMillis() - begin;
- logger.log(DEBUG, folderFullName + " - Migration of " + messageCount + " messages took "
- + (duration / 1000) + " s (" + (duration / messageCount) + " ms per message)");
- } finally {
- folder.close();
- targetFolder.close();
- }
- }
-
- // recursive
- if (hasSubFolders) {
- migrateFolders(folder, targetStore);
- }
- }
- }
-
- protected void migrateFoldersToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException {
- folders: for (Folder folder : sourceFolder.list()) {
- String folderName = folder.getName();
-
- if ((folder.getType() & Folder.HOLDS_MESSAGES) != 0) {
- // Make it configurable
- switch (folderName) {
- case "All Mail":
- case "Important":
- continue folders;
- default:
- // doe nothing
- }
- migrateFolderToFs(baseDir, folder);
- }
- if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
- migrateFoldersToFs(baseDir.resolve(folder.getName()), folder);
- }
- }
- }
-
- protected void migrateFolderToFs(Path baseDir, Folder sourceFolder) throws MessagingException, IOException {
-
- String folderName = sourceFolder.getName();
- sourceFolder.open(Folder.READ_ONLY);
-
- Folder targetFolder = null;
- try {
- int messageCount = sourceFolder.getMessageCount();
- logger.log(DEBUG, folderName + " - Message count : " + messageCount);
- if (messageCount == 0)
- return;
-// logger.log(DEBUG, folderName + " - Unread Messages : " + sourceFolder.getUnreadMessageCount());
-
- boolean saveAsFiles = false;
-
- if (saveAsFiles) {
- Message messages[] = sourceFolder.getMessages();
-
- for (int i = 0; i < messages.length; ++i) {
-// logger.log(DEBUG, "MESSAGE #" + (i + 1) + ":");
- Message msg = messages[i];
-// String from = "unknown";
-// if (msg.getReplyTo().length >= 1) {
-// from = msg.getReplyTo()[0].toString();
-// } else if (msg.getFrom().length >= 1) {
-// from = msg.getFrom()[0].toString();
-// }
- String subject = msg.getSubject();
- Instant sentDate = msg.getSentDate().toInstant();
-// logger.log(DEBUG, "Saving ... " + subject + " from " + from + " (" + sentDate + ")");
- String fileName = sentDate + " " + subject;
- Path file = baseDir.resolve(fileName);
- savePartsAsFiles(msg.getContent(), file);
- }
- }
- else {
- long begin = System.currentTimeMillis();
- targetFolder = openMboxTargetFolder(sourceFolder, baseDir);
- migrateFolder(sourceFolder, targetFolder);
- long duration = System.currentTimeMillis() - begin;
- logger.log(DEBUG, folderName + " - Migration of " + messageCount + " messages took " + (duration / 1000)
- + " s (" + (duration / messageCount) + " ms per message)");
- }
- } finally {
- sourceFolder.close();
- if (targetFolder != null)
- targetFolder.close();
- }
- }
-
- protected Folder migrateFolder(Folder sourceFolder, Folder targetFolder) throws MessagingException, IOException {
- String folderName = targetFolder.getName();
-
- int lastSourceNumber;
- int currentTargetMessageCount = targetFolder.getMessageCount();
- if (currentTargetMessageCount != 0) {
- MimeMessage lastTargetMessage = (MimeMessage) targetFolder.getMessage(currentTargetMessageCount);
- logger.log(DEBUG, folderName + " - Last target message " + describe(lastTargetMessage));
- Date lastTargetSent = lastTargetMessage.getReceivedDate();
- Message[] lastSourceMessage = sourceFolder
- .search(new HeaderTerm(EmailUtils.MESSAGE_ID, lastTargetMessage.getMessageID()));
- if (lastSourceMessage.length == 0)
- throw new IllegalStateException("No message found with message ID " + lastTargetMessage.getMessageID());
- if (lastSourceMessage.length != 1) {
- for (Message msg : lastSourceMessage) {
- logger.log(ERROR, "Message " + describe(msg));
-
- }
- throw new IllegalStateException(
- lastSourceMessage.length + " messages found with received date " + lastTargetSent.toInstant());
- }
- lastSourceNumber = lastSourceMessage[0].getMessageNumber();
- } else {
- lastSourceNumber = 0;
- }
- logger.log(DEBUG, folderName + " - Last source message number " + lastSourceNumber);
-
- int countToRetrieve = sourceFolder.getMessageCount() - lastSourceNumber;
-
- FetchProfile fetchProfile = new FetchProfile();
- fetchProfile.add(FetchProfile.Item.FLAGS);
- fetchProfile.add(FetchProfile.Item.ENVELOPE);
- fetchProfile.add(FetchProfile.Item.CONTENT_INFO);
- fetchProfile.add(FetchProfile.Item.SIZE);
- if (sourceFolder instanceof IMAPFolder) {
- // IMAPFolder sourceImapFolder = (IMAPFolder) sourceFolder;
- fetchProfile.add(IMAPFolder.FetchProfileItem.HEADERS);
- fetchProfile.add(IMAPFolder.FetchProfileItem.MESSAGE);
- }
-
- int batchSize = 100;
- int batchCount = countToRetrieve / batchSize;
- if (countToRetrieve % batchSize != 0)
- batchCount = batchCount + 1;
- // int batchCount = 2; // for testing
- for (int i = 0; i < batchCount; i++) {
- long begin = System.currentTimeMillis();
-
- int start = lastSourceNumber + i * batchSize + 1;
- int end = lastSourceNumber + (i + 1) * batchSize;
- if (end >= (lastSourceNumber + countToRetrieve + 1))
- end = lastSourceNumber + countToRetrieve;
- Message[] sourceMessages = sourceFolder.getMessages(start, end);
- sourceFolder.fetch(sourceMessages, fetchProfile);
- // targetFolder.appendMessages(sourceMessages);
- // sourceFolder.copyMessages(sourceMessages,targetFolder);
-
- copyMessages(sourceMessages, targetFolder);
-// copyMessagesToMbox(sourceMessages, targetFolder);
-
- String describeLast = describe(sourceMessages[sourceMessages.length - 1]);
-
-// if (i % 10 == 9) {
- // free memory from fetched messages
- sourceFolder.close();
- targetFolder.close();
-
- sourceFolder.open(Folder.READ_ONLY);
- targetFolder.open(Folder.READ_WRITE);
-// logger.log(DEBUG, "Open/close folder in order to free memory");
-// }
-
- long duration = System.currentTimeMillis() - begin;
- logger.log(DEBUG, folderName + " - batch " + i + " took " + (duration / 1000) + " s, "
- + (duration / (end - start + 1)) + " ms per message. Last message " + describeLast);
- }
-
- return targetFolder;
- }
-
- protected Folder openMboxTargetFolder(Folder sourceFolder, Path baseDir) throws MessagingException, IOException {
- String folderName = sourceFolder.getName();
- if (sourceFolder.getName().equals(EmailUtils.INBOX_UPPER_CASE))
- folderName = EmailUtils.INBOX;// Inbox
-
- Path targetDir = baseDir;// .resolve("mbox");
- Files.createDirectories(targetDir);
- Path targetPath;
- if (((sourceFolder.getType() & Folder.HOLDS_FOLDERS) != 0) && sourceFolder.list().length != 0) {
- Path dir = targetDir.resolve(folderName);
- Files.createDirectories(dir);
- targetPath = dir.resolve("_Misc");
- } else {
- targetPath = targetDir.resolve(folderName);
- }
- if (!Files.exists(targetPath))
- Files.createFile(targetPath);
- URLName targetUrlName = new URLName("mbox:" + targetPath.toString());
- Properties targetProperties = new Properties();
- // targetProperties.setProperty("mail.mime.address.strict", "false");
- Session targetSession = Session.getDefaultInstance(targetProperties);
- Folder targetFolder = targetSession.getFolder(targetUrlName);
- targetFolder.open(Folder.READ_WRITE);
-
- return targetFolder;
- }
-
- protected void copyMessages(Message[] sourceMessages, Folder targetFolder) throws MessagingException {
- targetFolder.appendMessages(sourceMessages);
- }
-
- protected void copyMessagesToMbox(Message[] sourceMessages, Folder targetFolder)
- throws MessagingException, IOException {
- Message[] targetMessages = new Message[sourceMessages.length];
- for (int j = 0; j < sourceMessages.length; j++) {
- MimeMessage sourceMm = (MimeMessage) sourceMessages[j];
- InternetHeaders ih = new InternetHeaders();
- for (Enumeration<String> e = sourceMm.getAllHeaderLines(); e.hasMoreElements();) {
- ih.addHeaderLine(e.nextElement());
- }
- Path tmpFileSource = Files.createTempFile("argeo-mbox-source", ".txt");
- Path tmpFileTarget = Files.createTempFile("argeo-mbox-target", ".txt");
- Files.copy(sourceMm.getRawInputStream(), tmpFileSource, StandardCopyOption.REPLACE_EXISTING);
-
- // we use ISO_8859_1 because it is more robust than US_ASCII with regard to
- // missing characters
- try (BufferedReader reader = Files.newBufferedReader(tmpFileSource, StandardCharsets.ISO_8859_1);
- BufferedWriter writer = Files.newBufferedWriter(tmpFileTarget, StandardCharsets.ISO_8859_1);) {
- int lineNumber = 0;
- String line = null;
- try {
- while ((line = reader.readLine()) != null) {
- lineNumber++;
- if (line.startsWith("From ")) {
- writer.write(">" + line);
- logger.log(DEBUG,
- "Fix line " + lineNumber + " in " + EmailUtils.describe(sourceMm) + ": " + line);
- } else {
- writer.write(line);
- }
- writer.newLine();
- }
- } catch (IOException e) {
- logger.log(ERROR, "Error around line " + lineNumber + " of " + tmpFileSource);
- throw e;
- }
- }
-
- MboxMessage mboxMessage = new MboxMessage((MboxFolder) targetFolder, ih,
- new SharedFileInputStream(tmpFileTarget.toFile()), sourceMm.getMessageNumber(),
- EmailUtils.getUnixFrom(sourceMm), true);
- targetMessages[j] = mboxMessage;
-
- // clean up
- Files.delete(tmpFileSource);
- Files.delete(tmpFileTarget);
- }
- targetFolder.appendMessages(targetMessages);
-
- }
-
- /** Save body parts and attachments as plain files. */
- protected void savePartsAsFiles(Object content, Path fileBase) throws IOException, MessagingException {
- OutputStream out = null;
- InputStream in = null;
- try {
- if (content instanceof Multipart) {
- Multipart multi = ((Multipart) content);
- int parts = multi.getCount();
- for (int j = 0; j < parts; ++j) {
- MimeBodyPart part = (MimeBodyPart) multi.getBodyPart(j);
- if (part.getContent() instanceof Multipart) {
- // part-within-a-part, do some recursion...
- savePartsAsFiles(part.getContent(), fileBase);
- } else {
- String extension = "";
- if (part.isMimeType("text/html")) {
- extension = "html";
- } else {
- if (part.isMimeType("text/plain")) {
- extension = "txt";
- } else {
- // Try to get the name of the attachment
- extension = part.getDataHandler().getName();
- }
- }
- String filename = fileBase + "." + extension;
- System.out.println("... " + filename);
- out = new FileOutputStream(new File(filename));
- in = part.getInputStream();
- int k;
- while ((k = in.read()) != -1) {
- out.write(k);
- }
- }
- }
- }
- } finally {
- if (in != null) {
- in.close();
- }
- if (out != null) {
- out.flush();
- out.close();
- }
- }
- }
-
- public void setSourceServer(String sourceServer) {
- this.sourceServer = sourceServer;
- }
-
- public void setSourceUsername(String sourceUsername) {
- this.sourceUsername = sourceUsername;
- }
-
- public void setSourcePassword(String sourcePassword) {
- this.sourcePassword = sourcePassword;
- }
-
- public void setTargetServer(String targetServer) {
- this.targetServer = targetServer;
- }
-
- public void setTargetUsername(String targetUsername) {
- this.targetUsername = targetUsername;
- }
-
- public void setTargetPassword(String targetPassword) {
- this.targetPassword = targetPassword;
- }
-
- public static void main(String args[]) throws Exception {
- if (args.length < 6)
- throw new IllegalArgumentException(
- "usage: <source IMAP server> <source username> <source password> <target IMAP server> <target username> <target password>");
- String sourceServer = args[0];
- String sourceUsername = args[1];
- String sourcePassword = args[2];
- String targetServer = args[3];
- String targetUsername = args[4];
- String targetPassword = args[5];
-
- EmailMigration emailMigration = new EmailMigration();
- emailMigration.setSourceServer(sourceServer);
- emailMigration.setSourceUsername(sourceUsername);
- emailMigration.setSourcePassword(sourcePassword);
- emailMigration.setTargetServer(targetServer);
- emailMigration.setTargetUsername(targetUsername);
- emailMigration.setTargetPassword(targetPassword);
-
- emailMigration.process();
- }
-}
+++ /dev/null
-package org.argeo.slc.mail;
-
-import java.util.Date;
-
-import javax.mail.Address;
-import javax.mail.Flags;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-
-/** Utilities around emails. */
-public class EmailUtils {
- public final static String INBOX = "Inbox";
- public final static String INBOX_UPPER_CASE = "INBOX";
- public final static String MESSAGE_ID = "Message-ID";
-
- public static String getMessageId(Message msg) {
- try {
- return msg instanceof MimeMessage ? ((MimeMessage) msg).getMessageID() : "<N/A>";
- } catch (MessagingException e) {
- throw new IllegalStateException("Cannot extract message id from " + msg, e);
- }
- }
-
- public static String describe(Message msg) {
- try {
- return "Message " + msg.getMessageNumber() + " " + msg.getSentDate().toInstant() + " " + getMessageId(msg);
- } catch (MessagingException e) {
- throw new IllegalStateException("Cannot describe " + msg, e);
- }
- }
-
- static void setHeadersFromFlags(MimeMessage msg, Flags flags) {
- try {
- StringBuilder status = new StringBuilder();
- if (flags.contains(Flags.Flag.SEEN))
- status.append('R');
- if (!flags.contains(Flags.Flag.RECENT))
- status.append('O');
- if (status.length() > 0)
- msg.setHeader("Status", status.toString());
- else
- msg.removeHeader("Status");
-
- boolean sims = false;
- String s = msg.getHeader("X-Status", null);
- // is it a SIMS 2.0 format X-Status header?
- sims = s != null && s.length() == 4 && s.indexOf('$') >= 0;
- //status.setLength(0);
- if (flags.contains(Flags.Flag.DELETED))
- status.append('D');
- else if (sims)
- status.append('$');
- if (flags.contains(Flags.Flag.FLAGGED))
- status.append('F');
- else if (sims)
- status.append('$');
- if (flags.contains(Flags.Flag.ANSWERED))
- status.append('A');
- else if (sims)
- status.append('$');
- if (flags.contains(Flags.Flag.DRAFT))
- status.append('T');
- else if (sims)
- status.append('$');
- if (status.length() > 0)
- msg.setHeader("X-Status", status.toString());
- else
- msg.removeHeader("X-Status");
-
- String[] userFlags = flags.getUserFlags();
- if (userFlags.length > 0) {
- status.setLength(0);
- for (int i = 0; i < userFlags.length; i++)
- status.append(userFlags[i]).append(' ');
- status.setLength(status.length() - 1); // smash trailing space
- msg.setHeader("X-Keywords", status.toString());
- }
- if (flags.contains(Flags.Flag.DELETED)) {
- s = msg.getHeader("X-Dt-Delete-Time", null);
- if (s == null)
- // XXX - should be time
- msg.setHeader("X-Dt-Delete-Time", "1");
- }
- } catch (MessagingException e) {
- // ignore it
- }
- }
-
- protected static String getUnixFrom(MimeMessage msg) {
- Address[] afrom;
- String from;
- Date ddate;
- String date;
- try {
- if ((afrom = msg.getFrom()) == null ||
- !(afrom[0] instanceof InternetAddress) ||
- (from = ((InternetAddress)afrom[0]).getAddress()) == null)
- from = "UNKNOWN";
- if ((ddate = msg.getReceivedDate()) == null ||
- (ddate = msg.getSentDate()) == null)
- ddate = new Date();
- } catch (MessagingException e) {
- from = "UNKNOWN";
- ddate = new Date();
- }
- date = ddate.toString();
- // date is of the form "Sat Aug 12 02:30:00 PDT 1995"
- // need to strip out the timezone
- return "From " + from + " " +
- date.substring(0, 20) + date.substring(24);
- }
-
- /** Singleton. */
- private EmailUtils() {
- }
-}
package org.argeo.slc.runtime;
import org.apache.commons.cli.Option;
-import org.argeo.slc.cli.CommandsCli;
-import org.argeo.slc.cli.fs.FsCommands;
+import org.argeo.cms.cli.CommandsCli;
import org.argeo.slc.cli.posix.PosixCommands;
/** Argeo command line tools. */
Option.builder("D").hasArgs().argName("property=value").desc("use value for given property").build());
addCommandsCli(new PosixCommands("posix"));
- addCommandsCli(new FsCommands("fs"));
+// addCommandsCli(new FsCommands("fs"));
// addCommandsCli(new JcrCommands("jcr"));
}
+++ /dev/null
-package org.argeo.slc.sync;
-
-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<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 {
- 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<Path> getSyncResult() {
- return syncResult;
- }
-
-}
+++ /dev/null
-package org.argeo.slc.sync;
-
-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<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 FsSyncUtils() {
-
- }
-}
+++ /dev/null
-package org.argeo.slc.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();
- }
-
- }
-}