From e59f097a4323674432a00af0d6bf90b325aea764 Mon Sep 17 00:00:00 2001 From: pponec Date: Sat, 11 Jan 2025 21:47:55 +0100 Subject: [PATCH 1/8] argument --files changed to the --file --- docs/PPUtils.md | 4 ++-- src/main/java/net/ponec/script/PPUtils.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/PPUtils.md b/docs/PPUtils.md index dc8f328..39db8f2 100644 --- a/docs/PPUtils.md +++ b/docs/PPUtils.md @@ -16,9 +16,9 @@ Services called from the command line for general use. - `PPUtils date-format "yyyy-MM-dd'T'HH:mm:ss.SSS"` - prints a time by a custom format - `PPUtils base64encode "file.bin"` - encode any (binary) file. - `PPUtils base64decode "file.base64"` - decode base64 encoded file (result removes extension) -- `PPUtils key json ` - get a value by the (composite) key, for example: `"a.b.c"` +- `PPUtils key json` - get a value by the (composite) key, for example: `"a.b.c"` - `PPUtils archive Archive.java File1 File2 Dir1 Dir2` - Creates a self-extracting archive in Java class source code format. Recursive directories are supported. -- `PPUtils archive Archive.java --files FileList.txt` - Creates a self-extracting archive for all files from the file list. +- `PPUtils archive Archive.java --file FileList.txt` - Creates a self-extracting archive for all files from the file list. - `PPUtils archive1 Archive.java File1 File2 File3` - Compress the archive to the one row. . Recursive directories are supported. File contents are compressed and converted using Base64. diff --git a/src/main/java/net/ponec/script/PPUtils.java b/src/main/java/net/ponec/script/PPUtils.java index fd6acf8..b08dd1a 100644 --- a/src/main/java/net/ponec/script/PPUtils.java +++ b/src/main/java/net/ponec/script/PPUtils.java @@ -53,7 +53,7 @@ *
  • {@code java PPUtils.java base64decode "file.base64"} - decode base64 encoded file (result removes extension)
  • *
  • {@code java PPUtils.java key json } - Get a value by the (composite) key, for example: {@code "a.b.c"}
  • *
  • {@code java PPUtils.java archive Archive.java File1 File2 Dir1 Dir2 } - Creates a self-extracting archive in Java class source code format. Recursive directories are supported.
  • - *
  • {@code java PPUtils.java archive Archive.java --files FileList.txt } - Creates a self-extracting archive for all files from the file list.
  • + *
  • {@code java PPUtils.java archive Archive.java --file FileList.txt } - Creates a self-extracting archive for all files from the file list.
  • *
  • {@code java PPUtils.java archive1 Archive.java File1 File2 File3 } - Compress the archive to the one row. . Recursive directories are supported.
  • * * For more information see the GitHub page. @@ -62,7 +62,7 @@ public final class PPUtils { private final String appName = getClass().getSimpleName(); - private final String appVersion = "1.2.5"; + private final String appVersion = "1.2.6"; private final Class mainClass = getClass(); @@ -319,7 +319,7 @@ public static final class ScriptArchiveBuilder { ScriptArchiveBuilder(boolean oneRowClass) { this.oneRowClass = oneRowClass; } private final String homeUrl = "https://github.com/pponec/PPScriptsForJava/blob/main/docs/PPUtils.md"; public void build(String archiveFile, Array files) throws IOException { - if ("--files".equals(files.getFirst().orElse("")) && files.size() == 2) { + if ("--file".equals(files.getFirst().orElse("")) && files.size() == 2) { files = readFiles(files.getItem(1)); } build(Path.of(archiveFile), findInnerFiles(files)); From 3c9aba26f36f295debbeb1927933810de12e3703 Mon Sep 17 00:00:00 2001 From: pponec Date: Sat, 11 Jan 2025 23:12:09 +0100 Subject: [PATCH 2/8] argument --files changed to the --file --- src/main/java/net/ponec/script/PPUtils.java | 54 ++++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/java/net/ponec/script/PPUtils.java b/src/main/java/net/ponec/script/PPUtils.java index b08dd1a..e01c4f9 100644 --- a/src/main/java/net/ponec/script/PPUtils.java +++ b/src/main/java/net/ponec/script/PPUtils.java @@ -41,9 +41,10 @@ /** * Usage and examples: *
      - *
    • {@code java PPUtils.java find main.*String java$ } - find readable files by regular expressions. Partial compliance is assessed.
    • - *
    • {@code java PPUtils.java grep main.*String PPUtils.java } - find readable file rows by a regular expression.
    • + *
    • {@code java PPUtils.java find . 'main.*String' java$ } - find readable files by regular expressions. Partial compliance is assessed.
    • + *
    • {@code java PPUtils.java grep 'main.*String' PPUtils.java } - find readable file rows by a regular expression.
    • *
    • {@code java PPUtils.java grepf 'class\s(\w+)' 'class:%s of ${file}' PPUtils.java} - grep file by grouped regexp and print result by the template.
    • + *
    • {@code java PPUtils.java grepf 'class\s(\w+)' 'class:%s of ${file}' --file file.txt} - grep file by grouped regexp and print result by the template.
    • *
    • {@code java PPUtils.java date} - prints a date by ISO format, for example: "2023-12-31"
    • *
    • {@code java PPUtils.java time} - prints hours and time, for example "2359"
    • *
    • {@code java PPUtils.java datetime} - prints datetime format "2023-12-31T2359"
    • @@ -62,7 +63,7 @@ public final class PPUtils { private final String appName = getClass().getSimpleName(); - private final String appVersion = "1.2.6"; + private final String appVersion = "1.2.7"; private final Class mainClass = getClass(); @@ -72,6 +73,8 @@ public final class PPUtils { private static final String grepSeparator = ":: "; + private static final String fileSourceArg = "--file"; + private static final boolean sortDirectoryLast = true; private final String sourceUrl = "https://raw.githubusercontent.com/pponec/PPScriptsForJava/development/src/%s/java/net/ponec/script/%s.java" @@ -99,22 +102,25 @@ void mainRun(Array args) throws Exception { final var bodyPattern = subArgs.get(-2).map(Pattern::compile).orElse(null); final var filePattern = subArgs.get(-1).map(Pattern::compile).orElseThrow(() -> new IllegalArgumentException("No file pattern")); - new FinderUtilitiy(pathComparator(), bodyPattern, "", filePattern, enforcedLinux, out) + new Finder(pathComparator(), bodyPattern, "", filePattern, enforcedLinux, out) .findFiles(file, !fileOnly && bodyPattern != null); } case "grep" -> { if (args.size() > 2) { final var bodyPattern = args.get(1).map(Pattern::compile).orElse(null); // Pattern.CASE_INSENSITIVE); - final var pathFinder = new FinderUtilitiy(pathComparator(), bodyPattern, "", null, enforcedLinux, out); - args.stream().skip(2).forEach(file -> pathFinder.grep(Path.of(file), true)); + final var finder = new Finder(pathComparator(), bodyPattern, "", null, enforcedLinux, out); + args.stream().skip(2).forEach(file -> finder.grep(Path.of(file), true)); } } case "grepf" -> { if (args.size() > 3) { final var bodyPattern = args.get(1).map(Pattern::compile).orElse(null); // Pattern.CASE_INSENSITIVE); final var bodyFormat = args.get(2).orElse(""); // Pattern.CASE_INSENSITIVE); - final var pathFinder = new FinderUtilitiy(pathComparator(), bodyPattern, bodyFormat, null, enforcedLinux, out); - args.stream().skip(3).forEach(file -> pathFinder.grep(Path.of(file), true)); + final var finder = new Finder(pathComparator(), bodyPattern, bodyFormat, null, enforcedLinux, out); + final var files = fileSourceArg.equals(args.get(3).orElse("")) && args.size() > 4 + ? readFiles(args.getItem(4)) + : args.subArray(3); + files.stream().forEach(file -> finder.grep(Path.of(file), true)); } } case "date" -> { @@ -178,6 +184,19 @@ private String currentDate(String format) { return LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)); } + private static Array readFiles(String file) { + try (Stream lines = Files.lines(Path.of(file))) { + final var result = Array.of(lines.toArray(String[]::new)); + result.stream() + .filter(f -> !Files.isRegularFile(Path.of(f))) + .findAny() + .ifPresent(f -> { throw new IllegalArgumentException("File '%s' was not found.".formatted(f)); }); + return result; + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + static final class Converters { private final PrintStream out; @@ -209,7 +228,7 @@ public void convertBase64(Path inpFile, boolean encode) throws IOException { } } - static final class FinderUtilitiy { + static final class Finder { private static String FILE_PATTEN = "${file}"; /** @Nullable */ private final Pattern bodyPattern; @@ -223,7 +242,7 @@ static final class FinderUtilitiy { private final PrintStream out; private final Comparator pathComparator; - public FinderUtilitiy(Comparator comparator, Pattern bodyPattern, String bodyFormat, Pattern filePattern, boolean enforcedLinux, PrintStream out) { + public Finder(Comparator comparator, Pattern bodyPattern, String bodyFormat, Pattern filePattern, boolean enforcedLinux, PrintStream out) { this.pathComparator = comparator; this.bodyPattern = bodyPattern; this.bodyFormat = bodyFormat; @@ -319,26 +338,13 @@ public static final class ScriptArchiveBuilder { ScriptArchiveBuilder(boolean oneRowClass) { this.oneRowClass = oneRowClass; } private final String homeUrl = "https://github.com/pponec/PPScriptsForJava/blob/main/docs/PPUtils.md"; public void build(String archiveFile, Array files) throws IOException { - if ("--file".equals(files.getFirst().orElse("")) && files.size() == 2) { + if (fileSourceArg.equals(files.getFirst().orElse("")) && files.size() == 2) { files = readFiles(files.getItem(1)); } build(Path.of(archiveFile), findInnerFiles(files)); System.out.printf("%s.%s: archive created: %s%n", PPUtils.class.getSimpleName(), getClass().getSimpleName(), archiveFile); } - private Array readFiles(String files) { - try (Stream lines = Files.lines(Path.of(files))) { - final var result = Array.of(lines.toArray(String[]::new)); - result.stream() - .filter(f -> !Files.isRegularFile(Path.of(f))) - .findAny() - .ifPresent(f -> { throw new IllegalArgumentException("File '%s' was not found.".formatted(f)); }); - return result; - } catch (IOException e) { - throw new IllegalArgumentException(e); - } - } - public Set findInnerFiles(Array items) { final var result = new TreeSet(); items.stream() From d6ac24df439185ddf4730f3d9e6cedfe3a08c2ac Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:03:27 +0100 Subject: [PATCH 3/8] Code cleaning (MyList) --- .../net/ponec/script/DirectoryBookmarks.java | 140 +++++++----------- .../ponec/script/DirectoryBookmarksTest.java | 6 +- .../{ArrayTest.java => MyListTest.java} | 2 +- 3 files changed, 54 insertions(+), 94 deletions(-) rename src/test/java/net/ponec/script/{ArrayTest.java => MyListTest.java} (99%) diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.java b/src/main/java/net/ponec/script/DirectoryBookmarks.java index b4ea155..9a78ad8 100644 --- a/src/main/java/net/ponec/script/DirectoryBookmarks.java +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.java @@ -24,7 +24,7 @@ public final class DirectoryBookmarks { final String homePage = "https://github.com/pponec/PPScriptsForJava"; final String appName = getClass().getSimpleName(); - final String appVersion = "1.9.8"; + final String appVersion = "2.0.0"; final String requiredJavaModules = "java.base,java.net.http,jdk.compiler,jdk.crypto.ec"; final char cellSeparator = '\t'; final char comment = '#'; @@ -46,10 +46,10 @@ public final class DirectoryBookmarks { final Utilities utils = new Utilities(); public static void main(String[] arguments) throws Exception { - var args = Array.of(arguments); - var enforcedLinux = args.getFirst().orElse("").equals("linux"); + var args = MyList.of(arguments); + var enforcedLinux = args.getFirst("").equals("linux"); if (enforcedLinux) { - args = args.removeFirst(); + args.remove(0); } new DirectoryBookmarks(new File(USER_HOME, ".directory-bookmarks.csv"), System.out, @@ -70,14 +70,14 @@ public static void main(String[] arguments) throws Exception { } /** The main object method */ - public void mainRun(Array args) throws Exception { - final var statement = args.getFirst().orElse(""); + public void mainRun(MyList args) throws Exception { + final var statement = args.getFirst(""); if (statement.isEmpty()) printHelpAndExit(0); switch (statement.charAt(0) == '-' ? statement.substring(1) : statement) { case "l", "list" -> { // list all directories or show the one directory - if (args.get(1).orElse("").length() > 0) { - var defaultDir = "Bookmark [%s] has no directory.".formatted(args.getItem(1)); - var dir = getDirectory(args.getItem(1), defaultDir); + if (args.get(1, "").length() > 0) { + var defaultDir = "Bookmark [%s] has no directory.".formatted(args.get(1)); + var dir = getDirectory(args.get(1), defaultDir); if (dir == defaultDir) { exit(-1, defaultDir); } else { @@ -88,24 +88,24 @@ public void mainRun(Array args) throws Exception { } } case "g", "get" -> { // get only one directory, default is the home. - var key = args.get(1).orElse(homeDirMark); - mainRun(Array.of("l", key)); + var key = args.get(1, homeDirMark); + mainRun(MyList.of("l", key)); } case "s", "save" -> { if (args.size() < 3) printHelpAndExit(-1); - var msg = args.subArray(3); - save(args.getItem(1), args.getItem(2), msg); // (dir, key, comments) + var msg = args.stream().skip(3).toList(); + save(args.get(1), args.get(2), msg); // (dir, key, comments) } case "d", "delete" -> { if (args.size() < 2) printHelpAndExit(-1); - save("", args.getItem(1), Array.of()); // (emptyDir, key, comments) + save("", args.get(1), MyList.of()); // (emptyDir, key, comments) } case "r", "read" -> { if (args.size() < 2) printHelpAndExit(-1); - removeBookmark(args.getItem(1)); + removeBookmark(args.get(1)); } case "b", "bookmarks"-> { - var dir = args.get(1).orElse(currentDir); + var dir = args.get(1, currentDir); printAllBookmarksOfDirectory(dir); } case "i", "install"-> { @@ -131,7 +131,7 @@ public void mainRun(Array args) throws Exception { } } default -> { - out.printf("Arguments are not supported: %s", String.join(" ", args.toList())); + out.printf("Arguments are not supported: %s", String.join(" ", args)); printHelpAndExit(-1); } } @@ -226,10 +226,10 @@ private String getDirectory(String key, String defaultDir) { } private void removeBookmark(String key) throws IOException { - save("", key, Array.of()); + save("", key, MyList.of()); } - private void save(String dir, String key, Array comments) throws IOException { + private void save(String dir, String key, List comments) throws IOException { if (key.indexOf(cellSeparator) >= 0 || key.indexOf(dirSeparator) >= 0) { exit(-1, "The bookmark contains a tab or a slash: '%s'".formatted(key)); } @@ -244,9 +244,9 @@ private void save(String dir, String key, Array comments) throws IOExcep if (!dir.isEmpty()) { // Function `isSystemMsWindows()` is required due a GitBash writer.append(key).append(cellSeparator).append(convertDir(true, dir, utils.isSystemMsWindows())); - if (comments.hasLength()) { + if (!comments.isEmpty()) { writer.append(cellSeparator).append(comment); - for (String comment : comments.toList()) { + for (String comment : comments) { writer.append(' ').append(comment); } } @@ -415,9 +415,10 @@ private void compile() throws Exception { var classFiles = getAllClassFiles(mainClass); // Build a JAR file: - var arguments = Array.of(jarExe, "cfe", jarFile, appName).add(classFiles); - var process = new ProcessBuilder(arguments.toArray()) - .directory(new File(classFiles[0]).getParentFile()) + var arguments = MyList.of(jarExe, "cfe", jarFile, appName); + arguments.addAll(classFiles); + var process = new ProcessBuilder(arguments) + .directory(new File(classFiles.get(0)).getParentFile()) .start(); var err = new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8); var exitCode = process.waitFor(); @@ -461,8 +462,8 @@ private String getPathOfRunningApplication() { } } - private void deleteClasses(String... classFiles) { - Stream.of(classFiles).forEach(f -> { + private void deleteClasses(List classFiles) { + classFiles.stream().forEach(f -> { try { Files.delete(Path.of(f)); } catch (IOException e) { @@ -475,14 +476,14 @@ private boolean isSystemMsWindows() { return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win"); } - private String[] getAllClassFiles(Class mainClass) { + private List getAllClassFiles(Class mainClass) { final var result = new ArrayList(); final var suffix = ".class"; result.add(mainClass.getSimpleName() + suffix); Stream.of(mainClass.getDeclaredClasses()) .map(c -> mainClass.getSimpleName() + '$' + c.getSimpleName() + suffix) .forEach(result::add); - return result.toArray(String[]::new); + return result; } private void download() throws IOException, InterruptedException { @@ -506,82 +507,41 @@ private void removePackage(Path fullJavaClass) throws IOException { } } - /** The immutable Array wrapper (from the Ujorm framework) */ - public record Array(T[] array) { + /** An extended ArrayList class */ + public static final class MyList extends ArrayList { - /** Negative index is supported */ - public Optional get(final int i) { - final var j = i >= 0 ? i : array.length + i; - return Optional.ofNullable(j >= 0 && j < array.length ? array[j] : null); + private MyList(final Collection c) { + super(c); } - /** Add new items to the new Array */ - @SuppressWarnings("unchecked") - public Array add(final T... toAdd) { - final T[] result = Arrays.copyOf(array, array.length + toAdd.length); - System.arraycopy(toAdd, 0, result, array.length, toAdd.length); - return new Array<>(result); + public T get(final int i, final T defaultValue) { + final var size = size(); + final var j = i >= 0 ? i : size + i; + final var result = j >= 0 && j < size + ? get(j) + : defaultValue; + return result != null ? result : defaultValue; } - /** Negative index is supported */ - public T getItem(final int i) { - return array[i >= 0 ? i : array.length + i]; + public T getFirst(T defaultValue) { + return get(0, defaultValue); } - public Optional getFirst() { - return get(0); + public T getLast(T defaultValue) { + return get(size() - 1, defaultValue); } - public Optional getLast() { - return get(-1); + public static MyList of(T... items) { + return new MyList(Arrays.asList(items)); } - public Array removeFirst() { - final var result = array.length > 0 ? Arrays.copyOfRange(array, 1, array.length) : array; - return new Array<>(result); - } - - public Array subArray(final int from) { - final var result = Arrays.copyOfRange(array, from, array.length); - return new Array<>(result); - } - - public List toList() { - return List.of(array); - } - - public Stream stream() { - return Stream.of(array); - } - - @SuppressWarnings("unchecked") - public T[] toArray() { - final var type = array.getClass().getComponentType(); - final var result = java.lang.reflect.Array.newInstance(type, array.length); - System.arraycopy(array, 0, result, 0, array.length); - return (T[]) result; - } - - public boolean isEmpty() { - return array.length == 0; + public static MyList of(Collection items) { + return new MyList(items); } public boolean hasLength() { - return array.length > 0; - } - - public int size() { - return array.length; - } - - @Override - public String toString() { - return List.of(array).toString(); - } - - @SuppressWarnings("unchecked") - public static Array of(T... chars) { - return new Array<>(chars); + return size() > 0; } } + } \ No newline at end of file diff --git a/src/test/java/net/ponec/script/DirectoryBookmarksTest.java b/src/test/java/net/ponec/script/DirectoryBookmarksTest.java index dd6316c..43efea2 100644 --- a/src/test/java/net/ponec/script/DirectoryBookmarksTest.java +++ b/src/test/java/net/ponec/script/DirectoryBookmarksTest.java @@ -171,8 +171,8 @@ void getSubdirTest() throws Exception { // =========== UTILS =========== - private DirectoryBookmarks.Array array(String... args) { - return DirectoryBookmarks.Array.of(args); + private DirectoryBookmarks.MyList array(String... args) { + return DirectoryBookmarks.MyList.of(args); } record DirBookContext ( @@ -203,7 +203,7 @@ public String bookmarkFile() throws IOException { public Stream bookmarkStream() throws Exception { out.reset(); - instance.mainRun(DirectoryBookmarks.Array.of("list")); + instance.mainRun(DirectoryBookmarks.MyList.of("list")); return getOutLines(); } diff --git a/src/test/java/net/ponec/script/ArrayTest.java b/src/test/java/net/ponec/script/MyListTest.java similarity index 99% rename from src/test/java/net/ponec/script/ArrayTest.java rename to src/test/java/net/ponec/script/MyListTest.java index 1bb5529..b6c76a1 100644 --- a/src/test/java/net/ponec/script/ArrayTest.java +++ b/src/test/java/net/ponec/script/MyListTest.java @@ -8,7 +8,7 @@ import static org.junit.jupiter.api.Assertions.*; -class ArrayTest { +class MyListTest { private final Array array = createArray(); private final Array empty = Array.of(); From 0475c4e3d73b0a844c3bba4c648910306b779655 Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:18:09 +0100 Subject: [PATCH 4/8] Simlify for python --- .../net/ponec/script/DirectoryBookmarks.java | 184 +----------------- 1 file changed, 7 insertions(+), 177 deletions(-) diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.java b/src/main/java/net/ponec/script/DirectoryBookmarks.java index 9a78ad8..34551f0 100644 --- a/src/main/java/net/ponec/script/DirectoryBookmarks.java +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.java @@ -4,20 +4,11 @@ package net.ponec.script; -import javax.tools.ToolProvider; import java.io.*; -import java.net.URI; -import java.net.URLDecoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.*; import java.util.regex.Pattern; -import java.util.stream.Stream; public final class DirectoryBookmarks { static final String USER_HOME = System.getProperty("user.home"); @@ -25,7 +16,6 @@ public final class DirectoryBookmarks { final String homePage = "https://github.com/pponec/PPScriptsForJava"; final String appName = getClass().getSimpleName(); final String appVersion = "2.0.0"; - final String requiredJavaModules = "java.base,java.net.http,jdk.compiler,jdk.crypto.ec"; final char cellSeparator = '\t'; final char comment = '#'; final String newLine = System.lineSeparator(); @@ -34,7 +24,6 @@ public final class DirectoryBookmarks { final String currentDirMark = "."; /** Shortcut for a home directory. Empty text is ignored. */ final String homeDirMark = "~"; - final Class mainClass = getClass(); final String sourceUrl = "https://raw.githubusercontent.com/pponec/PPScriptsForJava/%s/src/main/java/net/ponec/script/%s.java" .formatted(true ? "main" : "development", appName); final File storeName; @@ -43,7 +32,6 @@ public final class DirectoryBookmarks { final boolean exitByException; final boolean isSystemWindows; final char dirSeparator; - final Utilities utils = new Utilities(); public static void main(String[] arguments) throws Exception { var args = MyList.of(arguments); @@ -65,7 +53,7 @@ public static void main(String[] arguments) throws Exception { this.out = out; this.err = err; this.exitByException = exitByException; - this.isSystemWindows = !enforcedLinux && utils.isSystemMsWindows(); + this.isSystemWindows = !enforcedLinux && isSystemMsWindows(); this.dirSeparator = enforcedLinux ? '/' : File.separatorChar; } @@ -114,14 +102,6 @@ public void mainRun(MyList args) throws Exception { case "f", "fix"-> { fixMarksOfMissingDirectories(); } - case "c", "compile" -> { - utils.compile(); - } - case "u", "upgrade" -> { // update - utils.download(); - out.printf("%s %s was downloaded. The following compilation is recommended.%n", - appName, getScriptVersion()); - } case "v", "version"-> { var scriptVersion = getScriptVersion(); if (appVersion.equals(scriptVersion)) { @@ -143,7 +123,7 @@ public void mainRun(MyList args) throws Exception { */ private void printHelpAndExit(int status) { var out = status == 0 ? this.out : this.err; - var isJar = utils.isJar(); + var isJar = false; var javaExe = "java %s%s.%s".formatted( isJar ? "-jar " : "", appName, @@ -243,7 +223,7 @@ private void save(String dir, String key, List comments) throws IOExcept writer.append(dataHeader).append(newLine); if (!dir.isEmpty()) { // Function `isSystemMsWindows()` is required due a GitBash - writer.append(key).append(cellSeparator).append(convertDir(true, dir, utils.isSystemMsWindows())); + writer.append(key).append(cellSeparator).append(convertDir(true, dir, isSystemMsWindows())); if (!comments.isEmpty()) { writer.append(cellSeparator).append(comment); for (String comment : comments) { @@ -324,47 +304,11 @@ private void printAllBookmarksOfDirectory(String directory) throws IOException { /** Read version from the external script. */ private String getScriptVersion() { - final var pattern = Pattern.compile("String\\s+appVersion\\s*=\\s*\"(.+)\"\\s*;"); - try (var reader = new BufferedReader(new FileReader(utils.getSrcPath()))) { - return reader.lines() - .map(line -> { - final var matcher = pattern.matcher(line); - return matcher.find() ? matcher.group(1) : null; - }) - .filter(Objects::nonNull) - .findFirst() - .orElse(appVersion); - } catch (Exception e) { - return appVersion; - } + return appVersion; } private void printInstall() { - var exePath = utils.getPathOfRunningApplication().replace(USER_HOME, "$HOME"); - var javaHome = System.getProperty("java.home"); - if (isSystemWindows) { - var exe = "\"%s\\bin\\java\" --limit-modules %s %s\"%s\"" - .formatted(javaHome, requiredJavaModules, utils.isJar() ? "-jar " : "", exePath); - var msg = String.join(System.lineSeparator(), "" - , "# Shortcuts for %s v%s utilities - for the PowerShell:".formatted(appName, appVersion) - , "function directoryBookmarks { & %s $args }".formatted(exe) - , "function cdf { Set-Location -Path $(directoryBookmarks -g $args) }" - , "function sdf { directoryBookmarks s $($PWD.Path) @args }" - , "function ldf { directoryBookmarks l $args }" - , "function cpf() { cp ($args[0..($args.Length - 2)]) -Destination (ldf $args[-1]) -Force }"); - out.println(msg); - } else { - var exe = "\"%s/bin/java\" --limit-modules %s %s\"%s\"" - .formatted(javaHome, requiredJavaModules, utils.isJar() ? "-jar " : "", exePath); - var msg = String.join(System.lineSeparator(), "" - , "# Shortcuts for %s v%s utilities - for the Bash:".formatted(appName, appVersion) - , "alias directoryBookmarks='%s'".formatted(exe) - , "cdf() { cd \"$(directoryBookmarks g $1)\"; }" - , "sdf() { directoryBookmarks s \"$PWD\" \"$@\"; }" // Ready for symbolic links - , "ldf() { directoryBookmarks l \"$1\"; }" - , "cpf() { argCount=$#; cp ${@:1:$((argCount-1))} \"$(ldf ${!argCount})\"; }"); - out.println(msg); - } + out.println("todo"); } /** Convert a directory text to the store format or back */ @@ -389,122 +333,8 @@ private String convertDir(boolean toStoreFormat, String dir, boolean isSystemWin // ~ ~ ~ ~ ~ ~ ~ UTILITIES ~ ~ ~ ~ ~ ~ ~ - class Utilities { - - /** Compile the script and build it to the executable JAR file */ - private void compile() throws Exception { - if (isJar()) { - exit(-1, "Use the statement rather: java %s.java c".formatted(appName)); - } - - var scriptDir = getScriptDir(); - var jarExe = "%s/bin/jar".formatted(System.getProperty("java.home")); - var jarFile = "%s.jar".formatted(appName); - var fullJavaClass = "%s/%s.java".formatted(scriptDir, appName); - removePackage(Path.of(fullJavaClass)); - - var compiler = ToolProvider.getSystemJavaCompiler(); - if (compiler == null) { - throw new IllegalStateException("No Java Compiler is available"); - } - var error = new ByteArrayOutputStream(); - var result = compiler.run(null, null, new PrintStream(error), fullJavaClass); - if (result != 0) { - throw new IllegalStateException(error.toString()); - } - - var classFiles = getAllClassFiles(mainClass); - // Build a JAR file: - var arguments = MyList.of(jarExe, "cfe", jarFile, appName); - arguments.addAll(classFiles); - var process = new ProcessBuilder(arguments) - .directory(new File(classFiles.get(0)).getParentFile()) - .start(); - var err = new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8); - var exitCode = process.waitFor(); - if (exitCode != 0) { - throw new IllegalStateException(err); - } - - // Delete all classes: - deleteClasses(classFiles); - } - - private String getScriptDir() { - var exePath = getPathOfRunningApplication(); - return exePath.substring(0, exePath.lastIndexOf(appName) - 1); - } - - private boolean isJar() { - return getPathOfRunningApplication().toLowerCase(Locale.ENGLISH).endsWith(".jar"); - } - - /** - * Get a full path to this source Java file. - */ - private String getSrcPath() { - return "%s/%s.java".formatted(getScriptDir(), appName); - } - - private String getPathOfRunningApplication() { - final var protocol = "file:/"; - try { - final var location = mainClass.getProtectionDomain().getCodeSource().getLocation(); - var path = location.toString(); - if (isSystemWindows && path.startsWith(protocol)) { - path = path.substring(protocol.length()); - } else { - path = location.getPath(); - } - return URLDecoder.decode(path, StandardCharsets.UTF_8); - } catch (Exception e) { - return "%s.%s".formatted(appName, "java"); - } - } - - private void deleteClasses(List classFiles) { - classFiles.stream().forEach(f -> { - try { - Files.delete(Path.of(f)); - } catch (IOException e) { - throw new IllegalStateException(e); - } - }); - } - - private boolean isSystemMsWindows() { - return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win"); - } - - private List getAllClassFiles(Class mainClass) { - final var result = new ArrayList(); - final var suffix = ".class"; - result.add(mainClass.getSimpleName() + suffix); - Stream.of(mainClass.getDeclaredClasses()) - .map(c -> mainClass.getSimpleName() + '$' + c.getSimpleName() + suffix) - .forEach(result::add); - return result; - } - - private void download() throws IOException, InterruptedException { - var client = HttpClient.newHttpClient(); - var request = HttpRequest.newBuilder() - .uri(URI.create(sourceUrl)) - .build(); - var response = client.send(request, HttpResponse.BodyHandlers.ofString()); - if (response.statusCode() == 200) { - Files.writeString(Path.of(getSrcPath()), response.body()); - } else { - throw new IllegalStateException("Downloading error code: %s".formatted(response.statusCode())); - } - } - - private void removePackage(Path fullJavaClass) throws IOException { - var packageRegexp = "package %s;".formatted(mainClass.getPackageName()); - var script = Files.readString(fullJavaClass); - script = script.replaceFirst(packageRegexp, ""); - Files.writeString(fullJavaClass, script); - } + private boolean isSystemMsWindows() { + return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win"); } /** An extended ArrayList class */ From 6213872792d5443a6bd0668c941d9abe8618a8b7 Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:20:58 +0100 Subject: [PATCH 5/8] Python code --- .../net/ponec/script/DirectoryBookmarks.py | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/main/java/net/ponec/script/DirectoryBookmarks.py diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.py b/src/main/java/net/ponec/script/DirectoryBookmarks.py new file mode 100644 index 0000000..b695a15 --- /dev/null +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.py @@ -0,0 +1,108 @@ +import os +import sys +import shutil +import tempfile +from pathlib import Path + +def is_system_windows(): + return os.name == 'nt' + +class DirectoryBookmarks: + USER_HOME = str(Path.home()) + APP_NAME = "DirectoryBookmarks" + APP_VERSION = "2.0.0" + CELL_SEPARATOR = '\t' + COMMENT = '#' + NEW_LINE = '\n' + CURRENT_DIR_MARK = '.' + HOME_DIR_MARK = '~' + + def __init__(self, store_name=None, enforced_linux=False): + self.store_name = store_name or Path(self.USER_HOME) / ".directory-bookmarks.csv" + self.is_system_windows = not enforced_linux and is_system_windows() + self.dir_separator = '/' if enforced_linux else os.sep + + def main_run(self, args): + if not args: + self.print_help_and_exit(0) + statement = args[0] + if statement in ('l', 'list'): + if len(args) > 1: + key = args[1] + directory = self.get_directory(key, f"Bookmark [{key}] has no directory.") + print(directory) + else: + self.print_directories() + elif statement in ('g', 'get'): + key = args[1] if len(args) > 1 else self.HOME_DIR_MARK + self.main_run(['l', key]) + elif statement in ('s', 'save'): + if len(args) < 3: + self.print_help_and_exit(-1) + self.save(args[1], args[2], args[3:]) + elif statement in ('d', 'delete'): + if len(args) < 2: + self.print_help_and_exit(-1) + self.save("", args[1], []) + else: + print(f"Arguments are not supported: {' '.join(args)}") + self.print_help_and_exit(-1) + + def print_help_and_exit(self, status): + print(f"{self.APP_NAME} {self.APP_VERSION}") + print("Usage: python script.py [slgdr] directory bookmark optionalComment") + sys.exit(status) + + def print_directories(self): + try: + with open(self.store_name, 'r', encoding='utf-8') as file: + lines = file.readlines() + for line in sorted(lines): + if not line.startswith(self.COMMENT): + print(line.strip().replace('/', os.sep) if self.is_system_windows else line.strip()) + except FileNotFoundError: + pass + + def get_directory(self, key, default_dir): + if key == self.CURRENT_DIR_MARK: + return os.getcwd() + elif key == self.HOME_DIR_MARK: + return self.USER_HOME + try: + with open(self.store_name, 'r', encoding='utf-8') as file: + for line in file: + if line.startswith(key + self.CELL_SEPARATOR): + return line.split(self.CELL_SEPARATOR, 1)[1].strip() + except FileNotFoundError: + pass + return default_dir + + def save(self, directory, key, comments): + if self.CELL_SEPARATOR in key or os.sep in key: + print(f"Invalid bookmark key: {key}") + sys.exit(-1) + temp_file = tempfile.NamedTemporaryFile(delete=False, mode='w', encoding='utf-8') + try: + with open(self.store_name, 'r', encoding='utf-8') as file: + lines = file.readlines() + except FileNotFoundError: + lines = [] + + with open(temp_file.name, 'w', encoding='utf-8') as out_file: + out_file.write(f"{self.COMMENT} {self.APP_NAME} {self.APP_VERSION}{self.NEW_LINE}") + if directory: + line = f"{key}{self.CELL_SEPARATOR}{directory}" + if comments: + line += f"{self.CELL_SEPARATOR}{self.COMMENT} {' '.join(comments)}" + out_file.write(line + self.NEW_LINE) + for line in lines: + if not line.startswith(key + self.CELL_SEPARATOR): + out_file.write(line) + shutil.move(temp_file.name, self.store_name) + +if __name__ == "__main__": + args = sys.argv[1:] + enforced_linux = args and args[0] == "linux" + if enforced_linux: + args.pop(0) + DirectoryBookmarks(enforced_linux=enforced_linux).main_run(args) From a78cfbcef7590c26ea50709f592926b13221f90e Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:21:57 +0100 Subject: [PATCH 6/8] Python code --- src/main/java/net/ponec/script/DirectoryBookmarks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.py b/src/main/java/net/ponec/script/DirectoryBookmarks.py index b695a15..fd9b5e8 100644 --- a/src/main/java/net/ponec/script/DirectoryBookmarks.py +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.py @@ -18,7 +18,7 @@ class DirectoryBookmarks: HOME_DIR_MARK = '~' def __init__(self, store_name=None, enforced_linux=False): - self.store_name = store_name or Path(self.USER_HOME) / ".directory-bookmarks.csv" + self.store_name = store_name or Path(self.USER_HOME) / ".directory-bookmarks-py.csv" self.is_system_windows = not enforced_linux and is_system_windows() self.dir_separator = '/' if enforced_linux else os.sep From 30350ef65757b66e6b7929b4a8c244072eab2b8d Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:32:07 +0100 Subject: [PATCH 7/8] Python code --- .../java/net/ponec/script/DirectoryBookmarks.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.py b/src/main/java/net/ponec/script/DirectoryBookmarks.py index fd9b5e8..60752c7 100644 --- a/src/main/java/net/ponec/script/DirectoryBookmarks.py +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.py @@ -16,9 +16,10 @@ class DirectoryBookmarks: NEW_LINE = '\n' CURRENT_DIR_MARK = '.' HOME_DIR_MARK = '~' + UTF8='utf-8' def __init__(self, store_name=None, enforced_linux=False): - self.store_name = store_name or Path(self.USER_HOME) / ".directory-bookmarks-py.csv" + self.store_name = store_name or Path(self.USER_HOME) / ".directory-bookmarks.csv" self.is_system_windows = not enforced_linux and is_system_windows() self.dir_separator = '/' if enforced_linux else os.sep @@ -55,7 +56,7 @@ def print_help_and_exit(self, status): def print_directories(self): try: - with open(self.store_name, 'r', encoding='utf-8') as file: + with open(self.store_name, 'r', encoding=self.UTF8) as file: lines = file.readlines() for line in sorted(lines): if not line.startswith(self.COMMENT): @@ -69,7 +70,7 @@ def get_directory(self, key, default_dir): elif key == self.HOME_DIR_MARK: return self.USER_HOME try: - with open(self.store_name, 'r', encoding='utf-8') as file: + with open(self.store_name, 'r', encoding=self.UTF8) as file: for line in file: if line.startswith(key + self.CELL_SEPARATOR): return line.split(self.CELL_SEPARATOR, 1)[1].strip() @@ -81,14 +82,14 @@ def save(self, directory, key, comments): if self.CELL_SEPARATOR in key or os.sep in key: print(f"Invalid bookmark key: {key}") sys.exit(-1) - temp_file = tempfile.NamedTemporaryFile(delete=False, mode='w', encoding='utf-8') + temp_file = tempfile.NamedTemporaryFile(delete=False, mode='w', encoding=self.UTF8) try: - with open(self.store_name, 'r', encoding='utf-8') as file: + with open(self.store_name, 'r', encoding=self.UTF8) as file: lines = file.readlines() except FileNotFoundError: lines = [] - with open(temp_file.name, 'w', encoding='utf-8') as out_file: + with open(temp_file.name, 'w', encoding=self.UTF8) as out_file: out_file.write(f"{self.COMMENT} {self.APP_NAME} {self.APP_VERSION}{self.NEW_LINE}") if directory: line = f"{key}{self.CELL_SEPARATOR}{directory}" From 4d188060a024e9ef78352fe201512eb8b1814f58 Mon Sep 17 00:00:00 2001 From: "pavel.ponec" Date: Mon, 10 Mar 2025 20:34:11 +0100 Subject: [PATCH 8/8] Python code --- src/main/java/net/ponec/script/DirectoryBookmarks.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/net/ponec/script/DirectoryBookmarks.py b/src/main/java/net/ponec/script/DirectoryBookmarks.py index 60752c7..c73cb45 100644 --- a/src/main/java/net/ponec/script/DirectoryBookmarks.py +++ b/src/main/java/net/ponec/script/DirectoryBookmarks.py @@ -1,3 +1,7 @@ +# Running by Python 17: $ python3 DirectoryBookmarks.py +# Licence: Apache License, Version 2.0, https://github.com/pponec/ +# Enable PowerShell in Windows 11: Set-ExecutionPolicy unrestricted + import os import sys import shutil