Improve joinfiles subcommand.
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 25 May 2024 20:43:08 +0000 (23:43 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 25 May 2024 20:43:08 +0000 (23:43 +0300)
Add "implement idea" script as usage example.

doc/index.org
src/main/java/eu/svjatoslav/alyverkko_cli/commands/JoinFilesCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/MailCorrespondentCommand.java
tools/implement idea [new file with mode: 0755]

index 91e2d29..a1a0dae 100644 (file)
@@ -447,6 +447,10 @@ Ideas to be possibly implemented in the future:
   - What user did, when, where and how.
   - How and where did result appear.
 
+- Clarify operating system requirements.
+
+- Clarify hardware requirements.
+
 ** System operation
 
 - Implement CPU nice priority for inference processes to minimize the
@@ -462,14 +466,17 @@ Ideas to be possibly implemented in the future:
   in-progress computation. Unix process stop and continue signals
   could possibly be used.
 - Add support for speculative decoding to speed up inference.
+- Implement selftest command. It shall validate that configuration is
+  correct and all is operational. If errors are found, it should tell
+  what exactly is wrong and suggest how to fix it.
 
 ** Data management
 
-- Develop a feature to recursively aggregate files into a single
-  document using Emacs org-mode syntax, facilitating the preparation
-  of comprehensive problem statements for AI processing.
-  - Ensure that binary files are excluded from this aggregation
-    process to maintain text readability and compatibility.
+- in maildir ignore binary files, use joinfiles command as example how
+  to ignore binary files. Perhaps extract plain text file detection
+  into some utility class.
+
+- Make text editor configurable in application properties file.
 
 ** Configuration and logging
 
index ddd0665..186cbce 100644 (file)
@@ -1,7 +1,11 @@
 package eu.svjatoslav.alyverkko_cli.commands;
 
 import eu.svjatoslav.alyverkko_cli.*;
-import org.apache.commons.io.FilenameUtils;
+import eu.svjatoslav.commons.cli_helper.parameter_parser.Parser;
+import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.DirectoryOption;
+import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.NullOption;
+import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.StringOption;
+import eu.svjatoslav.commons.string.GlobMatcher;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -14,6 +18,21 @@ import static eu.svjatoslav.alyverkko_cli.configuration.Configuration.loadConfig
 
 public class JoinFilesCommand implements Command {
 
+    final Parser parser = new Parser();
+
+    public DirectoryOption sourceDirectoryOption = parser.add(new DirectoryOption("Directory to join files from"))
+            .addAliases("--src-dir", "-s").mustExist();
+
+    public StringOption patternOption = parser.add(new StringOption("Pattern to match files"))
+            .addAliases("--pattern", "-p");
+
+    public StringOption topic = parser.add(new StringOption("Topic of the joined files"))
+            .addAliases("--topic", "-t").setMandatory();
+
+    public NullOption editOption = parser.add(new NullOption("Edit the joined file using text editor"))
+            .addAliases("--edit", "-e");
+
+
     @Override
     public String getName() {
         return "joinfiles";
@@ -21,6 +40,10 @@ public class JoinFilesCommand implements Command {
 
     public Path baseDirectory;
 
+    public String pattern = null;
+
+    File outputFile;
+
     @Override
     public void execute(String[] cliArguments) throws IOException {
         configuration = loadConfiguration();
@@ -29,42 +52,66 @@ public class JoinFilesCommand implements Command {
             return;
         }
 
-        // Ask for file name to be created
-        System.out.print("Enter the output file name (without extension): ");
-        String fileName = System.console().readLine();
+        if (!parser.parse(cliArguments)) {
+            System.out.println("Failed to parse commandline arguments");
+            parser.showHelp();
+            return;
+        }
 
-        // Create the output file with .org extension
-        File outputFile = new File(FilenameUtils.normalize(fileName + ".org"));
+        // build the path to the target file that is relative to the mail directory
+        outputFile = configuration.getMailDirectory().toPath().resolve(topic.getValue() + ".org").toFile();
 
-        // create output file within the mail directory
-        outputFile = new File(configuration.getMailDirectory(), outputFile.getName());
+        if (patternOption.isPresent()) {
+            pattern = patternOption.getValue();
+            joinFiles();
+        }
 
+        if (editOption.isPresent()) {
+            // User requested to edit the file after joining
+            System.out.println("Editing the file: " + outputFile.getAbsolutePath());
+            String editorCommand = "emc " + outputFile.getAbsolutePath();
+            Runtime.getRuntime().exec(editorCommand);
+        }
 
-        try (BufferedWriter writer = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8)) {
+    }
+
+    private void joinFiles() throws IOException {
+
+        // Create or append to the target file
+        boolean appendToFile = outputFile.exists();
+
+        if (sourceDirectoryOption.isPresent()) {
+            baseDirectory = sourceDirectoryOption.getValue().toPath();
+        } else {
             baseDirectory = Paths.get(".");
-            joinFilesRecursively(baseDirectory,  writer);
         }
 
-        System.out.println("Files have been joined into: " + outputFile.getAbsolutePath());
-        System.out.println("Opening editor to edit the file...");
+        try (BufferedWriter writer = Files.newBufferedWriter(
+                outputFile.toPath(), StandardCharsets.UTF_8,
+                appendToFile ? StandardOpenOption.APPEND : StandardOpenOption.CREATE)) {
 
-        // TODO: make editor configurable
-        String command = "emc " + outputFile.getAbsolutePath();
 
-        // opening editor
-        Runtime.getRuntime().exec(command);
+            // Join files that match the pattern in the specified directory
+            joinFilesRecursively(sourceDirectoryOption.getValue().toPath(), writer);
+        }
+
+        System.out.println("Files have been joined into: " + outputFile.getAbsolutePath());
     }
 
     private void joinFilesRecursively(Path directoryToIndex, BufferedWriter writer) throws IOException {
-        DirectoryStream<Path> stream = Files.newDirectoryStream(directoryToIndex);
-
-        for (Path entry : stream) {
-            if (Files.isDirectory(entry)) {
-                joinFilesRecursively(entry,  writer);
-            } else if (Files.isRegularFile(entry)) {
-                String contentType = Files.probeContentType(entry);
-
-                if (contentType != null && contentType.startsWith("text/")) writeFile(writer, entry);
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryToIndex)) {
+            for (Path entry : stream) {
+                if (Files.isDirectory(entry)) {
+                    joinFilesRecursively(entry, writer);
+                } else if (Files.isRegularFile(entry)) {
+                    String fileName = entry.getFileName().toString();
+
+                    boolean match = GlobMatcher.match(fileName, pattern);
+                    if (match) {
+                        System.out.println("Joining file: " + fileName);
+                        writeFile(writer, entry);
+                    }
+                }
             }
         }
     }
@@ -82,7 +129,6 @@ public class JoinFilesCommand implements Command {
 
     private void writeFileHeader(BufferedWriter writer, Path entry) throws IOException {
         String relativePath = baseDirectory.relativize(entry).toString();
-        writer.write( "* file: " + relativePath + "\n\n");
+        writer.write("* file: " + relativePath + "\n\n");
     }
 }
-
index d694025..b2ef933 100644 (file)
@@ -27,12 +27,6 @@ public class MailCorrespondentCommand implements Command {
 
     private WatchService watcher;
 
-    /**
-     * The directory containing mail files.
-     */
-    DirectoryOption mailDirectoryOption = parser.add(new DirectoryOption("Directory containing mail files"))
-            .addAliases("--mail", "-m").mustExist();
-
     File mailDirectory;
 
     /**
@@ -132,7 +126,7 @@ public class MailCorrespondentCommand implements Command {
         }
 
         modelLibrary = new ModelLibrary(configuration.getModelsDirectory(), configuration.getModels());
-        mailDirectory = mailDirectoryOption.isPresent() ? mailDirectoryOption.getValue() : configuration.getMailDirectory();
+        mailDirectory = configuration.getMailDirectory();
 
         initializeFileWatcher();
 
diff --git a/tools/implement idea b/tools/implement idea
new file mode 100755 (executable)
index 0000000..02b0ceb
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# This script will prompt the user for a topic name if it is not
+# provided as an argument. Alternatively, you can run the script with
+# the desired topic name as the first argument:
+
+# implement_idea <my new topic>
+
+
+# Function to ask for the topic name if not provided
+ask_for_topic() {
+    read -p "Enter the topic name: " topic
+    echo "$topic"
+}
+
+# Main script execution
+(
+    cd "${0%/*}"
+    cd ..
+
+    # Use a default topic name or ask the user for one
+    TOPIC_NAME="${1:-$(ask_for_topic)}"
+
+    alyverkko-cli joinfiles -t "$TOPIC_NAME" --src-dir . --pattern "*.org"
+    alyverkko-cli joinfiles -t "$TOPIC_NAME" --src-dir . --pattern "*.java"
+    alyverkko-cli joinfiles -t "$TOPIC_NAME" --src-dir . --pattern "implement*"
+    alyverkko-cli joinfiles -t "$TOPIC_NAME" --edit
+
+)