diff --git a/.github/workflows/code-coverage.yaml b/.github/workflows/code-coverage.yaml index bdf0d7bfcde..8a7054763c5 100644 --- a/.github/workflows/code-coverage.yaml +++ b/.github/workflows/code-coverage.yaml @@ -26,7 +26,7 @@ jobs: run: mvn verify -P jacoco --batch-mode --also-make --projects matsim -Dmaven.test.redirectTestOutputToFile -Dmatsim.preferLocalDtds=true - name: Push coverage to CodeCov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: files: ./matsim/target/site/jacoco/jacoco.xml diff --git a/.github/workflows/deploy-on-pr-merge.yaml b/.github/workflows/deploy-on-pr-merge.yaml index ef046e1bdb0..11a60d440a6 100644 --- a/.github/workflows/deploy-on-pr-merge.yaml +++ b/.github/workflows/deploy-on-pr-merge.yaml @@ -46,7 +46,7 @@ jobs: - name: Submit Dependency Graph # Generate a complete dependency graph and submit the graph to the GitHub repository. # The goal is to improve security alerts from dependabot, because dependabot is not able to compute the complete dependency graph. - uses: advanced-security/maven-dependency-submission-action@v3 + uses: advanced-security/maven-dependency-submission-action@v4 env: MAVEN_OPTS: -Xmx2g diff --git a/.github/workflows/verify-push.yaml b/.github/workflows/verify-push.yaml index a4eb837efcb..a0d383b992d 100644 --- a/.github/workflows/verify-push.yaml +++ b/.github/workflows/verify-push.yaml @@ -75,7 +75,7 @@ jobs: - name: Detect changes against master # we only want to build matsim (module) if changes are not limited to contribs id: detect-changes - uses: dorny/paths-filter@v2 + uses: dorny/paths-filter@v3 if: ${{matrix.module == 'matsim'}} with: filters: | diff --git a/contribs/analysis/pom.xml b/contribs/analysis/pom.xml index 3894c728d93..8238a60b8bb 100644 --- a/contribs/analysis/pom.xml +++ b/contribs/analysis/pom.xml @@ -32,7 +32,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.3 + 5.3.1 diff --git a/contribs/application/src/main/java/org/matsim/application/ApplicationUtils.java b/contribs/application/src/main/java/org/matsim/application/ApplicationUtils.java index 89086cb00d3..bc9c97f08b3 100644 --- a/contribs/application/src/main/java/org/matsim/application/ApplicationUtils.java +++ b/contribs/application/src/main/java/org/matsim/application/ApplicationUtils.java @@ -31,10 +31,25 @@ public class ApplicationUtils { private ApplicationUtils() { } + + /** + * Merge given arguments with custom ones. + * + * @param args given args, usually input from command line / main method + * @param defaultArgs default arguments that will be added to existing ones. + */ + public static String[] mergeArgs(String[] args, String... defaultArgs) { + String[] mergedArgs = new String[args.length + defaultArgs.length]; + System.arraycopy(args, 0, mergedArgs, 0, args.length); + System.arraycopy(defaultArgs, 0, mergedArgs, args.length, defaultArgs.length); + return mergedArgs; + } + /** * Extends a context (usually config location) with an relative filename. * If the results is a local file, the path will be returned. Otherwise, it will be an url. * The results can be used as input for command line parameter or {@link IOUtils#resolveFileOrResource(String)}. + * * @return string with path or URL */ public static String resolve(URL context, String filename) { @@ -61,9 +76,9 @@ public static Path globFile(Path path, String pattern) { try { return Files.list(path) - .filter(p -> m.matches(p.getFileName())) - .findFirst() - .orElseThrow(() -> new IllegalStateException("No " + pattern + " file found.")); + .filter(p -> m.matches(p.getFileName())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No " + pattern + " file found.")); } catch (IOException e) { throw new RuntimeException(e); } @@ -154,11 +169,19 @@ public static void checkCommand(Class command) { boolean input = false; boolean output = false; for (Field field : fields) { - if (field.getType().equals(InputOptions.class)) + if (field.getType().equals(InputOptions.class)) { input = true; + CommandLine.Mixin mixin = field.getAnnotation(CommandLine.Mixin.class); + if (mixin == null) + throw new IllegalArgumentException(String.format("The command %s has no @Mixin annotation for InputOptions %s.", command, field.getName())); + } - if (field.getType().equals(OutputOptions.class)) + if (field.getType().equals(OutputOptions.class)) { output = true; + CommandLine.Mixin mixin = field.getAnnotation(CommandLine.Mixin.class); + if (mixin == null) + throw new IllegalArgumentException(String.format("The command %s has no @Mixin annotation for OutputOptions %s.", command, field.getName())); + } } if (!input) { @@ -213,7 +236,7 @@ public static Path matchInput(String name, Path dir) { return path.get(); // Match more general pattern at last - path = matchPattern( ".+\\.[a-zA-Z0-9]*_" + name + "\\..+", dir); + path = matchPattern(".+\\.[a-zA-Z0-9]*_" + name + "\\..+", dir); if (path.isPresent()) return path.get(); diff --git a/contribs/application/src/main/java/org/matsim/application/CommandRunner.java b/contribs/application/src/main/java/org/matsim/application/CommandRunner.java index 56f4549b678..b55fc548a56 100644 --- a/contribs/application/src/main/java/org/matsim/application/CommandRunner.java +++ b/contribs/application/src/main/java/org/matsim/application/CommandRunner.java @@ -247,6 +247,22 @@ public Path getRequiredPath(Class command, String fi return buildPath(spec, command).resolve(file); } + /** + * Return the output of a command with a placeholder. + * @param file file name, which must contain a %s, which will be replaced by the placeholder + */ + public Path getRequiredPath(Class command, String file, String placeholder) { + CommandSpec spec = ApplicationUtils.getSpec(command); + if (!ArrayUtils.contains(spec.produces(), file)) + throw new IllegalArgumentException(String.format("Command %s does not declare output %s", command, file)); + if (!file.contains("%s")) + throw new IllegalArgumentException(String.format("File %s does not contain placeholder %%s", file)); + + file = String.format(file, placeholder); + + return buildPath(spec, command).resolve(file); + } + /** * Base path for the runner. */ @@ -279,8 +295,8 @@ public void add(Class command, String... args) { if (args.length != 0) { String[] existing = this.args.get(command); if (existing != null && existing.length > 0 && !Arrays.equals(existing, args)) { - throw new IllegalArgumentException(String.format("Command %s already registered with args %s, can not define different args as %s", - command.toString(), Arrays.toString(existing), Arrays.toString(args))); + throw new IllegalArgumentException(String.format("Command %s already registered with args %s, can not define different args as %s (name '%s').", + command.toString(), Arrays.toString(existing), Arrays.toString(args), name)); } } @@ -298,6 +314,22 @@ public void add(Class command, String... args) { } } + /** + * Insert args for an already existing command. If the command was not added, this does nothing. + */ + public void insertArgs(Class command, String... args) { + + if (!this.args.containsKey(command)) + return; + + String[] existing = this.args.get(command); + String[] newArgs = new String[existing.length + args.length]; + System.arraycopy(args, 0, newArgs, 0, args.length); + System.arraycopy(existing, 0, newArgs, args.length, existing.length); + + this.args.put(command, newArgs); + } + /** * Set specific shape file for certain command. */ diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/LogFileAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/LogFileAnalysis.java index 36345aa2a79..5000c232482 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/LogFileAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/LogFileAnalysis.java @@ -171,7 +171,6 @@ private void renderWarnings(BufferedWriter writer, Set warnings) throws } else { Map> grouped = warnings.stream().collect(Collectors.groupingBy(w -> w.module, Collectors.toList())); - writer.write(String.format("

Warnings found in %d module%s ❌

\n\n", grouped.size(), grouped.size() > 1 ? "s" : "")); for (Map.Entry> e : grouped.entrySet()) { @@ -188,9 +187,7 @@ private void renderWarnings(BufferedWriter writer, Set warnings) throws writer.write("""