Skip to content

Commit 77b0676

Browse files
authored
Adopt a new CLI parsing library from Sourcemeta Core (#435)
Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 495cedc commit 77b0676

27 files changed

+652
-288
lines changed

DEPENDENCIES

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a4140267959ae334d3ecf4
2-
core https://github.com/sourcemeta/core 2951f08dadba6003aea55a28e2871cd04c5adb75
2+
core https://github.com/sourcemeta/core 7d7de98576f3d5c27dd340fd9ecde769eacb7961
33
jsonbinpack https://github.com/sourcemeta/jsonbinpack 3a5e2e37ad664be277a34145a9efc0ab14558421
44
blaze https://github.com/sourcemeta/blaze c907bb924fd21391b02aa15a80316710a3355295
55
curl https://github.com/curl/curl curl-8_14_0

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::jsonpointer)
2424
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::jsonschema)
2525
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::yaml)
2626
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::alterschema)
27+
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::options)
2728
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsonbinpack::compiler)
2829
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsonbinpack::runtime)
2930
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::compiler)

src/command.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
#ifndef SOURCEMETA_JSONSCHEMA_CLI_COMMAND_H_
22
#define SOURCEMETA_JSONSCHEMA_CLI_COMMAND_H_
33

4-
#include <span> // std::span
5-
#include <string> // std::string
4+
#include <sourcemeta/core/options.h>
65

76
namespace sourcemeta::jsonschema::cli {
8-
auto fmt(const std::span<const std::string> &arguments) -> int;
9-
auto inspect(const std::span<const std::string> &arguments) -> int;
10-
auto bundle(const std::span<const std::string> &arguments) -> int;
11-
auto test(const std::span<const std::string> &arguments) -> int;
12-
auto lint(const std::span<const std::string> &arguments) -> int;
13-
auto validate(const std::span<const std::string> &arguments) -> int;
14-
auto metaschema(const std::span<const std::string> &arguments) -> int;
15-
auto compile(const std::span<const std::string> &arguments) -> int;
16-
auto encode(const std::span<const std::string> &arguments) -> int;
17-
auto decode(const std::span<const std::string> &arguments) -> int;
7+
auto fmt(const sourcemeta::core::Options &options) -> int;
8+
auto inspect(const sourcemeta::core::Options &options) -> int;
9+
auto bundle(const sourcemeta::core::Options &options) -> int;
10+
auto test(const sourcemeta::core::Options &options) -> int;
11+
auto lint(const sourcemeta::core::Options &options) -> int;
12+
auto validate(const sourcemeta::core::Options &options) -> int;
13+
auto metaschema(const sourcemeta::core::Options &options) -> int;
14+
auto compile(const sourcemeta::core::Options &options) -> int;
15+
auto encode(const sourcemeta::core::Options &options) -> int;
16+
auto decode(const sourcemeta::core::Options &options) -> int;
1817
} // namespace sourcemeta::jsonschema::cli
1918

2019
#endif

src/command_bundle.cc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,19 @@
1010
#include "utils.h"
1111

