Skip to content

Commit 6795d78

Browse files
committed
Initial refactoring
1 parent 0489e36 commit 6795d78

16 files changed

+571
-495
lines changed

.gitignore

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,4 @@
1-
# Compiled class file
2-
*.class
3-
**/target
4-
**/out
5-
6-
# Build
7-
/build
1+
build/
82
.gradle/
9-
10-
# Log file
11-
*.log
12-
13-
# BlueJ files
14-
*.ctxt
15-
16-
# Mobile Tools for Java (J2ME)
17-
.mtj.tmp/
18-
19-
# Package Files #
20-
*.jar
21-
*.war
22-
*.nar
23-
*.ear
24-
*.zip
25-
*.tar.gz
26-
*.rar
27-
28-
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
29-
hs_err_pid*
30-
31-
# IntelliJ
32-
/.idea
3+
.cursor/
4+
.DS_Store

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ If you want to contribute to this project you can create a fork and a pull reque
9090
9191
```bash
9292
./gradlew clean build
93+
./gradlew clean build snapshot
94+
java -jar build/libs/context-mapper-cli-0.1.0-SNAPSHOT.jar
9395
```
9496
9597
## Contributing
@@ -100,4 +102,3 @@ Contribution is always welcome! Here are some ways how you can contribute:
100102
101103
## Licence
102104
ContextMapper is released under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
103-

build.gradle

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ repositories {
1717
}
1818

1919
dependencies {
20-
implementation "commons-cli:commons-cli:${commonsCliVersion}"
2120
implementation "org.contextmapper:context-mapper-dsl:${cmlVersion}"
21+
implementation "info.picocli:picocli:${picocliVersion}"
2222

2323
testImplementation "org.junit.jupiter:junit-jupiter-api:${jUnitVersion}"
2424
testImplementation "org.junit.jupiter:junit-jupiter-params:${jUnitVersion}"
@@ -43,6 +43,12 @@ jar {
4343
'Main-Class': 'org.contextmapper.cli.ContextMapperCLI'
4444
)
4545
}
46+
from {
47+
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
48+
}
49+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
50+
exclude('META-INF/LICENSE.txt', 'META-INF/NOTICE.txt', 'META-INF/DEPENDENCIES')
51+
exclude('META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/services/**')
4652
}
4753

