From 7d4ca8253a775b195b804abea769a36dd953e240 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Sun, 27 Jun 2021 12:54:05 +0200
Subject: [PATCH] 0.2.9

- add pages documentation
- propagate jastAddList option to ragconnect
- add logIncremental to ragconnect
---
 .gitlab-ci.yml                                |  25 +++++
 build.gradle                                  |   2 +-
 pages/.gitignore                              |   2 +
 pages/custom_theme/footer.html                |  11 ++
 pages/doc/index.md                            |  69 ++++++++++++
 pages/main.py                                 |  24 ++++
 pages/mkdocs.yml                              |  17 +++
 .../testing/doc/DocumentationCreator.java     | 106 ++++++++++++++++++
 .../testing/plugin/Description.java           |  11 ++
 .../testing/plugin/JastAddConfiguration.java  |  10 ++
 .../plugin/RagConnectConfiguration.java       |  19 ++++
 .../testing/plugin/RagConnectTest.java        |   6 +
 .../testing/plugin/RelastConfiguration.java   |   8 ++
 13 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 pages/.gitignore
 create mode 100644 pages/custom_theme/footer.html
 create mode 100644 pages/doc/index.md
 create mode 100644 pages/main.py
 create mode 100644 pages/mkdocs.yml
 create mode 100644 src/main/java/org/jastadd/preprocessor/testing/doc/DocumentationCreator.java
 create mode 100644 src/main/java/org/jastadd/preprocessor/testing/plugin/Description.java

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3c94406..0852b85 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,6 +19,15 @@ build:
   script:
     - ./gradlew assemble
 
+createDoc:
+  image: openjdk:11
+  stage: build
+  script:
+    - "./gradlew :run"
+  artifacts:
+    paths:
+      - "pages/doc/config.md"
+
 publish:
   image: openjdk:11
   stage: publish
@@ -26,3 +35,19 @@ publish:
     - "./gradlew publishPluginMavenPublicationToMavenRepository"
   only:
     - master
+
+pages:
+  image: python:3.8-buster
+  stage: publish
+  needs:
+    - createDoc
+  before_script:
+    - pip install -U mkdocs mkdocs-macros-plugin mkdocs-git-revision-date-localized-plugin
+  script:
+    - cd pages && mkdocs build
+  only:
+    - dev
+    - master
+  artifacts:
+    paths:
+      - public
diff --git a/build.gradle b/build.gradle
index 0edac03..618faff 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ plugins {
 }
 
 group 'org.jastadd.preprocessor'
