From 059ab0ba73e74269a046005af70310f42945f806 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 16 May 2022 07:21:53 +0200 Subject: [PATCH] Dispatch code to CMS and Suite --- .../ext/test/org/argeo/fs/FsUtilsTest.java | 51 -- .../argeo/slc/cli/CommandArgsException.java | 32 -- .../slc/cli/CommandRuntimeException.java | 35 -- .../src/org/argeo/slc/cli/CommandsCli.java | 131 ----- .../org/argeo/slc/cli/DescribedCommand.java | 55 -- .../src/org/argeo/slc/cli/HelpCommand.java | 143 ----- .../src/org/argeo/slc/cli/fs/FileSync.java | 102 ---- .../src/org/argeo/slc/cli/fs/FsCommands.java | 18 - .../src/org/argeo/slc/cli/fs/PathSync.java | 61 --- .../org/argeo/slc/cli/fs/SyncFileVisitor.java | 32 -- .../org/argeo/slc/cli/fs/package-info.java | 2 - .../src/org/argeo/slc/cli/package-info.java | 2 - .../src/org/argeo/slc/cli/posix/Echo.java | 2 +- .../argeo/slc/cli/posix/PosixCommands.java | 2 +- .../org/argeo/slc/mail/EmailMigration.java | 503 ------------------ .../src/org/argeo/slc/mail/EmailUtils.java | 118 ---- .../src/org/argeo/slc/runtime/ArgeoCli.java | 5 +- .../argeo/slc/sync/BasicSyncFileVisitor.java | 162 ------ .../src/org/argeo/slc/sync/FsSyncUtils.java | 62 --- .../src/org/argeo/slc/sync/SyncResult.java | 101 ---- 20 files changed, 4 insertions(+), 1615 deletions(-) delete mode 100644 org.argeo.slc.runtime/ext/test/org/argeo/fs/FsUtilsTest.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandArgsException.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandRuntimeException.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandsCli.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/DescribedCommand.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/HelpCommand.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FileSync.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FsCommands.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/PathSync.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/SyncFileVisitor.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/package-info.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/cli/package-info.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailMigration.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailUtils.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/sync/BasicSyncFileVisitor.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/sync/FsSyncUtils.java delete mode 100644 org.argeo.slc.runtime/src/org/argeo/slc/sync/SyncResult.java diff --git a/org.argeo.slc.runtime/ext/test/org/argeo/fs/FsUtilsTest.java b/org.argeo.slc.runtime/ext/test/org/argeo/fs/FsUtilsTest.java deleted file mode 100644 index 5d31f4aa1..000000000 --- a/org.argeo.slc.runtime/ext/test/org/argeo/fs/FsUtilsTest.java +++ /dev/null @@ -1,51 +0,0 @@ -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; - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandArgsException.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandArgsException.java deleted file mode 100644 index 4d4d759d2..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandArgsException.java +++ /dev/null @@ -1,32 +0,0 @@ -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; - } - -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandRuntimeException.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandRuntimeException.java deleted file mode 100644 index 907254456..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandRuntimeException.java +++ /dev/null @@ -1,35 +0,0 @@ -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 arguments; - - public CommandRuntimeException(Throwable e, DescribedCommand command, List arguments) { - this(null, e, command, arguments); - } - - public CommandRuntimeException(String message, DescribedCommand command, List arguments) { - this(message, null, command, arguments); - } - - public CommandRuntimeException(String message, Throwable e, DescribedCommand command, List 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 getArguments() { - return arguments; - } - -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandsCli.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandsCli.java deleted file mode 100644 index 5146fb731..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/CommandsCli.java +++ /dev/null @@ -1,131 +0,0 @@ -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 { - public final static String HELP = "help"; - - private final String commandName; - private Map, ?>> commands = new TreeMap<>(); - - protected final Options options = new Options(); - - public CommandsCli(String commandName) { - this.commandName = commandName; - } - - @Override - public Object apply(List args) { - String cmd = null; - List newArgs = new ArrayList<>(); - try { - CommandLineParser clParser = new DefaultParser(); - CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true); - List 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, ?> 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, ?> 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 getSubCommands() { - return commands.keySet(); - } - - public Function, ?> getCommand(String command) { - return commands.get(command); - } - - public HelpCommand getHelpCommand() { - return (HelpCommand) getCommand(HELP); - } - - public Function, 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); - } - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/DescribedCommand.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/DescribedCommand.java deleted file mode 100644 index fc1b13947..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/DescribedCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -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 extends Function, T> { - default Options getOptions() { - return new Options(); - } - - String getDescription(); - - default String getUsage() { - return null; - } - - default String getExamples() { - return null; - } - - default CommandLine toCommandLine(List 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); - } - } - -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/HelpCommand.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/HelpCommand.java deleted file mode 100644 index 8400d0502..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/HelpCommand.java +++ /dev/null @@ -1,143 +0,0 @@ -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 { - 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 args) { - StringWriter out = new StringWriter(); - - if (args.size() == 0) {// overview - printHelp(commandsCli, out); - } else { - String cmd = args.get(0); - Function, ?> 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, ?> 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, ?> 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(); - } - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FileSync.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FileSync.java deleted file mode 100644 index dfff27ce6..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FileSync.java +++ /dev/null @@ -1,102 +0,0 @@ -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> { - 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 apply(List t) { - try { - CommandLine line = toCommandLine(t); - List 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 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"; - } - -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FsCommands.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FsCommands.java deleted file mode 100644 index cab3c1e2b..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/FsCommands.java +++ /dev/null @@ -1,18 +0,0 @@ -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"; - } - -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/PathSync.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/PathSync.java deleted file mode 100644 index 844af0154..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/PathSync.java +++ /dev/null @@ -1,61 +0,0 @@ -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> { - 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.slc.runtime/src/org/argeo/slc/cli/fs/SyncFileVisitor.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/SyncFileVisitor.java deleted file mode 100644 index 43af11144..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/SyncFileVisitor.java +++ /dev/null @@ -1,32 +0,0 @@ -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)); - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/package-info.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/package-info.java deleted file mode 100644 index 8c61d93c6..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/fs/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** File system CLI commands. */ -package org.argeo.slc.cli.fs; \ No newline at end of file diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/package-info.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/package-info.java deleted file mode 100644 index 0216a288d..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Command line API. */ -package org.argeo.slc.cli; \ No newline at end of file diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java index a479e96d1..d773760bc 100644 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java +++ b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java @@ -5,7 +5,7 @@ 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.DescribedCommand; +import org.argeo.cms.cli.DescribedCommand; public class Echo implements DescribedCommand { diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java index 67544108d..bb5920e55 100644 --- a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java +++ b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java @@ -1,6 +1,6 @@ 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 { diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailMigration.java b/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailMigration.java deleted file mode 100644 index 7826cae79..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailMigration.java +++ /dev/null @@ -1,503 +0,0 @@ -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 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: "); - 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(); - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailUtils.java b/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailUtils.java deleted file mode 100644 index 69655471b..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/mail/EmailUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -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() : ""; - } 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() { - } -} diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java b/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java index 40470fea0..3e62f575b 100644 --- a/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java +++ b/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java @@ -1,8 +1,7 @@ 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. */ @@ -16,7 +15,7 @@ public class ArgeoCli extends CommandsCli { 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")); } diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/sync/BasicSyncFileVisitor.java b/org.argeo.slc.runtime/src/org/argeo/slc/sync/BasicSyncFileVisitor.java deleted file mode 100644 index 066812d16..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/sync/BasicSyncFileVisitor.java +++ /dev/null @@ -1,162 +0,0 @@ -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 { - // 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.slc.runtime/src/org/argeo/slc/sync/FsSyncUtils.java b/org.argeo.slc.runtime/src/org/argeo/slc/sync/FsSyncUtils.java deleted file mode 100644 index 4321778ec..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/sync/FsSyncUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -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() { - @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.slc.runtime/src/org/argeo/slc/sync/SyncResult.java b/org.argeo.slc.runtime/src/org/argeo/slc/sync/SyncResult.java deleted file mode 100644 index 22a2f5676..000000000 --- a/org.argeo.slc.runtime/src/org/argeo/slc/sync/SyncResult.java +++ /dev/null @@ -1,101 +0,0 @@ -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 { - 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(); - } - - } -} -- 2.30.2