Skip to content

Commit

Permalink
Updates dependencies, adds an inspect command.
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbrowndotje committed Feb 22, 2024
1 parent 4d45faf commit cc37ad4
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 34 deletions.
16 changes: 9 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ targetCompatibility = 17

repositories {
mavenCentral()
// mavenLocal()
}

dependencies {

implementation 'com.structurizr:structurizr-dsl:1.35.0'
implementation 'com.structurizr:structurizr-export:1.19.0'
implementation 'com.structurizr:structurizr-dsl:2.0.0'
implementation 'com.structurizr:structurizr-export:2.0.0'
implementation 'io.github.goto1134:structurizr-d2-exporter:1.5.2'
implementation 'com.structurizr:structurizr-graphviz:2.2.2'
implementation 'com.structurizr:structurizr-autolayout:2.0.0'
implementation 'com.structurizr:structurizr-inspection:2.0.0'

implementation 'commons-cli:commons-cli:1.5.0'

Expand All @@ -29,10 +31,10 @@ dependencies {
implementation 'org.jruby:jruby-core:9.4.4.0'

implementation 'commons-logging:commons-logging:1.2'
implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.apache.logging.log4j:log4j-jcl:2.20.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
implementation 'org.apache.logging.log4j:log4j-api:2.23.0'
implementation 'org.apache.logging.log4j:log4j-core:2.23.0'
implementation 'org.apache.logging.log4j:log4j-jcl:2.23.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.23.0'

testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.2'

Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/structurizr/cli/AbstractCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
import org.apache.hc.core5.http.io.entity.EntityUtils;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;

public abstract class AbstractCommand {

private static final Log log = LogFactory.getLog(AbstractCommand.class);

private static final String PLUGINS_DIRECTORY_NAME = "plugins";
private static final int HTTP_OK_STATUS = 200;

protected AbstractCommand() {
Expand Down Expand Up @@ -112,4 +115,27 @@ protected String readFromUrl(String url) {
return "";
}

protected Class loadClass(String fqn, File workspaceFile) throws Exception {
File pluginsDirectory = new File(workspaceFile.getParent(), PLUGINS_DIRECTORY_NAME);
URL[] urls = new URL[0];

if (pluginsDirectory.exists()) {
File[] jarFiles = pluginsDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
if (jarFiles != null) {
urls = new URL[jarFiles.length];
for (int i = 0; i < jarFiles.length; i++) {
System.out.println(jarFiles[i].getAbsolutePath());
try {
urls[i] = jarFiles[i].toURI().toURL();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

URLClassLoader childClassLoader = new URLClassLoader(urls, getClass().getClassLoader());
return childClassLoader.loadClass(fqn);
}

}
2 changes: 1 addition & 1 deletion src/main/java/com/structurizr/cli/HelpCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class HelpCommand extends AbstractCommand {
}

public void run(String... args) throws Exception {
log.info("Usage: structurizr push|pull|lock|unlock|export|validate|list|version|help [options]");
log.info("Usage: structurizr push|pull|lock|unlock|export|validate|inspect|list|version|help [options]");
}

}
145 changes: 145 additions & 0 deletions src/main/java/com/structurizr/cli/InspectCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.structurizr.cli;

import com.structurizr.Workspace;
import com.structurizr.inspection.Inspector;
import com.structurizr.inspection.Severity;
import com.structurizr.inspection.Violation;
import com.structurizr.util.StringUtils;
import org.apache.commons.cli.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

class InspectCommand extends AbstractCommand {

private static final Log log = LogFactory.getLog(InspectCommand.class);

private static final String DEFAULT_INSPECTOR = "com.structurizr.inspection.DefaultInspector";

InspectCommand() {
}

public void run(String... args) throws Exception {
Options options = new Options();

Option option = new Option("w", "workspace", true, "Path or URL to the workspace JSON/DSL file");
option.setRequired(true);
options.addOption(option);

option = new Option("i", "inspector", true, "Inspector implementation to use");
option.setRequired(false);
options.addOption(option);

option = new Option("s", "severity", true, "A comma separated list of the severity level(s) to show");
option.setRequired(false);
options.addOption(option);

CommandLineParser commandLineParser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();

String workspacePathAsString = null;
String inspectorName = null;
String severitiesAsString = null;

try {
CommandLine cmd = commandLineParser.parse(options, args);

workspacePathAsString = cmd.getOptionValue("workspace");
inspectorName = cmd.getOptionValue("inspector");
severitiesAsString = cmd.getOptionValue("severity");
} catch (ParseException e) {
log.error(e.getMessage());
formatter.printHelp("inspect", options);

System.exit(1);
}

if (StringUtils.isNullOrEmpty(inspectorName)) {
inspectorName = DEFAULT_INSPECTOR;
}

log.debug("Inspecting workspace at " + workspacePathAsString + " using " + inspectorName);

Set<Severity> severities = new HashSet<>();
if (StringUtils.isNullOrEmpty(severitiesAsString)) {
severities.add(Severity.ERROR);
severities.add(Severity.WARNING);
severities.add(Severity.INFO);
severities.add(Severity.IGNORE);
} else {
for (String severity : severitiesAsString.split(",")) {
severities.add(Severity.valueOf(severity.trim().toUpperCase()));
}
}

try {
Workspace workspace = loadWorkspace(workspacePathAsString);
Inspector inspector = findInspector(inspectorName, workspace, new File(workspacePathAsString));

if (inspector != null) {
List<Violation> violations = inspector.getViolations();
violations.sort(Comparator.comparing(Violation::getSeverity));

violations = violations.stream().filter(v -> severities.contains(v.getSeverity())).collect(Collectors.toList());

if (!violations.isEmpty()) {
int typeColumns = 0;
int descriptionColumns = 0;
for (Violation violation : violations) {
typeColumns = Math.max(typeColumns, violation.getType().length());
descriptionColumns = Math.max(descriptionColumns, violation.getMessage().length());
}

String rowFormat = "%-6s | %-" + typeColumns + "s | %s";

int counter = 0;
for (Violation violation : violations) {
if (severities.contains(violation.getSeverity())) {
counter++;

String line = String.format(
rowFormat,
violation.getSeverity().toString(),
violation.getType(),
violation.getMessage()
);

log.info(line);
}
}

System.exit(counter); // non-zero if there are violations shown
}
}
} catch (Exception e) {
// print the error and exit
log.error(e.getMessage());
System.exit(1);
}

log.debug(" - inspected");
log.debug(" - finished");
}

private Inspector findInspector(String name, Workspace workspace, File workspacePath) {
try {
Class<?> clazz = loadClass(name, workspacePath);
if (Inspector.class.isAssignableFrom(clazz)) {
return (Inspector) clazz.getDeclaredConstructor(Workspace.class).newInstance(workspace);
}
} catch (ClassNotFoundException e) {
log.error(" - unknown inspector: " + name);
} catch (Exception e) {
log.error(" - error creating instance of " + name, e);
}

return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class StructurizrCliApplication {
private static final String EXPORT_COMMAND = "export";
private static final String MERGE_COMMAND = "merge";
private static final String VALIDATE_COMMAND = "validate";
private static final String INSPECT_COMMAND = "inspect";
private static final String LIST_COMMAND = "list";
private static final String VERSION_COMMAND = "version";
private static final String HELP_COMMAND = "help";
Expand Down Expand Up @@ -64,6 +65,7 @@ public class StructurizrCliApplication {
COMMANDS.put(EXPORT_COMMAND, new ExportCommand());
COMMANDS.put(MERGE_COMMAND, new MergeCommand());
COMMANDS.put(VALIDATE_COMMAND, new ValidateCommand());
COMMANDS.put(INSPECT_COMMAND, new InspectCommand());
COMMANDS.put(LIST_COMMAND, new ListCommand());
COMMANDS.put(VERSION_COMMAND, new VersionCommand());
COMMANDS.put(HELP_COMMAND, new HelpCommand());
Expand Down Expand Up @@ -94,7 +96,7 @@ private void printUsageMessageAndExit(String commandName) {
log.error("Error: " + commandName + " not recognised");
}

log.error("Usage: structurizr push|pull|lock|unlock|export|validate|list|version|help [options]");
log.error("Usage: structurizr push|pull|lock|unlock|export|validate|inspect|list|version|help [options]");
System.exit(1);
}

Expand Down
25 changes: 0 additions & 25 deletions src/main/java/com/structurizr/cli/export/ExportCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

public class ExportCommand extends AbstractCommand {

private static final String PLUGINS_DIRECTORY_NAME = "plugins";

private static final Log log = LogFactory.getLog(ExportCommand.class);

private static final String JSON_FORMAT = "json";
Expand Down Expand Up @@ -199,29 +197,6 @@ private Exporter findExporter(String format, File workspacePath) {
return null;
}

private Class loadClass(String fqn, File workspaceFile) throws Exception {
File pluginsDirectory = new File(workspaceFile.getParent(), PLUGINS_DIRECTORY_NAME);
URL[] urls = new URL[0];

if (pluginsDirectory.exists()) {
File[] jarFiles = pluginsDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
if (jarFiles != null) {
urls = new URL[jarFiles.length];
for (int i = 0; i < jarFiles.length; i++) {
System.out.println(jarFiles[i].getAbsolutePath());
try {
urls[i] = jarFiles[i].toURI().toURL();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

URLClassLoader childClassLoader = new URLClassLoader(urls, getClass().getClassLoader());
return childClassLoader.loadClass(fqn);
}

private String prefix(long workspaceId) {
if (workspaceId > 0) {
return "structurizr-" + workspaceId;
Expand Down

0 comments on commit cc37ad4

Please sign in to comment.