From 400ee7e8295ede128e17c5e93b40145e7e48b3c4 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 10 Feb 2022 11:08:23 +0100 Subject: [PATCH] Move CLI and Sync to SLC. --- .../argeo/cms/cli/CommandArgsException.java | 32 ---- .../cms/cli/CommandRuntimeException.java | 35 ---- .../src/org/argeo/cms/cli/CommandsCli.java | 131 -------------- .../org/argeo/cms/cli/DescribedCommand.java | 55 ------ .../src/org/argeo/cms/cli/HelpCommand.java | 143 ---------------- .../src/org/argeo/cms/cli/package-info.java | 2 - .../org/argeo/util/BasicSyncFileVisitor.java | 162 ------------------ .../src/org/argeo/util/FsUtils.java | 19 -- .../src/org/argeo/util/SyncResult.java | 101 ----------- 9 files changed, 680 deletions(-) delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/CommandArgsException.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/CommandRuntimeException.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/CommandsCli.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/DescribedCommand.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/HelpCommand.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/cli/package-info.java delete mode 100644 org.argeo.util/src/org/argeo/util/BasicSyncFileVisitor.java delete mode 100644 org.argeo.util/src/org/argeo/util/SyncResult.java diff --git a/org.argeo.cms/src/org/argeo/cms/cli/CommandArgsException.java b/org.argeo.cms/src/org/argeo/cms/cli/CommandArgsException.java deleted file mode 100644 index 1f6d56bb1..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/CommandArgsException.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.argeo.cms.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.cms/src/org/argeo/cms/cli/CommandRuntimeException.java b/org.argeo.cms/src/org/argeo/cms/cli/CommandRuntimeException.java deleted file mode 100644 index ef27c1fc8..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/CommandRuntimeException.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.argeo.cms.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.cms/src/org/argeo/cms/cli/CommandsCli.java b/org.argeo.cms/src/org/argeo/cms/cli/CommandsCli.java deleted file mode 100644 index d45ea33a0..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/CommandsCli.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.argeo.cms.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.cms/src/org/argeo/cms/cli/DescribedCommand.java b/org.argeo.cms/src/org/argeo/cms/cli/DescribedCommand.java deleted file mode 100644 index cdfe1300d..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/DescribedCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.argeo.cms.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.cms/src/org/argeo/cms/cli/HelpCommand.java b/org.argeo.cms/src/org/argeo/cms/cli/HelpCommand.java deleted file mode 100644 index ab899f437..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/HelpCommand.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.argeo.cms.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.cms/src/org/argeo/cms/cli/package-info.java b/org.argeo.cms/src/org/argeo/cms/cli/package-info.java deleted file mode 100644 index 59feed1d1..000000000 --- a/org.argeo.cms/src/org/argeo/cms/cli/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Command line API. */ -package org.argeo.cms.cli; \ No newline at end of file diff --git a/org.argeo.util/src/org/argeo/util/BasicSyncFileVisitor.java b/org.argeo.util/src/org/argeo/util/BasicSyncFileVisitor.java deleted file mode 100644 index 839d38af7..000000000 --- a/org.argeo.util/src/org/argeo/util/BasicSyncFileVisitor.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.argeo.util; - -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 { - FsUtils.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.util/src/org/argeo/util/FsUtils.java b/org.argeo.util/src/org/argeo/util/FsUtils.java index 2d1363b61..b317f4bc9 100644 --- a/org.argeo.util/src/org/argeo/util/FsUtils.java +++ b/org.argeo.util/src/org/argeo/util/FsUtils.java @@ -9,25 +9,6 @@ import java.nio.file.attribute.BasicFileAttributes; /** Utilities around the standard Java file abstractions. */ public class FsUtils { - /** 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. diff --git a/org.argeo.util/src/org/argeo/util/SyncResult.java b/org.argeo.util/src/org/argeo/util/SyncResult.java deleted file mode 100644 index 0f2256b6c..000000000 --- a/org.argeo.util/src/org/argeo/util/SyncResult.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.argeo.util; - -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