diff --git a/README.adoc b/README.adoc index 7b9e57ca2..0676987af 100644 --- a/README.adoc +++ b/README.adoc @@ -135,7 +135,7 @@ Usage: jamal [options] input output -close= the macro closing string -T7 use {% and %} as macro opening and closing -depth= directory traversal depth, default is infinite - -debug= type:port, usually http:8080 + -debug= type:port, http:8080 by default when the value is skipped -include= file name regex pattern to include into the processing -exclude= file name regex pattern to exclude from the processing -source= source directory to start the processing diff --git a/README.jrf b/README.jrf index 9688d24c5..64ac134a5 100644 --- a/README.jrf +++ b/README.jrf @@ -1,5 +1,5 @@ # This is a Jamal reference file containing serialized base64 encoded macros -# Created: 2024-11-19 15:01:30 +0100 +# Created: 2024-12-06 11:05:02 +0100 # id|openStr|closeStr|verbatim|tailParameter|pure|content|parameters # TOC VE9D|eyU=|JX0=|0|0|0|Ci4gPDxJbnN0YWxsYXRpb24+PgouIDw8R1M+PgouIDw8Q29uZmlndXJhdGlvbj4+Ci4gPDxGZWF0dXJlcz4+Ci4gPDxDb250cmlidXRpbmc+PgouIDw8RG9jdW1lbnRhdGlvbj4+Ci4gPDxMaWNlbnNlPj4KLiA8PENoYW5nZWxvZz4+Ci4gPDxSb2FkbWFwPj4KLiA8PFN1cHBvcnQ+PgouIDw8RkFRPj4KLiA8PE1haW50ZW5hbmNlPj4=| diff --git a/RODMAP.adoc b/ROADMAP.adoc similarity index 100% rename from RODMAP.adoc rename to ROADMAP.adoc diff --git a/RODMAP.adoc.jam b/ROADMAP.adoc.jam similarity index 99% rename from RODMAP.adoc.jam rename to ROADMAP.adoc.jam index 6b410f491..211c20ebf 100644 --- a/RODMAP.adoc.jam +++ b/ROADMAP.adoc.jam @@ -1,5 +1,5 @@ = JAMAL ROADMAP -{%@define a=1%} + Rudimentary description of features that are to be developed in the future. The list is not listed in order of priority, and the list is not a promise or guarantee. If you feel that there is some feature here missing, then open a GitHub ticket and suggest the missing feature. diff --git a/documentation/macros/debug.adoc b/documentation/macros/debug.adoc index 01850ec18..285192825 100644 --- a/documentation/macros/debug.adoc +++ b/documentation/macros/debug.adoc @@ -14,7 +14,7 @@ The macro has the following syntax: .Jamal source [source] ---- -{@debug on/off using="..."} +{@debug [on/off using="..."]} ---- It is important to note, it will only work if the debugger is on the module path or on the classpath. @@ -27,6 +27,9 @@ The macro has the following options: * `using` (aliases `debugger`, `selector`) can specify the debugger connection string. This is the same connection string that you can use in the environment variable `JAMAL_DEBUG` or system property. ++ +Currently, the only implemented debugger is the one using HTTP, and the connection string is `http:8080` or whatever port instead of 8080 you want to use. + + You can switch off and on the debugger inside the input using the options `on` and `off`. diff --git a/documentation/macros/debug.adoc.jam b/documentation/macros/debug.adoc.jam index 7cad1f47c..ec9a933c5 100644 --- a/documentation/macros/debug.adoc.jam +++ b/documentation/macros/debug.adoc.jam @@ -9,7 +9,7 @@ It is an extra way to start the debugger in case setting an environment variable The macro has the following syntax: {%sample/ -{@debug on/off using="..."} +{@debug [on/off using="..."]} %} It is important to note, it will only work if the debugger is on the module path or on the classpath. @@ -22,6 +22,9 @@ The macro has the following options: * `using` (aliases `debugger`, `selector`) can specify the debugger connection string. This is the same connection string that you can use in the environment variable {%JAMAL_DEBUG_ENV%} or system property. ++ +Currently, the only implemented debugger is the one using HTTP, and the connection string is `http:8080` or whatever port instead of 8080 you want to use. + + You can switch off and on the debugger inside the input using the options `on` and `off`. diff --git a/jamal-api/src/main/java/javax0/jamal/api/Processor.java b/jamal-api/src/main/java/javax0/jamal/api/Processor.java index 30d29e421..a33df2c4b 100644 --- a/jamal-api/src/main/java/javax0/jamal/api/Processor.java +++ b/jamal-api/src/main/java/javax0/jamal/api/Processor.java @@ -383,8 +383,12 @@ interface FileReader { * Tries to read the file, decides on redirect or do nothing. * * @param fileName the original name of the file - * @return the structure containing the result, which is nothing, the final name of the file or the content of - * the file + * @return the structure containing the result, which is + *
    + *
  • nothing, + *
  • the final name of the file, or + *
  • the content of the file + *