4854
if (!project.hasProperty('signing.secretKeyRingFile')) {

context_mapper_cli.feature

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
Feature: Context Mapper CLI Usage
2+
As a user of the Context Mapper CLI
3+
I want to be able to validate CML files and generate various outputs
4+
So that I can effectively use the tool for my Domain-Driven Design modeling.
5+
6+
Background:
7+
Given the Context Mapper CLI is installed
8+
9+
Scenario: Display help for the validate command
10+
When I run the command `./cm validate -h`
11+
Then the output should contain:
12+
"""
13+
Context Mapper CLI
14+
usage: cm validate
15+
-h,--help Prints this message.
16+
-i,--input <arg> Path to the CML file which you want to validate.
17+
"""
18+
19+
Scenario: Validate a CML file
20+
Given a CML file named "DDD-Sample.cml" exists
21+
When I run the command `./cm validate -i DDD-Sample.cml`
22+
Then the CLI should validate "DDD-Sample.cml" successfully
23+
24+
Scenario: Display help for the generate command
25+
When I run the command `./cm generate -h`
26+
Then the output should contain:
27+
"""
28+
Context Mapper CLI
29+
usage: cm generate
30+
-f,--outputFile <arg> The name of the file that shall be generated
31+
(only used by Freemarker generator, as we cannot
32+
know the file extension).
33+
-g,--generator <arg> The generator you want to call. Use one of the
34+
following values: context-map (Graphical DDD
35+
Context Map), plantuml (PlantUML class-,
36+
component-, and state diagrams.), generic
37+
(Generate generic text with Freemarker template)
38+
-h,--help Prints this message.
39+
-i,--input <arg> Path to the CML file for which you want to
40+
generate output.
41+
-o,--outputDir <arg> Path to the directory into which you want to
42+
generate.
43+
-t,--template <arg> Path to the Freemarker template you want to use.
44+
This parameter is only used if you pass 'generic'
45+
to the 'generator' (-g) parameter.
46+
"""
47+
48+
Scenario: Generate PlantUML output
49+
Given a CML file named "DDD-Sample.cml" exists
50+
And an output directory named "output-directory"
51+
When I run the command `./cm generate -i DDD-Sample.cml -g plantuml -o ./output-directory`
52+
Then PlantUML diagrams should be generated in "./output-directory" from "DDD-Sample.cml"
53+
54+
Scenario: Generate Context Map output
55+
Given a CML file named "DDD-Sample.cml" exists
56+
And an output directory named "output-directory"
57+
When I run the command `./cm generate -i DDD-Sample.cml -g context-map -o ./output-directory`
58+
Then a Context Map should be generated in "./output-directory" from "DDD-Sample.cml"
59+
60+
Scenario: Generate arbitrary text file with Freemarker template
61+
Given a CML file named "DDD-Sample.cml" exists
62+
And an output directory named "output-directory"
63+
And a Freemarker template file named "template.md.ftl"
64+
When I run the command `./cm generate -i DDD-Sample.cml -g generic -o ./output-directory -t template.md.ftl -f glossary.md`
65+
Then a file named "glossary.md" should be generated in "./output-directory" using "template.md.ftl" and "DDD-Sample.cml"

gradle.properties

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ ossReleaseStagingRepository=https://oss.sonatype.org/service/local/staging/deplo
44

55
# dependency versions
66
jUnitVersion=5.9.1
7-
assertJVersion=3.19.0
7+
assertJVersion=3.27.3
88
mockitoVersion=3.9.0
99

10-
commonsCliVersion=1.4
1110
cmlVersion=6.12.0
12-
11+
picocliVersion=4.7.7

src/main/java/org/contextmapper/cli/ContextMapperCLI.java

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,61 +15,44 @@
1515
*/
1616
package org.contextmapper.cli;
1717

18-
import org.contextmapper.cli.commands.CliCommand;
1918
import org.contextmapper.cli.commands.GenerateCommand;
2019
import org.contextmapper.cli.commands.ValidateCommand;
20+
import picocli.CommandLine;
21+
import picocli.CommandLine.Command;
2122

22-
import java.util.Arrays;
23-
import java.util.Collections;
24-
import java.util.List;
25-
26-
public class ContextMapperCLI {
23+
@Command(name = "cm", mixinStandardHelpOptions = true, versionProvider = VersionProvider.class,
24+
description = "Context Mapper CLI",
25+
subcommands = {
26+
ValidateCommand.class,
27+
GenerateCommand.class
28+
})
29+
public class ContextMapperCLI implements Runnable {
2730

2831
private static final int REQUIRED_JAVA_VERSION = 11;
29-
private static final String VALIDATE_COMMAND = "validate";
30-
private static final String GENERATE_COMMAND = "generate";
31-
32-
private CliCommand generateCommand;
33-
private CliCommand validateCommand;
34-
35-
public ContextMapperCLI() {
36-
this.generateCommand = new GenerateCommand();
37-
this.validateCommand = new ValidateCommand();
38-
}
3932

4033
public static void main(String[] args) {
41-
int javaVersion = Runtime.version().feature();
42-
43-
if (Runtime.version().feature() >= REQUIRED_JAVA_VERSION) {
44-
new ContextMapperCLI().run(args);
45-
} else {
46-
System.out.printf("Invalid Java version '%s' (>=%s is required).", javaVersion, REQUIRED_JAVA_VERSION);
34+
if (Runtime.version().feature() < REQUIRED_JAVA_VERSION) {
35+
System.err.printf("Invalid Java version '%s' (>=%s is required).%n", Runtime.version().feature(), REQUIRED_JAVA_VERSION);
4736
System.exit(1);
4837
}
38+
int exitCode = new CommandLine(new ContextMapperCLI()).execute(args);
39+
System.exit(exitCode);
4940
}
5041

51-
protected void run(String[] args) {
52-
System.out.println("Context Mapper CLI " + getVersion());
53-
54-
if (args == null || args.length == 0) {
55-
printUsages();
56-
} else if (VALIDATE_COMMAND.equalsIgnoreCase(args[0])) {
57-
validateCommand.run(Arrays.copyOfRange(args, 1, args.length));
58-
} else if (GENERATE_COMMAND.equalsIgnoreCase(args[0])) {
59-
generateCommand.run(Arrays.copyOfRange(args, 1, args.length));
60-
} else {
61-
System.out.println("Invalid input");
62-
System.exit(127);
63-
}
42+
@Override
43+
public void run() {
44+
// This is executed if no subcommand is specified.
45+
// Picocli will show the help message by default if mixinStandardHelpOptions = true and no subcommand is given.
46+
// We can add a custom message here if needed, or rely on Picocli's default behavior.
47+
System.out.println("Context Mapper CLI. Use 'cm --help' for usage information.");
6448
}
6549

66-
private void printUsages() {
67-
System.out.println("Usage: cm " + VALIDATE_COMMAND + "|" + GENERATE_COMMAND + " [options]");
68-
}
50+
}
6951

70-
private String getVersion() {
52+
class VersionProvider implements CommandLine.IVersionProvider {
53+
@Override
54+
public String[] getVersion() throws Exception {
7155
String implVersion = ContextMapperCLI.class.getPackage().getImplementationVersion();
72-
return implVersion != null ? "v" + implVersion : "DEVELOPMENT VERSION";
56+
return new String[]{"Context Mapper CLI " + (implVersion != null ? "v" + implVersion : "DEVELOPMENT VERSION")};
7357
}
74-
7558
}

src/main/java/org/contextmapper/cli/commands/AbstractCliCommand.java

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/main/java/org/contextmapper/cli/commands/CliCommand.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/main/java/org/contextmapper/cli/commands/ContextMapperGenerator.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import org.contextmapper.dsl.generator.PlantUMLGenerator;
66
import org.eclipse.xtext.generator.IGenerator2;
77

8+
import java.util.Arrays;
9+
import java.util.stream.Collectors;
10+
811
public enum ContextMapperGenerator {
912

1013
CONTEXT_MAP("context-map", "Graphical DDD Context Map"),
@@ -27,28 +30,36 @@ public String getDescription() {
2730
return description;
2831
}
2932

33+
public String getDisplayName() {
34+
return this.name + " (" + this.description + ")";
35+
}
36+
3037
@Override
3138
public String toString() {
32-
return this.name + " (" + this.description + ")";
39+
// Picocli uses toString() for default value display and for completion candidates if no specific provider is set.
40+
// Returning only the name makes it cleaner for command-line usage.
41+
return this.name;
3342
}
3443

3544
public static ContextMapperGenerator byName(String name) {
3645
if (name == null || "".equals(name))
3746
throw new IllegalArgumentException("Please provide a name for the generator.");
3847

3948
for (ContextMapperGenerator generator : values()) {
40-
if (generator.getName().equals(name))
49+
if (generator.getName().equalsIgnoreCase(name)) // Make it case-insensitive for user-friendliness
4150
return generator;
4251
}
4352

44-
throw new IllegalArgumentException("No generator found for the name '" + name + "'.");
53+
throw new IllegalArgumentException("No generator found for the name '" + name + "'. Valid values are: " +
54+
Arrays.stream(values()).map(ContextMapperGenerator::getName).collect(Collectors.joining(", ")));
4555
}
4656

4757
public IGenerator2 getGenerator() {
4858
if (this == CONTEXT_MAP)
4959
return new ContextMapGenerator();
5060
if (this == PLANT_UML)
5161
return new PlantUMLGenerator();
62+
// Assumes GENERIC is the only other case based on current enum values
5263
return new GenericContentGenerator();
5364
}
5465

0 commit comments

Comments
 (0)