diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a9fd24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.iml +.idea +pom.xml.versionsBackup +target diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e8d95e0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".jenkins"] + path = .jenkins + url = https://www.github.com/io7m/jenkinsfiles diff --git a/.jenkins b/.jenkins new file mode 160000 index 0000000..61a9d19 --- /dev/null +++ b/.jenkins @@ -0,0 +1 @@ +Subproject commit 61a9d198e8ee8559228dc6179cbe4ae6e9bef6df diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2377beb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: java + +jdk: + - oraclejdk11 + - openjdk11 + +before_install: + - wget https://archive.apache.org/dist/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.zip + - unzip -qq apache-maven-3.6.2-bin.zip + - export M2_HOME=$PWD/apache-maven-3.6.2 + - export PATH=$M2_HOME/bin:$PATH + +install: true + +script: + - mvn --errors clean verify site + - bash <(curl -s https://codecov.io/bash) -f ./com.io7m.claypot.tests/target/site/jacoco-aggregate/jacoco.xml + +notifications: + irc: "chat.freenode.net#io7m" + diff --git a/README-CHANGES.xml b/README-CHANGES.xml new file mode 100644 index 0000000..d445360 --- /dev/null +++ b/README-CHANGES.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..abb3c44 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +claypot +=== + +[![Travis](https://img.shields.io/travis/io7m/claypot.png?style=flat-square)](https://travis-ci.org/io7m/claypot) +[![Maven Central](https://img.shields.io/maven-central/v/com.io7m.claypot/com.io7m.claypot.png?style=flat-square)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.io7m.claypot%22) +[![Maven Central (snapshot)](https://img.shields.io/nexus/s/https/oss.sonatype.org/com.io7m.claypot/com.io7m.claypot.svg?style=flat-square)](https://oss.sonatype.org/content/repositories/snapshots/com/io7m/claypot/) +[![Codacy grade](https://img.shields.io/codacy/grade/e6b8b59da8fb4d8383f26601bcc37d48.png?style=flat-square)](https://www.codacy.com/app/github_79/claypot) +[![Codecov](https://img.shields.io/codecov/c/github/io7m/claypot.png?style=flat-square)](https://codecov.io/gh/io7m/claypot) + +![claypot](./src/site/resources/claypot.jpg?raw=true) + diff --git a/com.io7m.claypot.core/pom.xml b/com.io7m.claypot.core/pom.xml new file mode 100644 index 0000000..8ce3d33 --- /dev/null +++ b/com.io7m.claypot.core/pom.xml @@ -0,0 +1,57 @@ + + + + + 4.0.0 + + + com.io7m.claypot + com.io7m.claypot + 0.0.1 + + + com.io7m.claypot.core + + JCommander conventions for io7m projects (Core) + com.io7m.claypot.core + https://www.github.com/io7m/claypot + + + + com.beust + jcommander + + + ch.qos.logback + logback-classic + + + org.slf4j + slf4j-api + + + + org.immutables + value + provided + + + com.io7m.immutables.style + com.io7m.immutables.style + provided + + + org.osgi + org.osgi.annotation.bundle + provided + + + org.osgi + org.osgi.annotation.versioning + provided + + + + \ No newline at end of file diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractCommand.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractCommand.java new file mode 100644 index 0000000..2f4777c --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractCommand.java @@ -0,0 +1,104 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import org.osgi.annotation.versioning.ProviderType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + +/** + * An abstract command. + */ + +@ProviderType +@Parameters(resourceBundle = "com.io7m.claypot.core.Claypot") +public abstract class CLPAbstractCommand implements CLPCommandType +{ + private final JCommander commander; + private final CLPCommandContextType context; + + @Parameter( + names = "--verbose", + converter = CLPLogLevelConverter.class, + descriptionKey = "com.io7m.claypot.rootDescription" + ) + private CLPLogLevel verbose = CLPLogLevel.LOG_INFO; + + /** + * Construct a command. + * + * @param inContext The command context + */ + + public CLPAbstractCommand( + final CLPCommandContextType inContext) + { + this.context = Objects.requireNonNull(inContext, "context"); + this.commander = this.context.commander(); + } + + protected final JCommander commander() + { + return this.commander; + } + + protected final CLPCommandContextType context() + { + return this.context; + } + + protected final Logger logger() + { + return this.configuration().logger(); + } + + protected final CLPApplicationConfiguration configuration() + { + return this.context().configuration(); + } + + protected abstract Status executeActual() + throws Exception; + + /** + * Set up logging for other commands. + * + * @return The command status + * + * @throws Exception On errors + */ + + @Override + public final Status execute() + throws Exception + { + if (this.verbose == null) { + this.verbose = CLPLogLevel.LOG_INFO; + } + + final ch.qos.logback.classic.Logger root = + (ch.qos.logback.classic.Logger) LoggerFactory.getLogger( + Logger.ROOT_LOGGER_NAME); + root.setLevel(this.verbose.toLevel()); + return this.executeActual(); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractStrings.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractStrings.java new file mode 100644 index 0000000..22c31dd --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPAbstractStrings.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import org.osgi.annotation.versioning.ProviderType; + +import java.text.MessageFormat; +import java.util.Objects; +import java.util.ResourceBundle; + +/** + * An abstract implementation of the {@link CLPStringsType} interface. + */ + +@ProviderType +public abstract class CLPAbstractStrings implements CLPStringsType +{ + private final ResourceBundle resources; + + protected CLPAbstractStrings( + final ResourceBundle inResources) + { + this.resources = Objects.requireNonNull(inResources, "inResources"); + } + + @Override + public final ResourceBundle resources() + { + return this.resources; + } + + @Override + public final String format( + final String id, + final Object... args) + { + Objects.requireNonNull(id, "id"); + Objects.requireNonNull(args, "args"); + return MessageFormat.format(this.resources.getString(id), args); + } +} + diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPApplicationConfigurationType.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPApplicationConfigurationType.java new file mode 100644 index 0000000..985c9a0 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPApplicationConfigurationType.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.io7m.immutables.styles.ImmutablesStyleType; +import org.immutables.value.Value; +import org.slf4j.Logger; + +import java.util.List; + +@ImmutablesStyleType +@Value.Immutable +public interface CLPApplicationConfigurationType +{ + Logger logger(); + + String programName(); + + List commands(); +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPBriefUsageFormatter.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPBriefUsageFormatter.java new file mode 100644 index 0000000..a44152f --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPBriefUsageFormatter.java @@ -0,0 +1,88 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.DefaultUsageFormatter; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.JCommander.ProgramName; +import com.beust.jcommander.Parameters; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Objects; + +public final class CLPBriefUsageFormatter extends DefaultUsageFormatter +{ + private final JCommander commander; + private final CLPStringsType strings; + + public CLPBriefUsageFormatter( + final JCommander inCommander) + { + super(inCommander); + + this.commander = + Objects.requireNonNull(inCommander, "commander"); + this.strings = + CLPStrings.create(); + } + + @Override + public void appendCommands( + final StringBuilder out, + final int indentCount, + final int descriptionIndent, + final String indent) + { + out.append('\n'); + out.append(indent); + out.append(" "); + out.append(this.strings.format("com.io7m.claypot.commands")); + out.append(":\n"); + + final var rawCommands = this.commander.getRawCommands(); + final var commandNames = new ArrayList<>(rawCommands.keySet()); + commandNames.sort(Comparator.comparing(ProgramName::getDisplayName)); + + for (final var commandName : commandNames) { + final var commands = rawCommands.get(commandName); + final Object arg = commands.getObjects().get(0); + final Parameters p = arg.getClass().getAnnotation(Parameters.class); + + if (p == null || !p.hidden()) { + final String description = + String.format( + " %-32s %s", + commandName.getDisplayName(), + this.getCommandDescription(commandName.getName()) + ); + + out.append(description); + out.append('\n'); + } + } + } + + @Override + public String toString() + { + return String.format( + "[CLPBriefUsageFormatter 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandConstructorType.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandConstructorType.java new file mode 100644 index 0000000..f4cb4d4 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandConstructorType.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +/** + * A command constructor. + */ + +public interface CLPCommandConstructorType +{ + CLPCommandType create(CLPCommandContextType context); +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandContextType.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandContextType.java new file mode 100644 index 0000000..e70fffc --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandContextType.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.JCommander; + +/** + * A command context. + */ + +public interface CLPCommandContextType +{ + CLPApplicationConfiguration configuration(); + + JCommander commander(); +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandHelp.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandHelp.java new file mode 100644 index 0000000..36480e7 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandHelp.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.DefaultUsageFormatter; +import com.beust.jcommander.Parameters; + +import static com.io7m.claypot.core.CLPCommandType.Status.SUCCESS; + +@Parameters( + resourceBundle = "com.io7m.claypot.core.Claypot", + commandDescriptionKey = "com.io7m.claypot.helpDescription") +public final class CLPCommandHelp extends CLPAbstractCommand +{ + public CLPCommandHelp( + final CLPCommandContextType inContext) + { + super(inContext); + } + + @Override + protected Status executeActual() + { + final var console = new CLPStringBuilderConsole(); + final var commander = this.commander(); + commander.setUsageFormatter(new DefaultUsageFormatter(commander)); + commander.setConsole(console); + commander.usage(); + + this.logger().info("{}", console.builder().toString()); + return SUCCESS; + } + + @Override + public String toString() + { + return String.format( + "[CLPCommandHelp 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } + + @Override + public String name() + { + return "help"; + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandRoot.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandRoot.java new file mode 100644 index 0000000..f142874 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandRoot.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import static com.io7m.claypot.core.CLPCommandType.Status.SUCCESS; + +public final class CLPCommandRoot extends CLPAbstractCommand +{ + public CLPCommandRoot( + final CLPCommandContextType inContext) + { + super(inContext); + } + + @Override + protected Status executeActual() + { + return SUCCESS; + } + + @Override + public String toString() + { + return String.format( + "[CLPCommandRoot 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } + + @Override + public String name() + { + return ""; + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandType.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandType.java new file mode 100644 index 0000000..b0c2773 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPCommandType.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * The base type of commands. + */ + +@ProviderType +public interface CLPCommandType +{ + /** + * @return The name of the command + */ + + String name(); + + /** + * Execute the command. + * + * @return The resulting command status + * + * @throws Exception On errors. + */ + + Status execute() + throws Exception; + + /** + * The result of executing a command. + */ + + enum Status + { + /** + * The command succeeded. + */ + + SUCCESS, + + /** + * The command failed. + */ + + FAILURE; + + /** + * @return The shell exit code + */ + + public int exitCode() + { + switch (this) { + case SUCCESS: + return 0; + case FAILURE: + return 1; + } + throw new IllegalStateException(); + } + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevel.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevel.java new file mode 100644 index 0000000..65b3c21 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevel.java @@ -0,0 +1,99 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import ch.qos.logback.classic.Level; + +import java.util.Objects; + +/** + * Log level. + */ + +public enum CLPLogLevel +{ + /** + * @see Level#TRACE + */ + + LOG_TRACE("trace"), + + /** + * @see Level#DEBUG + */ + + LOG_DEBUG("debug"), + + /** + * @see Level#INFO + */ + + LOG_INFO("info"), + + /** + * @see Level#WARN + */ + + LOG_WARN("warn"), + + /** + * @see Level#ERROR + */ + + LOG_ERROR("error"); + + + private final String name; + + CLPLogLevel(final String in_name) + { + this.name = Objects.requireNonNull(in_name, "Name"); + } + + @Override + public String toString() + { + return this.name; + } + + /** + * @return The short name of the level + */ + + public String getName() + { + return this.name; + } + + Level toLevel() + { + switch (this) { + case LOG_TRACE: + return Level.TRACE; + case LOG_DEBUG: + return Level.DEBUG; + case LOG_INFO: + return Level.INFO; + case LOG_WARN: + return Level.WARN; + case LOG_ERROR: + return Level.ERROR; + } + + throw new IllegalStateException(); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelConverter.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelConverter.java new file mode 100644 index 0000000..b49a336 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelConverter.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.IStringConverter; + +/** + * A converter for {@link CLPLogLevel} values. + */ + +public final class CLPLogLevelConverter + implements IStringConverter +{ + private final CLPStringsType strings; + + /** + * Construct a new converter. + */ + + public CLPLogLevelConverter() + { + this.strings = CLPStrings.create(); + } + + @Override + public CLPLogLevel convert(final String value) + { + for (final CLPLogLevel v : CLPLogLevel.values()) { + if (value.equals(v.getName())) { + return v; + } + } + + throw new CLPLogLevelUnrecognized( + this.strings.format("com.io7m.claypot.logLevelUnrecognized", value) + ); + } + + @Override + public String toString() + { + return String.format( + "[CLPLogLevelConverter 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelUnrecognized.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelUnrecognized.java new file mode 100644 index 0000000..d1566ab --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPLogLevelUnrecognized.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +/** + * A log level was unrecognized. + */ + +public final class CLPLogLevelUnrecognized extends RuntimeException +{ + /** + * Construct an exception. + * + * @param message The error message + */ + + CLPLogLevelUnrecognized(final String message) + { + super(message); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringBuilderConsole.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringBuilderConsole.java new file mode 100644 index 0000000..cd02266 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringBuilderConsole.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.internal.Console; + +public final class CLPStringBuilderConsole implements Console +{ + private final StringBuilder builder; + + public CLPStringBuilderConsole() + { + this.builder = new StringBuilder(128); + } + + @Override + public void print(final String s) + { + this.builder.append(s); + } + + @Override + public void println(final String s) + { + this.builder.append(s); + this.builder.append('\n'); + } + + public StringBuilder builder() + { + return this.builder; + } + + @Override + public char[] readPassword(final boolean b) + { + return new char[0]; + } + + @Override + public String toString() + { + return String.format( + "[CLPStringBuilderConsole 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStrings.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStrings.java new file mode 100644 index 0000000..2a13ad4 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStrings.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import java.util.ResourceBundle; + +public final class CLPStrings + extends CLPAbstractStrings +{ + private CLPStrings( + final ResourceBundle inResources) + { + super(inResources); + } + + public static CLPStringsType create() + { + return new CLPStrings( + ResourceBundle.getBundle("com.io7m.claypot.core.Claypot") + ); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringsType.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringsType.java new file mode 100644 index 0000000..9b46e36 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/CLPStringsType.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import java.text.MessageFormat; +import java.util.Objects; +import java.util.ResourceBundle; + +/** + * A provider of string resources. + */ + +public interface CLPStringsType +{ + /** + * @return The underlying resource bundle + */ + + ResourceBundle resources(); + + /** + * Format a message. + * + * @param id The string resource ID + * @param args Any required string format arguments + * + * @return A formatted string + * + * @see MessageFormat + */ + + default String format( + final String id, + final Object... args) + { + Objects.requireNonNull(id, "id"); + Objects.requireNonNull(args, "args"); + return MessageFormat.format(this.resources().getString(id), args); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/Claypot.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/Claypot.java new file mode 100644 index 0000000..cf4d182 --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/Claypot.java @@ -0,0 +1,217 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.core; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; +import org.slf4j.Logger; + +import java.util.HashMap; +import java.util.Objects; + +public final class Claypot +{ + private final CLPApplicationConfiguration configuration; + private final JCommander commander; + private final HashMap commandMap; + private final CLPStringsType strings; + private int exitCode; + + private Claypot( + final CLPApplicationConfiguration inConfiguration, + final JCommander inCommander, + final HashMap inCommandMap, + final CLPStringsType inStrings) + { + this.configuration = + Objects.requireNonNull(inConfiguration, "inConfiguration"); + this.commander = + Objects.requireNonNull(inCommander, "commander"); + this.commandMap = + Objects.requireNonNull(inCommandMap, "commandMap"); + this.strings = + Objects.requireNonNull(inStrings, "inStrings"); + } + + public static Claypot create( + final CLPApplicationConfiguration configuration) + { + final var strings = CLPStrings.create(); + + final var commander = new JCommander(); + final var context = new Context(commander, configuration); + + commander.setProgramName(configuration.programName()); + commander.addObject(new CLPCommandRoot(context)); + + final var constructors = + configuration.commands(); + final var commandMap = + new HashMap(constructors.size() + 1); + + commandMap.put("help", new CLPCommandHelp(context)); + + for (final var constructor : constructors) { + final var command = constructor.create(context); + final var name = command.name(); + if (commandMap.containsKey(name)) { + throw new IllegalStateException( + strings.format("com.io7m.claypot.commandConflict", name) + ); + } + commandMap.put(name, command); + } + + for (final var entry : commandMap.entrySet()) { + commander.addCommand(entry.getKey(), entry.getValue()); + } + + return new Claypot(configuration, commander, commandMap, strings); + } + + public int exitCode() + { + return this.exitCode; + } + + public void execute( + final String[] args) + { + final var logger = this.configuration.logger(); + + try { + this.commander.parse(args); + + final String cmd = this.commander.getParsedCommand(); + if (cmd == null) { + final var console = new CLPStringBuilderConsole(); + this.commander.setUsageFormatter(new CLPBriefUsageFormatter(this.commander)); + this.commander.setConsole(console); + this.commander.usage(); + logger.info("{}", console.builder().toString()); + this.exitCode = 1; + return; + } + + final CLPCommandType command = this.commandMap.get(cmd); + final CLPCommandType.Status status = command.execute(); + this.exitCode = status.exitCode(); + } catch (final ParameterException e) { + logger.error("{}", e.getMessage()); + this.exitCode = 1; + } catch (final Exception e) { + this.logExceptionFriendly(logger, false, e); + this.exitCode = 1; + } + } + + private void logExceptionFriendly( + final Logger logger, + final boolean isCause, + final Throwable e) + { + if (e == null) { + return; + } + + logger.error( + "{}{}: {}", + isCause ? this.strings.format("com.io7m.claypot.causedBy") : "", + e.getClass().getCanonicalName(), + e.getMessage()); + + if (logger.isDebugEnabled()) { + final var trace = new StringBuilder(256); + final String lineSeparator = System.lineSeparator(); + trace.append(lineSeparator); + final var elements = e.getStackTrace(); + for (final var element : elements) { + trace.append(" at "); + + final var moduleName = element.getModuleName(); + if (moduleName != null) { + trace.append(moduleName); + trace.append('/'); + } else { + trace.append("/"); + } + + trace.append(element.getClassName()); + trace.append('.'); + trace.append(element.getMethodName()); + trace.append('('); + trace.append(element.getFileName()); + trace.append(':'); + trace.append(element.getLineNumber()); + trace.append(')'); + trace.append(lineSeparator); + } + logger.debug( + "{}", + this.strings.format( + "com.io7m.claypot.stackTraceOf", + e.getClass().getCanonicalName(), + trace + )); + } + + final var causes = e.getSuppressed(); + if (causes.length > 0) { + for (final var cause : causes) { + this.logExceptionFriendly(logger, true, cause); + } + } + this.logExceptionFriendly(logger, true, e.getCause()); + } + + private static final class Context implements CLPCommandContextType + { + private final JCommander commander; + private final CLPApplicationConfiguration configuration; + + private Context( + final JCommander inCommander, + final CLPApplicationConfiguration inConfiguration) + { + this.commander = + Objects.requireNonNull(inCommander, "commander"); + this.configuration = + Objects.requireNonNull(inConfiguration, "inConfiguration"); + } + + @Override + public CLPApplicationConfiguration configuration() + { + return this.configuration; + } + + @Override + public JCommander commander() + { + return this.commander; + } + } + + @Override + public String toString() + { + return String.format( + "[Claypot 0x%s]", + Long.toUnsignedString(System.identityHashCode(this), 16) + ); + } +} diff --git a/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/package-info.java b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/package-info.java new file mode 100644 index 0000000..b4c157c --- /dev/null +++ b/com.io7m.claypot.core/src/main/java/com/io7m/claypot/core/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * JCommander conventions for io7m projects (Core) + */ + +@Export +@Version("1.0.0") +package com.io7m.claypot.core; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/com.io7m.claypot.core/src/main/resources/com/io7m/claypot/core/Claypot.properties b/com.io7m.claypot.core/src/main/resources/com/io7m/claypot/core/Claypot.properties new file mode 100644 index 0000000..95356a7 --- /dev/null +++ b/com.io7m.claypot.core/src/main/resources/com/io7m/claypot/core/Claypot.properties @@ -0,0 +1,23 @@ +# +# Copyright © 2020 Mark Raynsford http://io7m.com +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +com.io7m.claypot.commandConflict=Multiple commands registered with the same name: {0} +com.io7m.claypot.commands=Commands +com.io7m.claypot.helpDescription=Show a detailed help message describing all available commands. +com.io7m.claypot.logLevelUnrecognized=Unrecognized log level: {0} +com.io7m.claypot.rootDescription=Set the minimum logging verbosity level +com.io7m.claypot.stackTraceOf=Stacktrace of {0}: {1} +com.io7m.claypot.causedBy=Caused by: diff --git a/com.io7m.claypot.example/pom.xml b/com.io7m.claypot.example/pom.xml new file mode 100644 index 0000000..4380481 --- /dev/null +++ b/com.io7m.claypot.example/pom.xml @@ -0,0 +1,49 @@ + + + + + 4.0.0 + + + com.io7m.claypot + com.io7m.claypot + 0.0.1 + + + com.io7m.claypot.example + + JCommander conventions for io7m projects (Example application) + com.io7m.claypot.example + https://www.github.com/io7m/claypot + + + + ${project.groupId} + com.io7m.claypot.core + ${project.version} + + + + com.beust + jcommander + + + org.slf4j + slf4j-api + + + + org.osgi + org.osgi.annotation.bundle + provided + + + org.osgi + org.osgi.annotation.versioning + provided + + + + \ No newline at end of file diff --git a/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXEmptyMain.java b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXEmptyMain.java new file mode 100644 index 0000000..3bec8aa --- /dev/null +++ b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXEmptyMain.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.example; + +import com.io7m.claypot.core.CLPApplicationConfiguration; +import com.io7m.claypot.core.Claypot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class CEXEmptyMain +{ + private static final Logger LOG = + LoggerFactory.getLogger(CEXEmptyMain.class); + + private CEXEmptyMain() + { + + } + + public static void main( + final String[] args) + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(LOG) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(args); + System.exit(claypot.exitCode()); + } +} diff --git a/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXOthersMain.java b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXOthersMain.java new file mode 100644 index 0000000..dcc48dd --- /dev/null +++ b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXOthersMain.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.example; + +import com.io7m.claypot.core.CLPApplicationConfiguration; +import com.io7m.claypot.core.Claypot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class CEXOthersMain +{ + private static final Logger LOG = + LoggerFactory.getLogger(CEXOthersMain.class); + + private CEXOthersMain() + { + + } + + public static void main( + final String[] args) + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .addCommands(CEXRed::new) + .setLogger(LOG) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(args); + System.exit(claypot.exitCode()); + } +} diff --git a/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXRed.java b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXRed.java new file mode 100644 index 0000000..d6216f2 --- /dev/null +++ b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/CEXRed.java @@ -0,0 +1,42 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.example; + +import com.beust.jcommander.Parameters; +import com.io7m.claypot.core.CLPCommandContextType; +import com.io7m.claypot.core.CLPAbstractCommand; + +@Parameters(commandDescription = "Paint things red.") +public final class CEXRed extends CLPAbstractCommand +{ + public CEXRed(final CLPCommandContextType inContext) + { + super(inContext); + } + + @Override + protected Status executeActual() + { + return Status.SUCCESS; + } + + @Override + public String name() + { + return "red"; + } +} diff --git a/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/package-info.java b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/package-info.java new file mode 100644 index 0000000..adad157 --- /dev/null +++ b/com.io7m.claypot.example/src/main/java/com/io7m/claypot/example/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * JCommander conventions for io7m projects (Example) + */ + +@Export +@Version("1.0.0") +package com.io7m.claypot.example; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/com.io7m.claypot.example/src/main/resources/logback.xml b/com.io7m.claypot.example/src/main/resources/logback.xml new file mode 100644 index 0000000..eb4b83a --- /dev/null +++ b/com.io7m.claypot.example/src/main/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + + %level %logger: %msg%n + + System.err + + + + + + + diff --git a/com.io7m.claypot.tests/pom.xml b/com.io7m.claypot.tests/pom.xml new file mode 100644 index 0000000..9cc9842 --- /dev/null +++ b/com.io7m.claypot.tests/pom.xml @@ -0,0 +1,69 @@ + + + + + 4.0.0 + + + com.io7m.claypot + com.io7m.claypot + 0.0.1 + + + com.io7m.claypot.tests + + JCommander conventions for io7m projects (Test suite) + com.io7m.claypot.tests + https://www.github.com/io7m/claypot + + + true + + + + + ${project.groupId} + com.io7m.claypot.core + ${project.version} + + + + org.mockito + mockito-core + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.slf4j + slf4j-api + + + + org.osgi + org.osgi.annotation.versioning + provided + + + + + + + + org.jacoco + jacoco-maven-plugin + + + + + \ No newline at end of file diff --git a/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/ClaypotTest.java b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/ClaypotTest.java new file mode 100644 index 0000000..4cfc60f --- /dev/null +++ b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/ClaypotTest.java @@ -0,0 +1,214 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.tests; + +import com.io7m.claypot.core.CLPApplicationConfiguration; +import com.io7m.claypot.core.Claypot; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.verification.Times; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.AdditionalAnswers.delegatesTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public final class ClaypotTest +{ + private static final Logger LOG = LoggerFactory.getLogger(Claypot.class); + private Logger spyLog; + + @BeforeEach + public void setup() + { + this.spyLog = mock(Logger.class, delegatesTo(LOG)); + } + + @Test + public void noArgumentsShowsUsage() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{}); + + assertEquals(1, claypot.exitCode()); + final var captor = ArgumentCaptor.forClass(String.class); + verify(this.spyLog).info(eq("{}"), captor.capture()); + + final var argument = captor.getValue(); + assertTrue(argument.contains("Usage: cex")); + assertTrue(argument.contains("Commands:")); + } + + @Test + public void noArgumentsUnrecognizedLogLevel() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{"--verbose", "who-knows"}); + + assertEquals(1, claypot.exitCode()); + final var captor0 = ArgumentCaptor.forClass(String.class); + final var captor1 = ArgumentCaptor.forClass(String.class); + + verify(this.spyLog).error( + eq("{}{}: {}"), + any(), + captor0.capture(), + captor1.capture() + ); + + final var arg0 = captor0.getValue(); + final var arg1 = captor1.getValue(); + assertTrue(arg1.contains("Unrecognized log level: who-knows")); + } + + @Test + public void helpShowsDetailedUsage() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{"help"}); + + assertEquals(0, claypot.exitCode()); + final var captor = ArgumentCaptor.forClass(String.class); + verify(this.spyLog).info(eq("{}"), captor.capture()); + + final var argument = captor.getValue(); + assertTrue(argument.contains("Usage: cex")); + assertTrue(argument.contains("Usage: help [options]")); + } + + @Test + public void helpUnrecognizedParameter() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{"help", "--unrecognized"}); + + assertEquals(1, claypot.exitCode()); + final var captor = ArgumentCaptor.forClass(String.class); + verify(this.spyLog).error(eq("{}"), captor.capture()); + + final var argument = captor.getValue(); + assertTrue(argument.contains("Was passed main parameter '--unrecognized'")); + } + + @Test + public void commandCrashes() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .addCommands(CrashCommand::new) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{"crash"}); + + assertEquals(1, claypot.exitCode()); + final var captor1 = ArgumentCaptor.forClass(String.class); + final var captor2 = ArgumentCaptor.forClass(String.class); + verify(this.spyLog, new Times(2)) + .error( + eq("{}{}: {}"), + any(), + captor1.capture(), + captor2.capture()); + + final var argument = captor1.getValue(); + assertTrue(argument.contains("java.io.IOException")); + } + + @Test + public void commandCrashesVerbose() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .addCommands(CrashCommand::new) + .build(); + + final var claypot = Claypot.create(applicationConfiguration); + claypot.execute(new String[]{"crash", "--verbose", "debug"}); + + assertEquals(1, claypot.exitCode()); + + final var captor1 = ArgumentCaptor.forClass(String.class); + final var captor2 = ArgumentCaptor.forClass(String.class); + verify(this.spyLog, new Times(2)) + .error( + eq("{}{}: {}"), + any(), + captor1.capture(), + captor2.capture()); + + verify(this.spyLog, new Times(2)) + .debug(eq("{}"), captor2.capture()); + + final var arg0 = captor1.getValue(); + assertTrue(arg0.contains("java.io.IOException")); + + final var arg1 = captor2.getValue(); + assertTrue(arg1.contains("Stacktrace of java.io.IOException:")); + } + + @Test + public void commandDuplicate() + { + final var applicationConfiguration = + CLPApplicationConfiguration.builder() + .setProgramName("cex") + .setLogger(this.spyLog) + .addCommands(EmptyCommand::new) + .addCommands(EmptyCommand::new) + .build(); + + Assertions.assertThrows(IllegalStateException.class, () -> { + Claypot.create(applicationConfiguration); + }); + } +} diff --git a/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/CrashCommand.java b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/CrashCommand.java new file mode 100644 index 0000000..a16d86c --- /dev/null +++ b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/CrashCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.tests; + +import com.io7m.claypot.core.CLPAbstractCommand; +import com.io7m.claypot.core.CLPCommandContextType; + +import java.io.IOException; + +public final class CrashCommand extends CLPAbstractCommand +{ + /** + * Construct a command. + * + * @param inContext The command context + */ + + public CrashCommand( + final CLPCommandContextType inContext) + { + super(inContext); + } + + @Override + protected Status executeActual() + throws Exception + { + throw new IOException(new IOException()); + } + + @Override + public String name() + { + return "crash"; + } +} diff --git a/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/EmptyCommand.java b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/EmptyCommand.java new file mode 100644 index 0000000..dac591c --- /dev/null +++ b/com.io7m.claypot.tests/src/test/java/com/io7m/claypot/tests/EmptyCommand.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2020 Mark Raynsford http://io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package com.io7m.claypot.tests; + +import com.io7m.claypot.core.CLPAbstractCommand; +import com.io7m.claypot.core.CLPCommandContextType; + +import static com.io7m.claypot.core.CLPCommandType.Status.SUCCESS; + +public final class EmptyCommand extends CLPAbstractCommand +{ + /** + * Construct a command. + * + * @param inContext The command context + */ + + public EmptyCommand( + final CLPCommandContextType inContext) + { + super(inContext); + } + + @Override + protected Status executeActual() + { + return SUCCESS; + } + + @Override + public String name() + { + return "empty"; + } +} diff --git a/com.io7m.claypot.tests/src/test/resources/logback.xml b/com.io7m.claypot.tests/src/test/resources/logback.xml new file mode 100644 index 0000000..eb4b83a --- /dev/null +++ b/com.io7m.claypot.tests/src/test/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + + %level %logger: %msg%n + + System.err + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b138781 --- /dev/null +++ b/pom.xml @@ -0,0 +1,241 @@ + + + + + 4.0.0 + + + com.io7m.primogenitor + com.io7m.primogenitor.full + 5.0.0 + + + com.io7m.claypot + com.io7m.claypot + 0.0.1 + pom + + JCommander conventions for io7m projects + com.io7m.claypot + https://www.github.com/io7m/claypot + + + com.io7m.claypot.core + com.io7m.claypot.example + com.io7m.claypot.tests + + + + e6b8b59da8fb4d8383f26601bcc37d48 + 0.0.1 + 0.0.1-SNAPSHOT + 11,[14,15) + 5.7.0-M1 + 2.8.3 + + + + + ISC License + http://io7m.com/license/isc.txt + + + + + https://github.com/io7m/claypot + scm:git:https://github.com/io7m/claypot + scm:git:https://github.com/io7m/claypot + + + + + io7m + io7m + code@io7m.com + http://io7m.com + + + + + http://github.com/io7m/claypot/issues + GitHub Issues + + + + + io7m.com + io7m.com + https://www.io7m.com/software/claypot + + + sonatype-nexus-staging + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + Travis CI + https://travis-ci.org/io7m/claypot + + + + + + org.osgi + org.osgi.annotation.bundle + 1.0.0 + + + org.osgi + org.osgi.annotation.versioning + 1.1.0 + + + com.io7m.immutables.style + com.io7m.immutables.style + 0.0.1 + + + com.io7m.blackthorne + com.io7m.blackthorne.api + 0.0.5 + + + com.io7m.jxe + com.io7m.jxe.core + 0.0.2 + + + com.io7m.junreachable + com.io7m.junreachable.core + 3.0.0 + + + com.io7m.jlexing + com.io7m.jlexing.core + 2.0.0 + + + com.io7m.jaffirm + com.io7m.jaffirm.core + 3.0.4 + + + com.io7m.jranges + com.io7m.jranges.core + 4.0.0 + + + org.immutables + value + ${org.immutables.version} + + + org.slf4j + slf4j-api + 2.0.0-alpha1 + + + ch.qos.logback + logback-classic + 1.3.0-alpha4 + + + commons-io + commons-io + 2.6 + + + org.apache.commons + commons-lang3 + 3.10 + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + + + org.mock-server + mockserver-netty + 5.10.0 + + + com.beust + jcommander + 1.78 + + + nl.jqno.equalsverifier + equalsverifier + 3.1.13 + + + com.io7m.primogenitor + com.io7m.primogenitor.support + 5.0.0 + + + com.io7m.xstructural + com.io7m.xstructural.cmdline + 0.0.1 + + + com.github.marschall + memoryfilesystem + 2.1.0 + + + org.mockito + mockito-core + 3.3.3 + + + net.java.dev.jna + jna + 5.5.0 + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.immutables + value + ${org.immutables.version} + + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + + spotbugs-filter.xml + + + + + + com.io7m.minisite + com.io7m.minisite.maven_plugin + false + + + + + diff --git a/spotbugs-filter.xml b/spotbugs-filter.xml new file mode 100644 index 0000000..9997fe8 --- /dev/null +++ b/spotbugs-filter.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/site/resources/claypot.jpg b/src/site/resources/claypot.jpg new file mode 100644 index 0000000..98383c3 Binary files /dev/null and b/src/site/resources/claypot.jpg differ diff --git a/src/site/resources/documentation.xml b/src/site/resources/documentation.xml new file mode 100644 index 0000000..1ee34dc --- /dev/null +++ b/src/site/resources/documentation.xml @@ -0,0 +1,6 @@ + + +
+