*/ IOHookResult read(final String fileName); diff --git a/jamal-cmd/pom.jam b/jamal-cmd/pom.jam index 238b233a1..8e5ac41d1 100644 --- a/jamal-cmd/pom.jam +++ b/jamal-cmd/pom.jam @@ -36,7 +36,7 @@ } {dependencies# - {#for MODULE in ({modules:DEFAULT_JAMAL_MODULES},word)= + {#for MODULE in ({modules:DEFAULT_JAMAL_MODULES},word,{modules:DEBUG})= {dependency|{GROUPID}|jamal-MODULE}} {dependency :{GROUPID}:jamal-testsupport} {#for MODULE in (api,engine)= diff --git a/jamal-cmd/pom.xml b/jamal-cmd/pom.xml index fbeff5e39..bc84948f4 100644 --- a/jamal-cmd/pom.xml +++ b/jamal-cmd/pom.xml @@ -140,6 +140,10 @@ com.javax0.jamal jamal-word + + com.javax0.jamal + jamal-debug + com.javax0.jamal jamal-testsupport diff --git a/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java b/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java index e91c16321..1db44c907 100644 --- a/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java +++ b/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java @@ -81,7 +81,7 @@ public static void main(String[] args) { " -close= the macro closing string\n" + " -T7 use {% and %} as macro opening and closing\n" + " -depth= directory traversal depth, default is infinite\n" + - " -debug= type:port, usually http:8080\n" + + " -debug= type:port, http:8080 by default when the value is skipped\n" + " -include= file name regex pattern to include into the processing\n" + " -exclude= file name regex pattern to exclude from the processing\n" + " -source= source directory to start the processing\n" + @@ -98,7 +98,12 @@ public static void main(String[] args) { return; } if (params.get("debug").isPresent()) { - EnvironmentVariables.setenv(EnvironmentVariables.JAMAL_DEBUG_ENV, params.get("debug").get()); + final var value = params.get("debug").get(); + if( "true".equals(value) || value.isEmpty() ){ + EnvironmentVariables.setenv(EnvironmentVariables.JAMAL_DEBUG_ENV, "http:8080"); + } else { + EnvironmentVariables.setenv(EnvironmentVariables.JAMAL_DEBUG_ENV, value); + } } if (Arrays.stream("include,exclude,source,target,from,to,depth".split(",")).map(params::get).anyMatch(Optional::isPresent)) { final var sourceDirectory = params.get("source").orElse("."); diff --git a/jamal-cmd/src/test/java/javax0/jamal/cmd/TestJamalMain.java b/jamal-cmd/src/test/java/javax0/jamal/cmd/TestJamalMain.java index 08d537906..c27c3f998 100644 --- a/jamal-cmd/src/test/java/javax0/jamal/cmd/TestJamalMain.java +++ b/jamal-cmd/src/test/java/javax0/jamal/cmd/TestJamalMain.java @@ -72,6 +72,7 @@ public void testConvertMultipleFiles() { () -> Assertions.assertTrue(Files.exists(Paths.get("target/test-classes/test3"))) ); } + @Test @DisplayName("Command line converts a single docx file") public void testConvertSingleDocFile() { @@ -80,4 +81,13 @@ public void testConvertSingleDocFile() { () -> Assertions.assertTrue(Files.exists(Paths.get("target/test-classes/test1.docx"))) ); } + + @DisplayName("AdHoc test to support debugging") + public void testAdHocTest() { + final var out = jamal("-debug=", "../jamal-test/TEST_PLAYGROUND.md.jam", "../jamal-test/TEST_PLAYGROUND.markdown").replaceAll("\\\\", "/"); + Assertions.assertAll( + () -> Assertions.assertTrue(Files.exists(Paths.get("target/test-classes/test1.docx"))) + ); + } + } diff --git a/jamal-debug/src/main/java/javax0/jamal/debugger/HttpServerDebugger.java b/jamal-debug/src/main/java/javax0/jamal/debugger/HttpServerDebugger.java index 9c7004f4b..56a1ccd6f 100644 --- a/jamal-debug/src/main/java/javax0/jamal/debugger/HttpServerDebugger.java +++ b/jamal-debug/src/main/java/javax0/jamal/debugger/HttpServerDebugger.java @@ -15,6 +15,12 @@ import static java.net.HttpURLConnection.*; +/** + * Implementation of the {@link Debugger} interface using an HTTP server to interact with + * a debugging client. This debugger allows controlling the execution of a Jamal processor + * via HTTP requests, enabling features like stepping through macros, viewing internal + * states, and setting breakpoints. + */ public class HttpServerDebugger implements Debugger, AutoCloseable { private static final String MIME_PLAIN = "text/plain"; public static final String MIME_APPLICATION_JSON = "application/json"; @@ -25,6 +31,10 @@ private enum Method { GET, POST } + /** + * Enum representing the available debugger commands, their corresponding URL endpoints, + * and the HTTP method required to invoke them. + */ private enum Command { ALL("all", Method.GET), VERSION("version", Method.GET), @@ -53,7 +63,7 @@ private enum Command { } /** - * The thread that manages an HTTP request utilizes this queue to dispatch a task to the Jamal main thread. + * The thread that manages an HTTP request uses this queue to dispatch a task to the Jamal main thread. *

* Given that this server is not designed for heavy-duty use, the queue size is limited to one. * There is no need to increase this capacity, as the server is intended to handle only one client, with each @@ -96,8 +106,8 @@ boolean isCancelled() { } /** - * After the debugger was done it may wait for acknowledgement. For example asking the debugger to quit or run - * may result the main Jamal thread to finish before the http server thread services the client sending the + * After the debugger was done, it may wait for acknowledgement. For example, asking the debugger to quit or run + * may result in the main Jamal thread to finish before the http server thread services the client sending the * response. In that case the client would not get the response. To avoid that these commands call this {@code * #waitForAck()} method that will wait until the other thread invokes {@link #acknowledge()}. That is called by * the HTTP server when the content was sent to the client and the channel was closed. @@ -113,7 +123,7 @@ void waitForAck() { /** * The web service thread will call this method to wait for the debugger thread to call {@link #done()}. The * method {@link #done()} is invoked when the debugger has finished the processing, put all the result into the - * task and the http server can serve the client with this information. + * task, and the http server can serve the client with this information. * * @throws InterruptedException if the thread was interrupted */ @@ -209,7 +219,7 @@ private void addToResponse(Task task, Map response, Command comm private void handle() { if (state == RunState.RUN && handleState.equals("BEFORE")) { for (final var breakpoint : breakpoints) { - if (breakpoint != null && breakpoint.length() > 0 && macros.contains(breakpoint)) { + if (breakpoint != null && !breakpoint.isEmpty() && macros.contains(breakpoint)) { state = RunState.STEP_IN; break; } @@ -454,6 +464,7 @@ public int affinity(String s) { } private HttpServer server; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); private final Properties mimeTypes = new Properties(); @Override @@ -483,7 +494,7 @@ public void init(Debugger.Stub stub) throws Exception { createContext(server, Command.STEP_OUT); createContext(server, Command.QUIT); server.createContext("/client", e -> { - if (client == null || client.length() == 0) { + if (client == null || client.isEmpty()) { respond(e, HTTP_OK, MIME_PLAIN, e.getRemoteAddress().getHostString()); } else { respond(e, HTTP_NOT_FOUND, MIME_PLAIN, "404"); @@ -491,18 +502,19 @@ public void init(Debugger.Stub stub) throws Exception { } ); createStaticContext(server); - server.setExecutor(Executors.newSingleThreadExecutor()); + server.setExecutor(executor); server.start(); } @Override public void close() { server.stop(1); + executor.shutdownNow(); } private void createStaticContext(HttpServer server) { server.createContext("/", (e) -> { - if (client != null && client.length() > 0 && !Objects.equals(e.getRemoteAddress().getHostString(), client)) { + if (client != null && !client.isEmpty() && !Objects.equals(e.getRemoteAddress().getHostString(), client)) { respond(e, HTTP_UNAUTHORIZED, MIME_PLAIN, ""); return; } @@ -511,7 +523,7 @@ private void createStaticContext(HttpServer server) { return; } var file = e.getRequestURI().toString().substring(1); - if (file.length() == 0) { + if (file.isEmpty()) { file = "index.html"; } final var extensionStart = file.lastIndexOf('.'); @@ -550,7 +562,7 @@ private void createContext(HttpServer server, Command command) { respond(e, HTTP_NOT_FOUND, MIME_PLAIN, ""); return; } - if (client != null && client.length() > 0 && !Objects.equals(e.getRemoteAddress().getHostString(), client)) { + if (client != null && !client.isEmpty() && !Objects.equals(e.getRemoteAddress().getHostString(), client)) { respond(e, HTTP_UNAUTHORIZED, MIME_PLAIN, ""); return; } diff --git a/jamal-debug/src/main/java/javax0/jamal/debugger/JsonConverter.java b/jamal-debug/src/main/java/javax0/jamal/debugger/JsonConverter.java index cbda00bec..d87407431 100644 --- a/jamal-debug/src/main/java/javax0/jamal/debugger/JsonConverter.java +++ b/jamal-debug/src/main/java/javax0/jamal/debugger/JsonConverter.java @@ -22,7 +22,7 @@ public class JsonConverter { *

* When you are developing a library, you should consider the same costs. However, there is a multiplication factor * when you think of the library version change and security screening and follow-up in this case. This part of the - * cost, which uses an external library heavier, should be multiplied by the number of installation users will + * cost, which uses an external library heavily, should be multiplied by the number of installation users will * utilize your library. It means that you should consider using an external library *

  • if you intend to use a lot of features (the development is not 30min), *
  • you expect the library to be highly stable, rarely changing, not even for security reasons, diff --git a/jamal-engine/src/main/java/javax0/jamal/engine/debugger/DebuggerFactory.java b/jamal-engine/src/main/java/javax0/jamal/engine/debugger/DebuggerFactory.java index 473059f4f..57f3960f1 100644 --- a/jamal-engine/src/main/java/javax0/jamal/engine/debugger/DebuggerFactory.java +++ b/jamal-engine/src/main/java/javax0/jamal/engine/debugger/DebuggerFactory.java @@ -37,11 +37,9 @@ public class DebuggerFactory { */ public static Debugger build(Processor processor) { final var s = EnvironmentVariables.getenv(EnvironmentVariables.JAMAL_DEBUG_ENV).orElse(""); - if (s.length() == 0) { + if (s.isEmpty()) { return new ProxyDebugger(); } - int min = Integer.MAX_VALUE; - boolean unique = true; Debugger selected = MinimumAffinityDebuggerSelector.select(Debugger.getInstances(), s); try { if (processor.getDebuggerStub().isPresent()) { diff --git a/jamal-engine/src/main/resources/META-INF/services/javax0.jamal.api.Debugger b/jamal-engine/src/main/resources/META-INF/services/javax0.jamal.api.Debugger index e47eec04c..e69de29bb 100644 --- a/jamal-engine/src/main/resources/META-INF/services/javax0.jamal.api.Debugger +++ b/jamal-engine/src/main/resources/META-INF/services/javax0.jamal.api.Debugger @@ -1 +0,0 @@ -javax0.jamal.tools.NullDebugger \ No newline at end of file diff --git a/jamal-packaging/docker/README.adoc b/jamal-packaging/docker/README.adoc index c4e89302d..bc302058b 100644 --- a/jamal-packaging/docker/README.adoc +++ b/jamal-packaging/docker/README.adoc @@ -43,6 +43,6 @@ The final step is to display how to push the container to Docker Hub. To execute Jamal from the container, you should execut ethe command - docker run --rm -v $(pwd):/workspace verhas/jamal:2.6.1-SNAPSHOT jamal_command_line_arguments + docker run --rm -v $(pwd):/workspace verhas/jamal:2.8.2-SNAPSHOT jamal_command_line_arguments to work on files that are in the current working directory. \ No newline at end of file diff --git a/jamal-snippet/README.adoc b/jamal-snippet/README.adoc index 2c3861f35..bd03c9c67 100644 --- a/jamal-snippet/README.adoc +++ b/jamal-snippet/README.adoc @@ -3816,7 +3816,7 @@ will result in the output .output [source] ---- -2024-11-19 15:01:30 +2024-12-06 11:05:03 ---- diff --git a/jamal-sql/demodb.mv.db b/jamal-sql/demodb.mv.db index 8fce0f444..23514d8a0 100644 Binary files a/jamal-sql/demodb.mv.db and b/jamal-sql/demodb.mv.db differ diff --git a/jamal-test/TEST_PLAYGROUND.adoc b/jamal-test/TEST_PLAYGROUND.adoc index 40ce0ed49..32e6ac1cd 100644 --- a/jamal-test/TEST_PLAYGROUND.adoc +++ b/jamal-test/TEST_PLAYGROUND.adoc @@ -21,9 +21,8 @@ User macro '{%biroka ...' is not defined. at /Users/verhasp/github/jamal/jamal-t javax0.jamal.engine.Processor(evalMacro:417) javax0.jamal.engine.Processor(processMacro:327) javax0.jamal.engine.Processor(process:202) - javax0.jamal.asciidoc.JamalPreprocessor(processJamal:455) - javax0.jamal.asciidoc.JamalPreprocessor(runJamalInProcess:292) - javax0.jamal.asciidoc.JamalPreprocessor(process:212) - javax0.jamal.asciidoc258.Asciidoctor2XXCompatibilityProxy(process:63) + javax0.jamal.asciidoc.JamalPreprocessor(processJamal:451) + javax0.jamal.asciidoc.JamalPreprocessor(runJamalInProcess:288) + javax0.jamal.asciidoc.JamalPreprocessor(process:205) sed -i.bak '' /Users/verhasp/github/jamal/jamal-test/TEST_PLAYGROUND.adoc.jam ---- \ No newline at end of file diff --git a/jamal-tools/src/main/java/javax0/jamal/tools/NullDebugger.java b/jamal-tools/src/main/java/javax0/jamal/tools/NullDebugger.java index f02d3dcae..9cb53744d 100644 --- a/jamal-tools/src/main/java/javax0/jamal/tools/NullDebugger.java +++ b/jamal-tools/src/main/java/javax0/jamal/tools/NullDebugger.java @@ -4,6 +4,9 @@ /** * A sample implementation of the {@link Debugger} interface that does nothing. + *

    + * Note that this implementation is used when there is no other debugger configured, and it is NOT provided as a + * service via the service loader mechanism. If you do so it will throw an exception during the service loading. */ public class NullDebugger implements Debugger { @Override @@ -28,7 +31,7 @@ public void close() { @Override public int affinity(String s) { - return Integer.MAX_VALUE-1; + throw new RuntimeException("This debugger must not be included in the META-INF list or as a service."); } @Override diff --git a/jamal-tools/src/main/java/module-info.java b/jamal-tools/src/main/java/module-info.java index bb03f8dd0..3040a92c9 100644 --- a/jamal-tools/src/main/java/module-info.java +++ b/jamal-tools/src/main/java/module-info.java @@ -2,7 +2,6 @@ import javax0.jamal.api.ResourceReader; import javax0.jamal.tools.HttpsInput; import javax0.jamal.tools.ResourceInput; -import javax0.jamal.tools.NullDebugger; module jamal.tools { uses ResourceReader; @@ -11,6 +10,5 @@ exports javax0.jamal.tools.param; requires java.scripting; requires levenshtein; - provides Debugger with NullDebugger; provides ResourceReader with ResourceInput, HttpsInput; } \ No newline at end of file diff --git a/jamal-word/src/test/resources/demoConverted.docx b/jamal-word/src/test/resources/demoConverted.docx index 13d2eed54..01654f75f 100644 Binary files a/jamal-word/src/test/resources/demoConverted.docx and b/jamal-word/src/test/resources/demoConverted.docx differ diff --git a/jamal-word/src/test/resources/includetestConverted.docx b/jamal-word/src/test/resources/includetestConverted.docx index 255066f1a..ace29e792 100644 Binary files a/jamal-word/src/test/resources/includetestConverted.docx and b/jamal-word/src/test/resources/includetestConverted.docx differ diff --git a/jamal-word/src/test/resources/pictureConverted.docx b/jamal-word/src/test/resources/pictureConverted.docx index 0934f15dd..4ceeb1d85 100644 Binary files a/jamal-word/src/test/resources/pictureConverted.docx and b/jamal-word/src/test/resources/pictureConverted.docx differ diff --git a/jamal-word/src/test/resources/sampleConverted.docx b/jamal-word/src/test/resources/sampleConverted.docx index 0419278ee..180eb6174 100644 Binary files a/jamal-word/src/test/resources/sampleConverted.docx and b/jamal-word/src/test/resources/sampleConverted.docx differ diff --git a/jamal.sh b/jamal.sh index 5ca4f6362..2f96689da 100755 --- a/jamal.sh +++ b/jamal.sh @@ -133,6 +133,7 @@ download "org.slf4j" "slf4j-api" "1.7.36" download "com.javax0.jamal" "jamal-maven-input" "2.8.2-SNAPSHOT" download "com.javax0.jamal" "jamal-jar-input" "2.8.2-SNAPSHOT" download "com.javax0.jamal" "jamal-word" "2.8.2-SNAPSHOT" +download "com.javax0.jamal" "jamal-debug" "2.8.2-SNAPSHOT" download "com.javax0.jamal" "jamal-testsupport" "2.8.2-SNAPSHOT" diff --git a/usage.txt b/usage.txt index 4f901f0b6..6ba7266ef 100644 --- a/usage.txt +++ b/usage.txt @@ -7,7 +7,7 @@ Usage: jamal [options] input output -close= the macro closing string -T7 use {% and %} as macro opening and closing -depth= directory traversal depth, default is infinite - -debug= type:port, usually http:8080 + -debug= type:port, http:8080 by default when the value is skipped -include= file name regex pattern to include into the processing -exclude= file name regex pattern to exclude from the processing -source= source directory to start the processing