added Wcfg file parser and CLI
This commit is contained in:
12
wson-cli/src/main/java/module-info.java
Normal file
12
wson-cli/src/main/java/module-info.java
Normal file
@@ -0,0 +1,12 @@
|
||||
module net.woggioni.wson.cli {
|
||||
requires static lombok;
|
||||
requires net.woggioni.jwo;
|
||||
requires net.woggioni.wson;
|
||||
requires net.woggioni.wson.wcfg;
|
||||
requires org.slf4j;
|
||||
requires org.slf4j.simple;
|
||||
requires info.picocli;
|
||||
exports net.woggioni.wson.cli;
|
||||
|
||||
opens net.woggioni.wson.cli to info.picocli;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
|
||||
abstract class AbstractVersionProvider implements CommandLine.IVersionProvider {
|
||||
private String version;
|
||||
private String vcsHash;
|
||||
|
||||
@SneakyThrows
|
||||
protected AbstractVersionProvider(String specificationTitle) {
|
||||
String version = null;
|
||||
String vcsHash = null;
|
||||
Enumeration<URL> it = getClass().getClassLoader().getResources(JarFile.MANIFEST_NAME);
|
||||
while (it.hasMoreElements()) {
|
||||
URL manifestURL = it.nextElement();
|
||||
Manifest mf = new Manifest();
|
||||
try (InputStream inputStream = manifestURL.openStream()) {
|
||||
mf.read(inputStream);
|
||||
}
|
||||
Attributes mainAttributes = mf.getMainAttributes();
|
||||
if (Objects.equals(specificationTitle, mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE))) {
|
||||
version = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
|
||||
vcsHash = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
}
|
||||
}
|
||||
if (version == null || vcsHash == null) {
|
||||
throw new RuntimeException("Version information not found in manifest");
|
||||
}
|
||||
this.version = version;
|
||||
this.vcsHash = vcsHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getVersion() {
|
||||
if (version.endsWith("-SNAPSHOT")) {
|
||||
return new String[]{version, vcsHash};
|
||||
} else {
|
||||
return new String[]{version};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.woggioni.jwo.JWO.newThrowable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
enum SerializationFormat {
|
||||
JSON("json"), JBON("jbon");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
public static SerializationFormat parse(String value) {
|
||||
return Arrays.stream(SerializationFormat.values())
|
||||
.filter(sf -> Objects.equals(sf.name, value))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> {
|
||||
var availableValues = Stream.of(
|
||||
JSON,
|
||||
JBON
|
||||
).map(SerializationFormat::name).collect(Collectors.joining(", "));
|
||||
throw newThrowable(IllegalArgumentException.class,
|
||||
"Unknown serialization format '%s', possible values are %s",
|
||||
value, availableValues
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import picocli.CommandLine;
|
||||
|
||||
class SerializationTypeConverter implements CommandLine.ITypeConverter<SerializationFormat> {
|
||||
@Override
|
||||
public SerializationFormat convert(String value) {
|
||||
return SerializationFormat.parse(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
class VersionProvider extends AbstractVersionProvider {
|
||||
protected VersionProvider() {
|
||||
super("wson-cli");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.jwo.Fun;
|
||||
import net.woggioni.wson.serialization.binary.JBONDumper;
|
||||
import net.woggioni.wson.serialization.json.JSONDumper;
|
||||
import net.woggioni.wson.value.ObjectValue;
|
||||
import net.woggioni.wson.wcfg.WConfig;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "wcfg",
|
||||
versionProvider = VersionProvider.class)
|
||||
public class WcfgCommand implements Runnable {
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"-f", "--file"},
|
||||
description = {"Name of the input file to parse"}
|
||||
)
|
||||
private Path fileName;
|
||||
|
||||
@CommandLine.Option(names = {"-o", "--output"},
|
||||
description = {"Name of the JSON file to generate"})
|
||||
private Path output;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"-t", "--type"},
|
||||
description = {"Output type"},
|
||||
converter = {SerializationTypeConverter.class})
|
||||
private SerializationFormat outputType = SerializationFormat.JSON;
|
||||
|
||||
@CommandLine.Option(names = {"-d", "--resolve-refernces"}, description = "Resolve references")
|
||||
private boolean resolveReferences = false;
|
||||
|
||||
@CommandLine.Option(names = {"-h", "--help"}, usageHelp = true)
|
||||
private boolean help = false;
|
||||
|
||||
@SneakyThrows
|
||||
public void run() {
|
||||
Value.Configuration cfg = Value.Configuration.builder()
|
||||
.objectValueImplementation(ObjectValue.Implementation.LinkedHashMap)
|
||||
.serializeReferences(!resolveReferences)
|
||||
.build();
|
||||
InputStream inputStream;
|
||||
if (fileName != null) {
|
||||
inputStream = new BufferedInputStream(Files.newInputStream(fileName));
|
||||
} else {
|
||||
inputStream = System.in;
|
||||
}
|
||||
|
||||
Value result;
|
||||
try(Reader reader = new InputStreamReader(inputStream)) {
|
||||
WConfig wcfg = WConfig.parse(reader, cfg);
|
||||
result = wcfg.whole();
|
||||
}
|
||||
|
||||
|
||||
OutputStream outputStream = Optional.ofNullable(output)
|
||||
.map((Fun<Path, OutputStream>) Files::newOutputStream)
|
||||
.<OutputStream>map(BufferedOutputStream::new)
|
||||
.orElse(System.out);
|
||||
|
||||
switch (outputType) {
|
||||
case JSON:
|
||||
try (Writer writer = new OutputStreamWriter(outputStream)) {
|
||||
new JSONDumper(cfg).dump(result, writer);
|
||||
}
|
||||
break;
|
||||
case JBON:
|
||||
try {
|
||||
new JBONDumper(cfg).dump(result, outputStream);
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
wson-cli/src/main/java/net/woggioni/wson/cli/WsonCli.java
Normal file
33
wson-cli/src/main/java/net/woggioni/wson/cli/WsonCli.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@Slf4j
|
||||
@CommandLine.Command(
|
||||
name = "wcfg",
|
||||
versionProvider = VersionProvider.class,
|
||||
subcommands = {WsonCommand.class, WcfgCommand.class})
|
||||
public class WsonCli implements Runnable {
|
||||
public static void main(String[] args) {
|
||||
final var commandLine = new CommandLine(new WsonCli());
|
||||
commandLine.setExecutionExceptionHandler((ex, cl, parseResult) -> {
|
||||
log.error(ex.getMessage(), ex);
|
||||
return CommandLine.ExitCode.SOFTWARE;
|
||||
});
|
||||
System.exit(commandLine.execute(args));
|
||||
}
|
||||
|
||||
@Getter
|
||||
@CommandLine.Option(names = {"-V", "--version"}, versionHelp = true)
|
||||
private boolean versionHelp;
|
||||
|
||||
@CommandLine.Spec
|
||||
private CommandLine.Model.CommandSpec spec;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
spec.commandLine().usage(System.out);
|
||||
}
|
||||
}
|
||||
104
wson-cli/src/main/java/net/woggioni/wson/cli/WsonCommand.java
Normal file
104
wson-cli/src/main/java/net/woggioni/wson/cli/WsonCommand.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package net.woggioni.wson.cli;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.jwo.Fun;
|
||||
import net.woggioni.wson.serialization.binary.JBONDumper;
|
||||
import net.woggioni.wson.serialization.binary.JBONParser;
|
||||
import net.woggioni.wson.serialization.json.JSONDumper;
|
||||
import net.woggioni.wson.serialization.json.JSONParser;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
import static net.woggioni.jwo.JWO.newThrowable;
|
||||
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "wson",
|
||||
versionProvider = VersionProvider.class)
|
||||
public class WsonCommand implements Runnable {
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"-f", "--file"},
|
||||
description = {"Name of the input file to parse"}
|
||||
)
|
||||
private Path fileName;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--input-type"},
|
||||
description = {"Input type"},
|
||||
converter = {SerializationTypeConverter.class})
|
||||
private SerializationFormat inputType = SerializationFormat.JSON;
|
||||
|
||||
@CommandLine.Option(names = {"-o", "--output"},
|
||||
description = {"Name of the JSON file to generate"})
|
||||
private Path output;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"-t", "--type"},
|
||||
description = {"Output type"},
|
||||
converter = {SerializationTypeConverter.class})
|
||||
private SerializationFormat outputType = SerializationFormat.JSON;
|
||||
|
||||
@CommandLine.Option(names = {"-h", "--help"}, usageHelp = true)
|
||||
private boolean help = false;
|
||||
|
||||
@SneakyThrows
|
||||
public void run() {
|
||||
Value.Configuration cfg = Value.Configuration.builder().serializeReferences(true).build();
|
||||
InputStream inputStream;
|
||||
if (fileName != null) {
|
||||
inputStream = new BufferedInputStream(Files.newInputStream(fileName));
|
||||
} else {
|
||||
inputStream = System.in;
|
||||
}
|
||||
|
||||
Value result;
|
||||
switch (inputType) {
|
||||
case JSON:
|
||||
try (Reader reader = new InputStreamReader(inputStream)) {
|
||||
result = new JSONParser(cfg).parse(reader);
|
||||
}
|
||||
break;
|
||||
case JBON:
|
||||
try {
|
||||
result = new JBONParser(cfg).parse(inputStream);
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw newThrowable(RuntimeException.class, "This sohuld never happen");
|
||||
}
|
||||
|
||||
OutputStream outputStream = Optional.ofNullable(output)
|
||||
.map((Fun<Path, OutputStream>) Files::newOutputStream)
|
||||
.<OutputStream>map(BufferedOutputStream::new)
|
||||
.orElse(System.out);
|
||||
|
||||
switch (outputType) {
|
||||
case JSON:
|
||||
try (Writer writer = new OutputStreamWriter(outputStream)) {
|
||||
new JSONDumper(cfg).dump(result, writer);
|
||||
}
|
||||
break;
|
||||
case JBON:
|
||||
try {
|
||||
new JBONDumper(cfg).dump(result, outputStream);
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
module net.woggioni.wson.cli {
|
||||
requires kotlin.stdlib;
|
||||
requires kotlin.stdlib.jdk8;
|
||||
requires net.woggioni.wson;
|
||||
requires com.beust.jcommander;
|
||||
exports net.woggioni.wson.cli;
|
||||
|
||||
opens net.woggioni.wson.cli to com.beust.jcommander;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.woggioni.wson.cli
|
||||
|
||||
import java.net.URL
|
||||
import java.util.Enumeration
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.Manifest
|
||||
import lombok.SneakyThrows
|
||||
import picocli.CommandLine
|
||||
|
||||
|
||||
abstract class AbstractVersionProvider @SneakyThrows protected constructor(specificationTitle: String?) :
|
||||
CommandLine.IVersionProvider {
|
||||
private val version: String
|
||||
private val vcsHash: String
|
||||
|
||||
init {
|
||||
var version: String? = null
|
||||
var vcsHash: String? = null
|
||||
val it: Enumeration<URL> = javaClass.classLoader.getResources(JarFile.MANIFEST_NAME)
|
||||
while (it.hasMoreElements()) {
|
||||
val manifestURL: URL = it.nextElement()
|
||||
val mf = Manifest()
|
||||
manifestURL.openStream().use(mf::read)
|
||||
val mainAttributes: Attributes = mf.mainAttributes
|
||||
if (specificationTitle == mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE)) {
|
||||
version = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION)
|
||||
vcsHash = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION)
|
||||
}
|
||||
}
|
||||
if (version == null || vcsHash == null) {
|
||||
throw RuntimeException("Version information not found in manifest")
|
||||
}
|
||||
this.version = version
|
||||
this.vcsHash = vcsHash
|
||||
}
|
||||
|
||||
override fun getVersion(): Array<String?> {
|
||||
return if (version.endsWith("-SNAPSHOT")) {
|
||||
arrayOf(version, vcsHash)
|
||||
} else {
|
||||
arrayOf(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,13 @@ import java.io.OutputStreamWriter
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.system.exitProcess
|
||||
import com.beust.jcommander.IStringConverter
|
||||
import com.beust.jcommander.JCommander
|
||||
import com.beust.jcommander.Parameter
|
||||
import com.beust.jcommander.ParameterException
|
||||
import com.beust.jcommander.converters.PathConverter
|
||||
import net.woggioni.wson.serialization.binary.JBONDumper
|
||||
import net.woggioni.wson.serialization.binary.JBONParser
|
||||
import net.woggioni.wson.serialization.json.JSONDumper
|
||||
import net.woggioni.wson.serialization.json.JSONParser
|
||||
import net.woggioni.wson.xface.Value
|
||||
import org.slf4j.LoggerFactory
|
||||
import picocli.CommandLine
|
||||
|
||||
|
||||
sealed class SerializationFormat(val name: String) {
|
||||
@@ -41,88 +38,99 @@ sealed class SerializationFormat(val name: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private class OutputTypeConverter : IStringConverter<SerializationFormat> {
|
||||
class OutputTypeConverter : CommandLine.ITypeConverter<SerializationFormat> {
|
||||
override fun convert(value: String): SerializationFormat = SerializationFormat.parse(value)
|
||||
}
|
||||
|
||||
private class CliArg {
|
||||
|
||||
@Parameter(names = ["-f", "--file"], description = "Name of the input file to parse", converter = PathConverter::class)
|
||||
class VersionProvider internal constructor() : AbstractVersionProvider("wson-cli")
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "wson-cli",
|
||||
versionProvider = VersionProvider::class)
|
||||
private class WsonCli : Runnable {
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-f", "--file"],
|
||||
description = ["Name of the input file to parse"],
|
||||
)
|
||||
var fileName: Path? = null
|
||||
|
||||
@Parameter(names = ["--input-type"], description = "Input type", converter = OutputTypeConverter::class)
|
||||
@CommandLine.Option(
|
||||
names = ["--input-type"],
|
||||
description = ["Input type"],
|
||||
converter = [OutputTypeConverter::class])
|
||||
var inputType: SerializationFormat = SerializationFormat.JSON
|
||||
|
||||
@Parameter(names = ["-o", "--output"], description = "Name of the JSON file to generate", converter = PathConverter::class)
|
||||
@CommandLine.Option(names = ["-o", "--output"],
|
||||
description = ["Name of the JSON file to generate"])
|
||||
var output: Path? = null
|
||||
|
||||
@Parameter(names = ["-t", "--type"], description = "Output type", converter = OutputTypeConverter::class)
|
||||
@CommandLine.Option(
|
||||
names = ["-t", "--type"],
|
||||
description = ["Output type"],
|
||||
converter = [OutputTypeConverter::class])
|
||||
var outputType: SerializationFormat = SerializationFormat.JSON
|
||||
|
||||
@Parameter(names = ["-h", "--help"], help = true)
|
||||
@CommandLine.Option(names = ["-h", "--help"], usageHelp = true)
|
||||
var help: Boolean = false
|
||||
|
||||
override fun run() {
|
||||
val cfg = Value.Configuration.builder().serializeReferences(true).build()
|
||||
val inputStream = if (fileName != null) {
|
||||
BufferedInputStream(Files.newInputStream(fileName))
|
||||
} else {
|
||||
System.`in`
|
||||
}
|
||||
|
||||
val result = when(inputType) {
|
||||
SerializationFormat.JSON -> {
|
||||
val reader = InputStreamReader(inputStream)
|
||||
try {
|
||||
JSONParser(cfg).parse(reader)
|
||||
} finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
SerializationFormat.JBON -> {
|
||||
try {
|
||||
JBONParser(cfg).parse(inputStream)
|
||||
} finally {
|
||||
inputStream.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val outputStream = output?.let {
|
||||
BufferedOutputStream(Files.newOutputStream(it))
|
||||
} ?: System.out
|
||||
when(outputType) {
|
||||
SerializationFormat.JSON -> {
|
||||
val writer = OutputStreamWriter(outputStream)
|
||||
try {
|
||||
JSONDumper(cfg).dump(result, writer)
|
||||
} finally {
|
||||
writer.close()
|
||||
}
|
||||
}
|
||||
SerializationFormat.JBON -> {
|
||||
try {
|
||||
JBONDumper(cfg).dump(result, outputStream)
|
||||
} finally {
|
||||
outputStream.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun main(vararg args: String) {
|
||||
val cliArg = CliArg()
|
||||
val cliArgumentParser = JCommander.newBuilder()
|
||||
.addObject(cliArg)
|
||||
.build()
|
||||
try {
|
||||
cliArgumentParser.parse(*args)
|
||||
} catch (pe: ParameterException) {
|
||||
cliArgumentParser.usage()
|
||||
exitProcess(-1)
|
||||
}
|
||||
if (cliArg.help) {
|
||||
cliArgumentParser.usage()
|
||||
exitProcess(0)
|
||||
}
|
||||
val cfg = Value.Configuration.builder().serializeReferences(true).build()
|
||||
val inputStream = if (cliArg.fileName != null) {
|
||||
BufferedInputStream(Files.newInputStream(cliArg.fileName))
|
||||
} else {
|
||||
System.`in`
|
||||
}
|
||||
|
||||
val result = when(cliArg.inputType) {
|
||||
SerializationFormat.JSON -> {
|
||||
val reader = InputStreamReader(inputStream)
|
||||
try {
|
||||
JSONParser(cfg).parse(reader)
|
||||
} finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
SerializationFormat.JBON -> {
|
||||
try {
|
||||
JBONParser(cfg).parse(inputStream)
|
||||
} finally {
|
||||
inputStream.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val outputStream = if (cliArg.output != null) {
|
||||
BufferedOutputStream(Files.newOutputStream(cliArg.output))
|
||||
} else {
|
||||
System.out
|
||||
}
|
||||
when(cliArg.outputType) {
|
||||
SerializationFormat.JSON -> {
|
||||
val writer = OutputStreamWriter(outputStream)
|
||||
try {
|
||||
JSONDumper(cfg).dump(result, writer)
|
||||
} finally {
|
||||
writer.close()
|
||||
}
|
||||
}
|
||||
SerializationFormat.JBON -> {
|
||||
try {
|
||||
JBONDumper(cfg).dump(result, outputStream)
|
||||
} finally {
|
||||
outputStream.close()
|
||||
}
|
||||
}
|
||||
val log = LoggerFactory.getLogger("wson-cli")
|
||||
val commandLine = CommandLine(WsonCli())
|
||||
commandLine.setExecutionExceptionHandler { ex, cl, parseResult ->
|
||||
log.error(ex.message, ex)
|
||||
CommandLine.ExitCode.SOFTWARE
|
||||
}
|
||||
exitProcess(commandLine.execute(*args))
|
||||
}
|
||||
Reference in New Issue
Block a user