User documentation

+

No user documentation is currently available.

+
diff --git a/src/site/resources/features.xml b/src/site/resources/features.xml new file mode 100644 index 0000000..6e09c09 --- /dev/null +++ b/src/site/resources/features.xml @@ -0,0 +1,10 @@ + + +
+
    +
  • OSGi-ready.
  • +
  • JPMS-ready
  • +
  • High coverage automated test suite
  • +
  • ISC license
  • +
+
diff --git a/src/site/resources/header.xml b/src/site/resources/header.xml new file mode 100644 index 0000000..4507597 --- /dev/null +++ b/src/site/resources/header.xml @@ -0,0 +1,8 @@ + +
+

+ io7m.com | software | claypot + +

+
+
diff --git a/src/site/resources/icon.png b/src/site/resources/icon.png new file mode 100644 index 0000000..002f655 Binary files /dev/null and b/src/site/resources/icon.png differ diff --git a/src/site/resources/overview.xml b/src/site/resources/overview.xml new file mode 100644 index 0000000..8e5e75b --- /dev/null +++ b/src/site/resources/overview.xml @@ -0,0 +1,28 @@ +
+

+ + Build status + + + Maven Central + + + Codacy + + + Codecov + +

+ +

+ The claypot package implements a small API over the excellent + JCommander command-line parser that implements + defaults and conventions that are used across many io7m + packages. +

+ +
diff --git a/src/site/resources/site.css b/src/site/resources/site.css new file mode 100644 index 0000000..e4bb857 --- /dev/null +++ b/src/site/resources/site.css @@ -0,0 +1,7 @@ +p.shields a { + text-decoration: none; +} + +#header { + font-family: monospace; +}