-version '0.2.8'
+version '0.2.9'
 
 gradlePlugin {
     plugins {
diff --git a/pages/.gitignore b/pages/.gitignore
new file mode 100644
index 0000000..0b3e404
--- /dev/null
+++ b/pages/.gitignore
@@ -0,0 +1,2 @@
+/doc/config.md
+__pycache__
diff --git a/pages/custom_theme/footer.html b/pages/custom_theme/footer.html
new file mode 100644
index 0000000..8e9d67e
--- /dev/null
+++ b/pages/custom_theme/footer.html
@@ -0,0 +1,11 @@
+{% block footer %}
+<p>{% if config.copyright %}
+    <small>{{ config.copyright }}<br></small>
+    {% endif %}
+<hr>
+Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
+{% if page and page.meta and page.meta.git_revision_date_localized %}
+<small><br><i>Last updated {{ page.meta.git_revision_date_localized }}</i></small>
+{% endif %}
+</p>
+{% endblock %}
diff --git a/pages/doc/index.md b/pages/doc/index.md
new file mode 100644
index 0000000..f1cea28
--- /dev/null
+++ b/pages/doc/index.md
@@ -0,0 +1,69 @@
+# Gradle Plugin for JastAdd preprocessors
+
+This [Gradle plugin](https://git-st.inf.tu-dresden.de/jastadd/testing) is providing means to write Gradle tasks to invoke the two preprocessors [Relast]() and [RagConnect](https://jastadd.pages.st.inf.tu-dresden.de/ragconnect) as well as [JastAdd](http://jastadd.org/) itself.
+
+To use this plugin, add the following to your `build.gradle`:
+
+```groovy
+buildscript {
+    repositories {
+        mavenCentral()
+        maven {
+            name "gitlab-maven"
+            url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
+        }
+    }
+    dependencies {
+        classpath 'org.jastadd.preprocessor:testing:0.2.8'
+    }
+}
+
+import org.jastadd.preprocessor.testing.plugin.PreprocessorPlugin
+import org.jastadd.preprocessor.testing.plugin.RagConnectTest
+
+apply plugin: PreprocessorPlugin
+```
+
+A typical usage (taken from tests used for RagConnect) looks as follows:
+
+```groovy
+task compileTreeIncremental(type: RagConnectTest) {
+    ragconnect {
+        outputDir = file('src/test/02-after-ragconnect/treeInc')
+        inputFiles = [file('src/test/01-input/tree/Test.relast'),
+                      file('src/test/01-input/tree/Test.connect')]
+        rootNode = 'Root'
+        logWrites = true
+    }
+    relast {
+        useJastAddNames = true
+        grammarName = 'src/test/03-after-relast/treeInc/treeInc'
+        serializer = 'jackson'
+    }
+    jastadd {
+        jastAddList = 'JastAddList'
+        packageName = 'treeInc.ast'
+        inputFiles = [file('src/test/01-input/tree/Test.jadd')]
+        extraOptions = ['--tracing=cache,flush',
+                        '--incremental=param',
+                        '--cache=all',
+                        '--rewrite=cnta',
+                        '--flush=full']
+    }
+}
+```
+
+Available options are listed at [configuration](/config).
+Notably, all options passed to JastAdd are also passed to the preprocessors, and generated files are handled correctly, e.g., generated aspects are passed to JastAdd automatically.
+
+The compilers to be used can be configured as follows:
+
+```groovy
+preprocessorTesting {
+    //noinspection GroovyAssignabilityCheck
+    relastCompilerLocation = '../libs/relast.jar'
+    ragconnectCompilerLocation = '../libs/ragconnect.jar'
+}
+```
+
+By default, the compilers are expected to be available in the classpath.
diff --git a/pages/main.py b/pages/main.py
new file mode 100644
index 0000000..f48dc72
--- /dev/null
+++ b/pages/main.py
@@ -0,0 +1,24 @@
+buildGradle = '../build.gradle'
+
+
+def get_version():
+    with open(buildGradle) as fd:
+        for line in fd.readlines():
+            # look for line `version 'Major.Minor.Patch'`
+            if line.startswith('version '):
+                return line[9:-2]
+    return '?'
+
+
+def define_env(env):
+    """
+    This is the hook for defining variables, macros and filters
+
+    - variables: the dictionary that contains the environment variables
+    - macro: a decorator function, to declare a macro.
+    """
+    env.conf['site_name'] = 'Gradle Plugin RelastTest ' + get_version()
+
+
+if __name__ == '__main__':
+    print(get_version())
diff --git a/pages/mkdocs.yml b/pages/mkdocs.yml
new file mode 100644
index 0000000..4b9e75b
--- /dev/null
+++ b/pages/mkdocs.yml
@@ -0,0 +1,17 @@
+site_name: Gradle Plugin RelastTest
+nav:
+  - using.md
+  - API documentation: ragdoc/index.html
+theme:
+  name: readthedocs
+  custom_dir: custom_theme/
+plugins:
+  - search
+  - git-revision-date-localized:
+      type: datetime
+      timezone: Europe/Berlin
+      locale: en
+      fallback_to_build_date: True
+  - macros
+repo_url: https://git-st.inf.tu-dresden.de/jastadd/preprocessors/coverage-generator
+site_dir: ../public
diff --git a/src/main/java/org/jastadd/preprocessor/testing/doc/DocumentationCreator.java b/src/main/java/org/jastadd/preprocessor/testing/doc/DocumentationCreator.java
new file mode 100644
index 0000000..8f819e8
--- /dev/null
+++ b/src/main/java/org/jastadd/preprocessor/testing/doc/DocumentationCreator.java
@@ -0,0 +1,106 @@
+package org.jastadd.preprocessor.testing.doc;
+
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.InputFiles;
+import org.gradle.api.tasks.Optional;
+import org.gradle.api.tasks.OutputDirectory;
+import org.jastadd.preprocessor.testing.plugin.Description;
+import org.jastadd.preprocessor.testing.plugin.JastAddConfiguration;
+import org.jastadd.preprocessor.testing.plugin.RagConnectConfiguration;
+import org.jastadd.preprocessor.testing.plugin.RelastConfiguration;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+
+public class DocumentationCreator {
+  private static final String HEADER = "# Configuration options\n\n";
+  private static final List<Map.Entry<String, Class<?>>> entitiesToBeDocumented = new ArrayList<>() {{
+    add(Map.entry("RagConnect Configuration", RagConnectConfiguration.class));
+    add(Map.entry("Relast Configuration", RelastConfiguration.class));
+    add(Map.entry("JastAdd Configuration", JastAddConfiguration.class));
+  }};
+  private static final String outputFile = "pages/doc/config.md";
+
+  public static void main(String[] args) {
+    new DocumentationCreator().run();
+  }
+
+  protected void run() {
+    PriorityQueue<String[]> options = new PriorityQueue<>((e1, e2) -> {
+      if (e1[1].equals("Yes")) {
+        if (e2[1].equals("Yes")) {
+          return e1[0].compareTo(e2[0]);
+        }
+        return -1;
+      }
+      if (e2[1].equals("Yes")) {
+        return 1;
+      }
+      return e1[0].compareTo(e2[0]);
+    });
+    try(BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputFile),
+        StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
+      writer.write(HEADER);
+      for (Map.Entry<String, Class<?>> entry : entitiesToBeDocumented) {
+        options.clear();
+        writer.write("## " + entry.getKey() + "\n\n");
+        writer.write("Name | Required? | Corresponding parameter | Description\n");
+        writer.write("--- | --- | --- | ---\n");
+        for (Method method : entry.getValue().getMethods()) {
+          if (method.isAnnotationPresent(Input.class) ||
+              method.isAnnotationPresent(InputFiles.class) ||
+              method.isAnnotationPresent(OutputDirectory.class)) {
+            String name = nameOfOption(method.getName());
+            String required = method.isAnnotationPresent(Optional.class) ? "No" : "Yes";
+            final String parameter, description;
+            if (method.isAnnotationPresent(Description.class)) {
+              Description descriptionAnnotation = method.getAnnotation(Description.class);
+              if (descriptionAnnotation.skip()) {
+                continue;
+              }
+              if (descriptionAnnotation.correspondingParameter().isBlank()) {
+                parameter = "";
+              } else {
+                parameter = "`" + descriptionAnnotation.correspondingParameter() + "`";
+              }
+              description = descriptionAnnotation.value();
+            } else {
+              parameter = "";
+              description = "_not provided_";
+            }
+            options.add(new String[]{name, required, parameter, description});
+          }
+        }
+        while(!options.isEmpty()) {
+          String[] option = options.poll();
+          String toWrite = String.format("%s | %s | %s | %s%n", (Object[]) option);
+          writer.write(toWrite);
+        }
+        writer.write("\n\n");
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private String nameOfOption(String methodName) {
+    if (methodName == null || methodName.isEmpty()) { return methodName; }
+    final String s;
+    if (methodName.startsWith("get")) {
+      s = methodName.substring(3);
+    } else if (methodName.startsWith("is")) {
+      s = methodName.substring(2);
+    } else {
+      throw new RuntimeException("Unknown prefix in method " + methodName);
+    }
+    return Character.toLowerCase(s.charAt(0)) + s.substring(1);
+  }
+}
diff --git a/src/main/java/org/jastadd/preprocessor/testing/plugin/Description.java b/src/main/java/org/jastadd/preprocessor/testing/plugin/Description.java
new file mode 100644
index 0000000..21f6c85
--- /dev/null
+++ b/src/main/java/org/jastadd/preprocessor/testing/plugin/Description.java
@@ -0,0 +1,11 @@
+package org.jastadd.preprocessor.testing.plugin;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Description {
+  String value();
+  String correspondingParameter() default "";
+  boolean skip() default false;
+}
diff --git a/src/main/java/org/jastadd/preprocessor/testing/plugin/JastAddConfiguration.java b/src/main/java/org/jastadd/preprocessor/testing/plugin/JastAddConfiguration.java
index 0d60e46..8ed8cdc 100644
--- a/src/main/java/org/jastadd/preprocessor/testing/plugin/JastAddConfiguration.java
+++ b/src/main/java/org/jastadd/preprocessor/testing/plugin/JastAddConfiguration.java
@@ -15,20 +15,24 @@ import java.util.List;
  */
 public interface JastAddConfiguration {
 
+  @Description(value = "Package name of AST files", correspondingParameter = "--package")
   @Input
   String getPackageName();
   void setPackageName(String packageName);
 
+  @Description(value = "Name of the List class", correspondingParameter = "--List")
   @Optional
   @Input
   String getJastAddList();
   void setJastAddList(String jastAddList);
 
+  @Description(value = "Do not run JastAdd")
   @Optional
   @Input
   boolean isSkipRun();
   void setSkipRun(boolean skipRun);
 
+  @Description(value = "Add more options not directly supported")
   @Optional
   @Input
   List<String> getExtraOptions();
@@ -37,19 +41,25 @@ public interface JastAddConfiguration {
     return getExtraOptions() != null ? getExtraOptions() : Collections.emptyList();
   }
 
+  @Description(value = "Add new input files to be processed")
   @Optional
   @InputFiles
   List<File> getInputFiles();
   void setInputFiles(List<File> inputFiles);
 
+  @Description(value = "Output directory (defaults to `src/test/java-gen`)", correspondingParameter = "--o")
   @Optional
   @OutputDirectory
   File getOutputDir();
   void setOutputDir(File outputDir);
+
+  @Description(value = "_only used internally_", skip = true)
   @OutputDirectory
   default File getOutputDirOrDefault() {
     return getOutputDir() != null ? getOutputDir() : Paths.get("src", "test", "java-gen").toFile();
   }
+
+  @Description(value = "_only used internally_", skip = true)
   @OutputDirectory
   default File getPackageOutputDir() {
     return getOutputDirOrDefault().toPath().resolve(getPackageName().replace('.', File.separatorChar)).toFile();
diff --git a/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectConfiguration.java b/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectConfiguration.java
index 8c7bb91..783fe60 100644
--- a/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectConfiguration.java
+++ b/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectConfiguration.java
@@ -14,35 +14,54 @@ import java.util.List;
  */
 public interface RagConnectConfiguration {
 
+  @Description(value = "Sets the root node", correspondingParameter = "--rootNode")
   @Input
   String getRootNode();
   void setRootNode(String rootNode);
 
+  @Description(value = "Sets the output directory", correspondingParameter = "--o")
   @Input
   String getOutputDir();
   void setOutputDir(String outputDir);
 
+  @Description(value = "Add new input files to be processed")
   @InputFiles
   List<File> getInputFiles();
   void setInputFiles(List<File> inputFiles);
 
+  @Description(value = "Log read endpoints", correspondingParameter = "--logReads")
   @Optional
   @Input
   boolean isLogReads();
   void setLogReads(boolean logReads);
 
+  @Description(value = "Log write endpoints", correspondingParameter = "--logWrites")
   @Optional
   @Input
   boolean isLogWrites();
   void setLogWrites(boolean logWrites);
 
+  @Description(value = "Log incremental activities", correspondingParameter = "--logIncremental")
+  @Optional
+  @Input
+  boolean isLogIncremental();
+  void setLogIncremental(boolean loggIncremental);
+
+  @Description(value = "Be more verbose during compilation", correspondingParameter = "--verbose")
   @Optional
   @Input
   boolean isVerbose();
   void setVerbose(boolean verbose);
 
+  @Description(value = "Set protocols to be used", correspondingParameter = "--protocols")
   @Optional
   @Input
   List<String> getProtocols();
   void setProtocols(List<String> protocols);
+
+  @Description(value = "Add more options not directly supported")
+  @Optional
+  @Input
+  List<String> getAdditionalOptions();
+  void setAdditionalOptions(List<String> additionalOptions);
 }
diff --git a/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectTest.java b/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectTest.java
index 726c6ec..d310f3a 100644
--- a/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectTest.java
+++ b/src/main/java/org/jastadd/preprocessor/testing/plugin/RagConnectTest.java
@@ -108,12 +108,18 @@ public abstract class RagConnectTest extends RelastTest {
         if (getRagconnect().isLogWrites()) {
           args.add("--logWrites");
         }
+        if (getRagconnect().isLogIncremental()) {
+          args.add("--logIncremental");
+        }
         if (getRagconnect().isVerbose()) {
           args.add("--verbose");
         }
         if (getRagconnect().getProtocols() != null && !getRagconnect().getProtocols().isEmpty()) {
           args.add("--protocols=" + String.join(",", getRagconnect().getProtocols()));
         }
+        if (getJastadd().getJastAddList() != null) {
+          args.add("--jastAddList=" + getJastadd().getJastAddList());
+        }
         args.addAll(getJastadd().getExtraOptionsOrDefault());
         args.addAll(getRagconnect().getInputFiles());
         javaExecSpec.args(args);
diff --git a/src/main/java/org/jastadd/preprocessor/testing/plugin/RelastConfiguration.java b/src/main/java/org/jastadd/preprocessor/testing/plugin/RelastConfiguration.java
index 958ec33..bf721f6 100644
--- a/src/main/java/org/jastadd/preprocessor/testing/plugin/RelastConfiguration.java
+++ b/src/main/java/org/jastadd/preprocessor/testing/plugin/RelastConfiguration.java
@@ -14,40 +14,48 @@ import java.util.List;
  */
 public interface RelastConfiguration {
 
+  @Description(value = "Use JastAdd like API for relations", correspondingParameter = "--useJastAddNames")
   @Optional
   @Input
   boolean isUseJastAddNames();
   void setUseJastAddNames(boolean useJastAddNames);
 
+  @Description(value = "Name of resulting grammar (can be a path)", correspondingParameter = "--grammarName")
   @Input
   String getGrammarName();
   void setGrammarName(String grammarName);
 
+  @Description(value = "Add new input files to be processed")
   @Optional
   @InputFiles
   List<File> getInputFiles();
   void setInputFiles(List<File> inputFiles);
 
+  @Description(value = "Do not write any files", correspondingParameter = "--file")
   @Optional
   @Input
   boolean isNoWriteToFile();
   void setNoWriteToFile(boolean noWriteToFile);
 
+  @Description(value = "Do not generate resolverHelper", correspondingParameter = "--resolverHelper")
   @Optional
   @Input
   boolean isNoResolverHelper();
   void setNoResolverHelper(boolean noResolverHelper);
 
+  @Description(value = "Class to be used for relations", correspondingParameter = "--listClass")
   @Optional
   @Input
   String getListClass();
   void setListClass(String listClass);
 
+  @Description(value = "Activate serialization, and set its implementation", correspondingParameter = "--serializer")
   @Optional
   @Input
   String getSerializer();
   void setSerializer(String serializer);
 
+  @Description(value = "Be more verbose during compilation")
   @Optional
   @Input
   boolean isVerbose();
-- 
GitLab