1212
auto sourcemeta::jsonschema::cli::bundle(
13-
const std::span<const std::string> &arguments) -> int {
14-
const auto options{
15-
parse_options(arguments, {"h", "http", "w", "without-id"})};
13+
const sourcemeta::core::Options &options) -> int {
1614
const auto dialect{default_dialect(options)};
1715

18-
if (options.at("").size() < 1) {
16+
if (options.positional().size() < 1) {
1917
std::cerr
2018
<< "error: This command expects a path to a schema. For example:\n\n"
2119
<< " jsonschema bundle path/to/schema.json\n";
2220
return EXIT_FAILURE;
2321
}
2422

25-
const std::filesystem::path schema_path{options.at("").front()};
26-
const auto custom_resolver{resolver(
27-
options, options.contains("h") || options.contains("http"), dialect)};
23+
const std::filesystem::path schema_path{options.positional().front()};
24+
const auto custom_resolver{
25+
resolver(options, options.contains("http"), dialect)};
2826
auto schema{sourcemeta::core::read_yaml_or_json(schema_path)};
2927

3028
sourcemeta::core::bundle(schema, sourcemeta::core::schema_official_walker,
@@ -33,7 +31,7 @@ auto sourcemeta::jsonschema::cli::bundle(
3331
sourcemeta::core::weakly_canonical(schema_path))
3432
.recompose());
3533

36-
if (options.contains("w") || options.contains("without-id")) {
34+
if (options.contains("without-id")) {
3735
std::cerr << "warning: You are opting in to remove schema identifiers in "
3836
"the bundled schema.\n";
3937
std::cerr << "The only legit use case of this advanced feature we know of "

src/command_compile.cc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,18 @@
1212
#include "utils.h"
1313

1414
auto sourcemeta::jsonschema::cli::compile(
15-
const std::span<const std::string> &arguments) -> int {
16-
const auto options{parse_options(arguments, {"h", "http", "f", "fast"})};
17-
18-
if (options.at("").size() < 1) {
15+
const sourcemeta::core::Options &options) -> int {
16+
if (options.positional().size() < 1) {
1917
std::cerr
2018
<< "error: This command expects a path to a schema. For example:\n\n"
2119
<< " jsonschema compile path/to/schema.json\n";
2220
return EXIT_FAILURE;
2321
}
2422

25-
const auto &schema_path{options.at("").at(0)};
23+
const auto &schema_path{options.positional().at(0)};
2624
const auto dialect{default_dialect(options)};
27-
const auto custom_resolver{resolver(
28-
options, options.contains("h") || options.contains("http"), dialect)};
25+
const auto custom_resolver{
26+
resolver(options, options.contains("http"), dialect)};
2927

3028
const auto schema{sourcemeta::core::read_yaml_or_json(schema_path)};
3129

@@ -37,7 +35,7 @@ auto sourcemeta::jsonschema::cli::compile(
3735
return EXIT_FAILURE;
3836
}
3937

40-
const auto fast_mode{options.contains("f") || options.contains("fast")};
38+
const auto fast_mode{options.contains("fast")};
4139
const auto schema_template{sourcemeta::blaze::compile(
4240
schema, sourcemeta::core::schema_official_walker, custom_resolver,
4341
sourcemeta::blaze::default_schema_compiler,

src/command_decode.cc

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ static auto has_data(std::ifstream &stream) -> bool {
2828
}
2929

3030
auto sourcemeta::jsonschema::cli::decode(
31-
const std::span<const std::string> &arguments) -> int {
32-
const auto options{parse_options(arguments, {})};
33-
34-
if (options.at("").size() < 2) {
31+
const sourcemeta::core::Options &options) -> int {
32+
if (options.positional().size() < 2) {
3533
std::cerr
3634
<< "error: This command expects a path to a binary file and an "
3735
"output path. For example:\n\n"
@@ -47,27 +45,27 @@ auto sourcemeta::jsonschema::cli::decode(
4745
const auto dialect{default_dialect(options)};
4846
sourcemeta::jsonbinpack::compile(
4947
schema, sourcemeta::core::schema_official_walker,
50-
resolver(options, options.contains("h") || options.contains("http"),
51-
dialect));
48+
resolver(options, options.contains("http"), dialect));
5249
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
5350

5451
std::ifstream input_stream{
55-
sourcemeta::core::weakly_canonical(options.at("").front()),
52+
sourcemeta::core::weakly_canonical(options.positional().front()),
5653
std::ios::binary};
5754
assert(!input_stream.fail());
5855
assert(input_stream.is_open());
5956

60-
const std::filesystem::path output{options.at("").at(1)};
57+
const std::filesystem::path output{options.positional().at(1)};
6158
std::ofstream output_stream(sourcemeta::core::weakly_canonical(output),
6259
std::ios::binary);
6360
output_stream.exceptions(std::ios_base::badbit);
6461
sourcemeta::jsonbinpack::Decoder decoder{input_stream};
6562

6663
if (output.extension() == ".jsonl") {
67-
log_verbose(options)
68-
<< "Interpreting input as JSONL: "
69-
<< sourcemeta::core::weakly_canonical(options.at("").front()).string()
70-
<< "\n";
64+
log_verbose(options) << "Interpreting input as JSONL: "
65+
<< sourcemeta::core::weakly_canonical(
66+
options.positional().front())
67+
.string()
68+
<< "\n";
7169

7270
std::size_t count{0};
7371
while (has_data(input_stream)) {

src/command_encode.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@
1616
#include "utils.h"
1717

1818
auto sourcemeta::jsonschema::cli::encode(
19-
const std::span<const std::string> &arguments) -> int {
20-
const auto options{parse_options(arguments, {})};
21-
22-
if (options.at("").size() < 2) {
19+
const sourcemeta::core::Options &options) -> int {
20+
if (options.positional().size() < 2) {
2321
std::cerr
2422
<< "error: This command expects a path to a JSON document and an "
2523
"output path. For example:\n\n"
@@ -35,11 +33,10 @@ auto sourcemeta::jsonschema::cli::encode(
3533
const auto dialect{default_dialect(options)};
3634
sourcemeta::jsonbinpack::compile(
3735
schema, sourcemeta::core::schema_official_walker,
38-
resolver(options, options.contains("h") || options.contains("http"),
39-
dialect));
36+
resolver(options, options.contains("http"), dialect));
4037
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
4138

42-
const std::filesystem::path document{options.at("").front()};
39+
const std::filesystem::path document{options.positional().front()};
4340
const auto original_size{std::filesystem::file_size(document)};
4441
std::cerr << "original file size: " << original_size << " bytes\n";
4542

@@ -50,7 +47,7 @@ auto sourcemeta::jsonschema::cli::encode(
5047

5148
auto stream{sourcemeta::core::read_file(document)};
5249
std::ofstream output_stream(
53-
sourcemeta::core::weakly_canonical(options.at("").at(1)),
50+
sourcemeta::core::weakly_canonical(options.positional().at(1)),
5451
std::ios::binary);
5552
output_stream.exceptions(std::ios_base::badbit);
5653
sourcemeta::jsonbinpack::Encoder encoder{output_stream};
@@ -70,9 +67,9 @@ auto sourcemeta::jsonschema::cli::encode(
7067
<< "%\n";
7168
} else {
7269
const auto entry{
73-
sourcemeta::core::read_yaml_or_json(options.at("").front())};
70+
sourcemeta::core::read_yaml_or_json(options.positional().front())};
7471
std::ofstream output_stream(
75-
sourcemeta::core::weakly_canonical(options.at("").at(1)),
72+
sourcemeta::core::weakly_canonical(options.positional().at(1)),
7673
std::ios::binary);
7774
output_stream.exceptions(std::ios_base::badbit);
7875
sourcemeta::jsonbinpack::Encoder encoder{output_stream};

src/command_fmt.cc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,25 @@
99
#include "command.h"
1010
#include "utils.h"
1111

12-
auto sourcemeta::jsonschema::cli::fmt(
13-
const std::span<const std::string> &arguments) -> int {
14-
const auto options{
15-
parse_options(arguments, {"c", "check", "k", "keep-ordering"})};
16-
17-
for (const auto &entry : for_each_json(options.at(""), parse_ignore(options),
18-
parse_extensions(options))) {
12+
auto sourcemeta::jsonschema::cli::fmt(const sourcemeta::core::Options &options)
13+
-> int {
14+
for (const auto &entry :
15+
for_each_json(options.positional(), parse_ignore(options),
16+
parse_extensions(options))) {
1917
if (entry.first.extension() == ".yaml" ||
2018
entry.first.extension() == ".yml") {
2119
std::cerr << "This command does not support YAML input files yet\n";
2220
return EXIT_FAILURE;
2321
}
2422

25-
if (options.contains("c") || options.contains("check")) {
23+
if (options.contains("check")) {
2624
log_verbose(options) << "Checking: " << entry.first.string() << "\n";
2725
std::ifstream input{entry.first};
2826
std::ostringstream buffer;
2927
buffer << input.rdbuf();
3028
std::ostringstream expected;
3129

32-
if (options.contains("k") || options.contains("keep-ordering")) {
30+
if (options.contains("keep-ordering")) {
3331
sourcemeta::core::prettify(entry.second, expected);
3432
} else {
3533
sourcemeta::core::prettify(entry.second, expected,
@@ -51,7 +49,7 @@ auto sourcemeta::jsonschema::cli::fmt(
5149
log_verbose(options) << "Formatting: " << entry.first.string() << "\n";
5250
std::ofstream output{entry.first};
5351

54-
if (options.contains("k") || options.contains("keep-ordering")) {
52+
if (options.contains("keep-ordering")) {
5553
sourcemeta::core::prettify(entry.second, output);
5654
} else {
5755
sourcemeta::core::prettify(entry.second, output,

src/command_inspect.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,21 @@ auto operator<<(std::ostream &stream,
127127
}
128128

129129
auto sourcemeta::jsonschema::cli::inspect(
130-
const std::span<const std::string> &arguments) -> int {
131-
const auto options{parse_options(arguments, {})};
132-
if (options.at("").size() < 1) {
130+
const sourcemeta::core::Options &options) -> int {
131+
if (options.positional().size() < 1) {
133132
std::cerr
134133
<< "error: This command expects a path to a schema. For example:\n\n"
135134
<< " jsonschema inspect path/to/schema.json\n";
136135
return EXIT_FAILURE;
137136
}
138137

139-
const std::filesystem::path schema_path{options.at("").front()};
138+
const std::filesystem::path schema_path{options.positional().front()};
140139
const sourcemeta::core::JSON schema{
141140
sourcemeta::core::read_yaml_or_json(schema_path)};
142141

143142
const auto dialect{default_dialect(options)};
144-
const auto custom_resolver{resolver(
145-
options, options.contains("h") || options.contains("http"), dialect)};
143+
const auto custom_resolver{
144+
resolver(options, options.contains("http"), dialect)};
146145
const auto identifier{sourcemeta::core::identify(
147146
schema, custom_resolver,
148147
sourcemeta::core::SchemaIdentificationStrategy::Strict, dialect)};
@@ -163,7 +162,7 @@ auto sourcemeta::jsonschema::cli::inspect(
163162
sourcemeta::core::weakly_canonical(schema_path))
164163
.recompose());
165164

166-
if (options.contains("json") || options.contains("j")) {
165+
if (options.contains("json")) {
167166
sourcemeta::core::prettify(frame.to_json(), std::cout);
168167
std::cout << "\n";
169168
} else {

src/command_lint.cc

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ static auto disable_lint_rules(sourcemeta::core::SchemaTransformer &bundle,
1919
const Options &options, Iterator first,
2020
Iterator last) -> void {
2121
for (auto iterator = first; iterator != last; ++iterator) {
22-
if (bundle.remove(*iterator)) {
22+
if (bundle.remove(std::string{*iterator})) {
2323
sourcemeta::jsonschema::cli::log_verbose(options)
2424
<< "Disabling rule: " << *iterator << "\n";
2525
} else {
@@ -86,11 +86,9 @@ static auto get_lint_callback(sourcemeta::core::JSON &errors_array,
8686
};
8787
}
8888

89-
auto sourcemeta::jsonschema::cli::lint(
90-
const std::span<const std::string> &arguments) -> int {
91-
const auto options{
92-
parse_options(arguments, {"f", "fix", "json", "j", "l", "list"})};
93-
const bool output_json = options.contains("json") || options.contains("j");
89+
auto sourcemeta::jsonschema::cli::lint(const sourcemeta::core::Options &options)
90+
-> int {
91+
const bool output_json = options.contains("json");
9492

9593
sourcemeta::core::SchemaTransformer bundle;
9694
sourcemeta::core::add(bundle, sourcemeta::core::AlterSchemaMode::Readability);
@@ -105,12 +103,7 @@ auto sourcemeta::jsonschema::cli::lint(
105103
options.at("exclude").cend());
106104
}
107105

108-
if (options.contains("x")) {
109-
disable_lint_rules(bundle, options, options.at("x").cbegin(),
110-
options.at("x").cend());
111-
}
112-
113-
if (options.contains("list") || options.contains("l")) {
106+
if (options.contains("list")) {
114107
std::vector<std::pair<std::reference_wrapper<const std::string>,
115108
std::reference_wrapper<const std::string>>>
116109
rules;
@@ -139,12 +132,12 @@ auto sourcemeta::jsonschema::cli::lint(
139132
bool result{true};
140133
auto errors_array = sourcemeta::core::JSON::make_array();
141134
const auto dialect{default_dialect(options)};
142-
const auto custom_resolver{resolver(
143-
options, options.contains("h") || options.contains("http"), dialect)};
135+
const auto custom_resolver{
136+
resolver(options, options.contains("http"), dialect)};
144137

145-
if (options.contains("f") || options.contains("fix")) {
138+
if (options.contains("fix")) {
146139
for (const auto &entry :
147-
for_each_json(options.at(""), parse_ignore(options),
140+
for_each_json(options.positional(), parse_ignore(options),
148141
parse_extensions(options))) {
149142
log_verbose(options) << "Linting: " << entry.first.string() << "\n";
150143
if (entry.first.extension() == ".yaml" ||
@@ -184,7 +177,7 @@ auto sourcemeta::jsonschema::cli::lint(
184177
}
185178
} else {
186179
for (const auto &entry :
187-
for_each_json(options.at(""), parse_ignore(options),
180+
for_each_json(options.positional(), parse_ignore(options),
188181
parse_extensions(options))) {
189182
log_verbose(options) << "Linting: " << entry.first.string() << "\n";
190183

0 commit comments

Comments
 (0)