| Line |
Branch |
Exec |
Source |
| 1 |
|
|
#include "terraingen/app/cli.h" |
| 2 |
|
|
|
| 3 |
|
|
#include "terraingen/app/gui/run.h" |
| 4 |
|
|
#include "terraingen/config/build.h" |
| 5 |
|
|
#include "terraingen/config/generate.h" |
| 6 |
|
|
#include "terraingen/config/json.h" |
| 7 |
|
|
#include "terraingen/config/validate.h" |
| 8 |
|
|
#include "terraingen/util/build_info.h" |
| 9 |
|
|
#include "terraingen/util/log.h" |
| 10 |
|
|
#include "terraingen/util/version.h" |
| 11 |
|
|
|
| 12 |
|
|
#include <algorithm> |
| 13 |
|
|
#include <cstddef> |
| 14 |
|
|
#include <exception> |
| 15 |
|
|
#include <filesystem> |
| 16 |
|
|
#include <optional> |
| 17 |
|
|
#include <stdexcept> |
| 18 |
|
|
#include <string> |
| 19 |
|
|
#include <vector> |
| 20 |
|
|
|
| 21 |
|
|
namespace terraingen::cli { |
| 22 |
|
|
|
| 23 |
|
|
namespace { |
| 24 |
|
|
|
| 25 |
|
|
/// Options of the generate command. |
| 26 |
|
|
struct GenerateArgs { |
| 27 |
|
|
std::filesystem::path config; |
| 28 |
|
|
std::optional<std::filesystem::path> outputDir; |
| 29 |
|
|
LogLevel logLevel = LogLevel::Info; |
| 30 |
|
|
unsigned threads = 0; |
| 31 |
|
|
std::optional<Backend> backend = std::nullopt; |
| 32 |
|
|
}; |
| 33 |
|
|
|
| 34 |
|
94 |
GenerateArgs ParseGenerate(const std::vector<std::string>& args) { |
| 35 |
|
94 |
GenerateArgs parsed; |
| 36 |
|
94 |
bool haveConfig = false; |
| 37 |
2/2
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 84 times.
|
348 |
for (std::size_t i = 0; i < args.size(); ++i) { |
| 38 |
|
264 |
const std::string& arg = args[i]; |
| 39 |
|
171 |
const auto value = [&]() -> const std::string& { |
| 40 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 169 times.
|
171 |
if (i + 1 >= args.size()) { |
| 41 |
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
|
2 |
throw std::invalid_argument(arg + " needs a value"); |
| 42 |
|
|
} |
| 43 |
|
169 |
return args[++i]; |
| 44 |
|
264 |
}; |
| 45 |
3/3
✓ Branch 1 taken 264 times.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 184 times.
|
264 |
if (arg == "--output-dir") { |
| 46 |
2/2
✓ Branch 1 taken 79 times.
✓ Branch 4 taken 79 times.
|
80 |
parsed.outputDir = value(); |
| 47 |
3/3
✓ Branch 1 taken 184 times.
✓ Branch 3 taken 81 times.
✓ Branch 4 taken 103 times.
|
184 |
} else if (arg == "--log-level") { |
| 48 |
1/1
✓ Branch 1 taken 81 times.
|
81 |
const std::string& name = value(); |
| 49 |
1/1
✓ Branch 2 taken 81 times.
|
81 |
const std::optional<LogLevel> level = ParseLogLevel(name); |
| 50 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 80 times.
|
81 |
if (!level) { |
| 51 |
|
|
throw std::invalid_argument( |
| 52 |
1/1
✓ Branch 1 taken 1 time.
|
2 |
"--log-level needs trace, debug, info, warning, error or off, not '" + name + |
| 53 |
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
|
3 |
"'"); |
| 54 |
|
|
} |
| 55 |
|
80 |
parsed.logLevel = *level; |
| 56 |
3/3
✓ Branch 1 taken 103 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 97 times.
|
103 |
} else if (arg == "--threads") { |
| 57 |
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 2 times.
|
6 |
parsed.threads = ParseThreads(value()); |
| 58 |
3/3
✓ Branch 1 taken 97 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 93 times.
|
97 |
} else if (arg == "--backend") { |
| 59 |
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 2 times.
|
4 |
parsed.backend = ParseBackend(value()); |
| 60 |
3/3
✓ Branch 1 taken 93 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 92 times.
|
93 |
} else if (arg.rfind("--", 0) == 0) { |
| 61 |
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
|
1 |
throw std::invalid_argument("Unknown option " + arg); |
| 62 |
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 91 times.
|
92 |
} else if (haveConfig) { |
| 63 |
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
|
1 |
throw std::invalid_argument("Unexpected argument " + arg); |
| 64 |
|
|
} else { |
| 65 |
1/1
✓ Branch 1 taken 91 times.
|
91 |
parsed.config = arg; |
| 66 |
|
91 |
haveConfig = true; |
| 67 |
|
|
} |
| 68 |
|
|
} |
| 69 |
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 83 times.
|
84 |
if (!haveConfig) { |
| 70 |
1/1
✓ Branch 2 taken 1 time.
|
1 |
throw std::invalid_argument("Missing the configuration file"); |
| 71 |
|
|
} |
| 72 |
|
83 |
return parsed; |
| 73 |
|
11 |
} |
| 74 |
|
|
|
| 75 |
|
|
/// Restores the log level it was made with when it goes out of scope. |
| 76 |
|
|
class LogLevelScope { |
| 77 |
|
|
public: |
| 78 |
|
83 |
explicit LogLevelScope(LogLevel level) : previous_(GetLogLevel()) { |
| 79 |
|
83 |
SetLogLevel(level); |
| 80 |
|
83 |
} |
| 81 |
|
|
LogLevelScope(const LogLevelScope&) = delete; |
| 82 |
|
|
LogLevelScope& operator=(const LogLevelScope&) = delete; |
| 83 |
|
83 |
~LogLevelScope() { |
| 84 |
|
83 |
SetLogLevel(previous_); |
| 85 |
|
83 |
} |
| 86 |
|
|
|
| 87 |
|
|
private: |
| 88 |
|
|
LogLevel previous_; |
| 89 |
|
|
}; |
| 90 |
|
|
|
| 91 |
|
|
/// Runs `command`, reporting a configuration error against the file `config` and any other error |
| 92 |
|
|
/// as terraingen's, and returns the exit code. |
| 93 |
|
|
template <typename Command> |
| 94 |
|
88 |
int RunReporting(const std::filesystem::path& config, std::ostream& err, Command command) { |
| 95 |
|
|
try { |
| 96 |
2/2
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 81 times.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 2 times.
|
88 |
command(); |
| 97 |
3/6
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
5 |
} catch (const ConfigError& error) { |
| 98 |
10/10
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 14 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 11 taken 3 times.
✓ Branch 14 taken 3 times.
|
4 |
err << config.string() << ": " << error.what() << "\n"; |
| 99 |
|
4 |
return kExitInvalidConfig; |
| 100 |
|
1 |
} catch (const std::exception& error) { |
| 101 |
3/6
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 1 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
|
1 |
err << "terraingen: " << error.what() << "\n"; |
| 102 |
|
1 |
return kExitFailure; |
| 103 |
|
|
} |
| 104 |
|
83 |
return kExitSuccess; |
| 105 |
|
|
} |
| 106 |
|
|
|
| 107 |
|
94 |
int Generate(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) { |
| 108 |
1/1
✓ Branch 1 taken 83 times.
|
94 |
const GenerateArgs parsed = ParseGenerate(args); |
| 109 |
1/1
✓ Branch 1 taken 83 times.
|
83 |
const LogLevelScope level(parsed.logLevel); |
| 110 |
1/1
✓ Branch 1 taken 83 times.
|
83 |
return RunReporting(parsed.config, err, [&] { |
| 111 |
1/1
✓ Branch 1 taken 82 times.
|
83 |
const TerrainConfig config = LoadConfig(parsed.config); |
| 112 |
1/1
✓ Branch 1 taken 82 times.
|
82 |
const std::filesystem::path inputs = parsed.config.parent_path(); |
| 113 |
|
|
const GeneratedTerrain terrain = |
| 114 |
1/1
✓ Branch 1 taken 82 times.
|
82 |
GenerateTerrain(config, inputs, parsed.threads, parsed.backend); |
| 115 |
1/1
✓ Branch 1 taken 82 times.
|
82 |
const std::filesystem::path outputs = parsed.outputDir.value_or(inputs); |
| 116 |
|
82 |
const Stopwatch stopwatch; |
| 117 |
1/1
✓ Branch 1 taken 81 times.
|
82 |
const auto written = WriteOutputs(config, terrain, outputs); |
| 118 |
3/3
✓ Branch 1 taken 81 times.
✓ Branch 4 taken 81 times.
✓ Branch 7 taken 81 times.
|
81 |
out << Summary(terrain) << "\n"; |
| 119 |
2/2
✓ Branch 1 taken 81 times.
✓ Branch 5 taken 81 times.
|
81 |
out << "Wrote " << written.size() << (written.size() == 1 ? " file" : " files") << " to " |
| 120 |
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 81 times.
✓ Branch 9 taken 81 times.
|
162 |
<< (outputs.empty() ? std::filesystem::path(".") : outputs).string() << " in " |
| 121 |
10/10
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 56 times.
✓ Branch 3 taken 81 times.
✓ Branch 6 taken 81 times.
✓ Branch 10 taken 81 times.
✓ Branch 13 taken 81 times.
✓ Branch 16 taken 81 times.
✓ Branch 19 taken 81 times.
✓ Branch 22 taken 81 times.
✓ Branch 25 taken 81 times.
|
162 |
<< FormatDuration(stopwatch.Milliseconds()) << "\n"; |
| 122 |
|
251 |
}); |
| 123 |
|
83 |
} |
| 124 |
|
|
|
| 125 |
|
|
/// Prints each backend with its device or why it is unavailable, then the default backend. |
| 126 |
|
1 |
int ListBackends(std::ostream& out, std::ostream& err) { |
| 127 |
3/3
✓ Branch 1 taken 1 time.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 time.
|
5 |
for (const BackendStatus& status : Backends()) { |
| 128 |
|
4 |
out << BackendName(status.backend) << ": " |
| 129 |
1/1
✓ Branch 1 taken 2 times.
|
6 |
<< (status.available ? "available on " + status.device |
| 130 |
1/1
✓ Branch 1 taken 2 times.
|
2 |
: "unavailable: " + status.reason) |
| 131 |
7/7
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 4 times.
✓ Branch 15 taken 4 times.
|
8 |
<< "\n"; |
| 132 |
|
1 |
} |
| 133 |
|
|
try { |
| 134 |
5/5
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
|
1 |
out << "default: " << BackendName(DefaultBackend()) << "\n"; |
| 135 |
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
✗ |
} catch (const std::invalid_argument& error) { |
| 136 |
0/3
✗ Branch 1 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
|
✗ |
err << "terraingen: " << error.what() << "\n"; |
| 137 |
|
✗ |
return kExitFailure; |
| 138 |
|
|
} |
| 139 |
|
1 |
return kExitSuccess; |
| 140 |
|
|
} |
| 141 |
|
|
|
| 142 |
|
7 |
int Validate(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) { |
| 143 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
|
7 |
if (args.size() != 2) { |
| 144 |
1/1
✓ Branch 2 taken 2 times.
|
2 |
throw std::invalid_argument("validate needs exactly one configuration file"); |
| 145 |
|
|
} |
| 146 |
1/1
✓ Branch 2 taken 5 times.
|
5 |
const std::filesystem::path path = args[1]; |
| 147 |
1/1
✓ Branch 1 taken 5 times.
|
5 |
return RunReporting(path, err, [&] { |
| 148 |
1/1
✓ Branch 1 taken 4 times.
|
5 |
const TerrainConfig config = LoadConfig(path); |
| 149 |
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 2 times.
|
6 |
const ConfigSummary summary = ValidateConfig(config, path.parent_path()); |
| 150 |
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
|
2 |
out << path.string() << " is valid: "; |
| 151 |
|
2 |
std::vector<RasterGrid> grids; |
| 152 |
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
|
4 |
for (const std::optional<RasterGrid>& grid : summary.outputGrids) { |
| 153 |
6/7
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 11 taken 1 time.
✓ Branch 12 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 14 taken 1 time.
|
2 |
if (grid && std::find(grids.begin(), grids.end(), *grid) == grids.end()) { |
| 154 |
5/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 15 taken 1 time.
|
1 |
out << (grids.empty() ? "a " : " and ") << grid->width << "x" << grid->height; |
| 155 |
1/1
✓ Branch 2 taken 1 time.
|
1 |
grids.push_back(*grid); |
| 156 |
|
|
} |
| 157 |
|
|
} |
| 158 |
4/5
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
|
2 |
out << (grids.empty() ? "no grids" : grids.size() == 1 ? " grid" : " grids"); |
| 159 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 |
if (summary.expectedCraters) { |
| 160 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
|
1 |
out << ", about " << static_cast<long long>(*summary.expectedCraters) |
| 161 |
1/1
✓ Branch 1 taken 1 time.
|
1 |
<< " craters expected"; |
| 162 |
|
|
} |
| 163 |
4/4
✓ Branch 1 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 12 taken 2 times.
|
2 |
out << ", " << config.layers.size() << " layers and " << config.outputs.size() |
| 164 |
1/1
✓ Branch 1 taken 2 times.
|
2 |
<< " outputs\n"; |
| 165 |
|
14 |
}); |
| 166 |
|
5 |
} |
| 167 |
|
|
|
| 168 |
|
|
} // namespace |
| 169 |
|
|
|
| 170 |
|
15 |
unsigned ParseThreads(const std::string& text) { |
| 171 |
|
15 |
std::size_t used = 0; |
| 172 |
|
15 |
unsigned long value = 0; |
| 173 |
|
|
try { |
| 174 |
1/1
✓ Branch 1 taken 10 times.
|
15 |
value = std::stoul(text, &used); |
| 175 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 |
} catch (const std::exception&) { |
| 176 |
|
5 |
used = 0; |
| 177 |
|
5 |
} |
| 178 |
10/10
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 5 times.
|
15 |
if (used == 0 || used != text.size() || text.front() == '-' || value > 4096) { |
| 179 |
|
|
throw std::invalid_argument( |
| 180 |
3/3
✓ Branch 2 taken 10 times.
✓ Branch 5 taken 10 times.
✓ Branch 8 taken 10 times.
|
10 |
"--threads needs a count from 0 (every hardware thread) to 4096, not '" + text + "'"); |
| 181 |
|
|
} |
| 182 |
|
5 |
return static_cast<unsigned>(value); |
| 183 |
|
|
} |
| 184 |
|
|
|
| 185 |
|
12 |
Backend ParseBackend(const std::string& text) { |
| 186 |
3/3
✓ Branch 2 taken 12 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 3 times.
|
12 |
if (const std::optional<Backend> backend = BackendNamed(text)) { |
| 187 |
|
9 |
return *backend; |
| 188 |
|
|
} |
| 189 |
|
3 |
throw std::invalid_argument("--backend needs auto, cpu, gpu, vulkan, cuda or metal, not '" + |
| 190 |
3/3
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 8 taken 3 times.
|
6 |
text + "'"); |
| 191 |
|
|
} |
| 192 |
|
|
|
| 193 |
|
12 |
GuiArgs ParseGuiArgs(const std::vector<std::string>& args) { |
| 194 |
|
12 |
GuiArgs parsed; |
| 195 |
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 3 times.
|
21 |
for (std::size_t i = 0; i < args.size(); ++i) { |
| 196 |
|
18 |
const std::string& arg = args[i]; |
| 197 |
|
7 |
const auto value = [&]() -> const std::string& { |
| 198 |
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
|
7 |
if (i + 1 >= args.size()) { |
| 199 |
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
|
3 |
throw std::invalid_argument(arg + " needs a value"); |
| 200 |
|
|
} |
| 201 |
|
4 |
return args[++i]; |
| 202 |
|
18 |
}; |
| 203 |
3/3
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 14 times.
|
18 |
if (arg == "--threads") { |
| 204 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 1 time.
|
4 |
parsed.threads = ParseThreads(value()); |
| 205 |
3/3
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 11 times.
|
14 |
} else if (arg == "--backend") { |
| 206 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 1 time.
|
3 |
parsed.backend = ParseBackend(value()); |
| 207 |
3/3
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
|
11 |
} else if (arg.rfind("--", 0) == 0) { |
| 208 |
3/3
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
|
2 |
throw std::invalid_argument("Unknown option " + arg + " with --gui"); |
| 209 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
|
9 |
} else if (!parsed.open.empty()) { |
| 210 |
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
|
2 |
throw std::invalid_argument("Unexpected argument " + arg); |
| 211 |
|
|
} else { |
| 212 |
1/1
✓ Branch 1 taken 7 times.
|
7 |
parsed.open = arg; |
| 213 |
|
|
} |
| 214 |
|
|
} |
| 215 |
|
3 |
return parsed; |
| 216 |
|
9 |
} |
| 217 |
|
|
|
| 218 |
|
6 |
std::string Usage() { |
| 219 |
|
|
return "Usage:\n" |
| 220 |
|
|
" terraingen CONFIG [--output-dir DIR] [--log-level LEVEL] [--threads N]\n" |
| 221 |
|
|
" [--backend auto|cpu|gpu|vulkan|cuda|metal]\n" |
| 222 |
|
|
" Generate the terrain the JSON file CONFIG describes\n" |
| 223 |
|
|
" terraingen validate CONFIG\n" |
| 224 |
|
|
" Check CONFIG without generating\n" |
| 225 |
|
|
" terraingen schema Print every configuration type with its defaults\n" |
| 226 |
|
|
" terraingen backends Show where terrains can be evaluated here, and the default\n" |
| 227 |
|
|
" terraingen [PATH] --gui [--threads N] [--backend auto|cpu|gpu|vulkan|cuda|metal]\n" |
| 228 |
|
|
" Open the GUI on a configuration, GeoTIFF heights or the\n" |
| 229 |
|
|
" starter terrain\n" |
| 230 |
|
|
" terraingen -V, --version\n" |
| 231 |
|
|
" Show version and build information\n" |
| 232 |
1/1
✓ Branch 1 taken 6 times.
|
12 |
" terraingen -h, --help Show this message\n"; |
| 233 |
|
|
} |
| 234 |
|
|
|
| 235 |
|
123 |
int Run(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) { |
| 236 |
|
|
try { |
| 237 |
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 121 times.
|
123 |
if (args.empty()) { |
| 238 |
1/1
✓ Branch 2 taken 2 times.
|
2 |
throw std::invalid_argument("Missing a command or configuration file"); |
| 239 |
|
|
} |
| 240 |
1/1
✓ Branch 3 taken 121 times.
|
121 |
const auto gui = std::find(args.begin(), args.end(), "--gui"); |
| 241 |
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 113 times.
|
121 |
if (gui != args.end()) { |
| 242 |
1/1
✓ Branch 2 taken 8 times.
|
8 |
std::vector<std::string> rest(args.begin(), gui); |
| 243 |
1/1
✓ Branch 5 taken 8 times.
|
8 |
rest.insert(rest.end(), gui + 1, args.end()); |
| 244 |
1/1
✓ Branch 1 taken 1 time.
|
8 |
return RunGui(rest, out, err); |
| 245 |
|
8 |
} |
| 246 |
|
113 |
const std::string& first = args.front(); |
| 247 |
8/8
✓ Branch 1 taken 113 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 5 times.
✓ Branch 6 taken 108 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 107 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 107 times.
|
113 |
if (first == "--help" || first == "-h") { |
| 248 |
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
|
6 |
out << Usage(); |
| 249 |
|
6 |
return kExitSuccess; |
| 250 |
|
|
} |
| 251 |
8/8
✓ Branch 1 taken 107 times.
✓ Branch 3 taken 106 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 106 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 105 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 105 times.
|
107 |
if (first == "--version" || first == "-V") { |
| 252 |
1/1
✓ Branch 1 taken 2 times.
|
2 |
const Version version = GetVersion(); |
| 253 |
1/1
✓ Branch 1 taken 2 times.
|
2 |
const BuildInfo build = GetBuildInfo(); |
| 254 |
5/5
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 13 taken 2 times.
|
2 |
out << "TerrainGen " << version.major << "." << version.minor << "." << version.patch |
| 255 |
|
2 |
<< " (" << build.gitSha << (build.gitDirty ? "-dirty" : "") << ", " |
| 256 |
8/9
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 18 taken 2 times.
✓ Branch 21 taken 2 times.
|
2 |
<< build.buildDate << ")\n"; |
| 257 |
|
2 |
return kExitSuccess; |
| 258 |
|
2 |
} |
| 259 |
3/3
✓ Branch 1 taken 105 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 103 times.
|
105 |
if (first == "schema") { |
| 260 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 |
if (args.size() != 1) { |
| 261 |
1/1
✓ Branch 2 taken 1 time.
|
1 |
throw std::invalid_argument("schema takes no arguments"); |
| 262 |
|
|
} |
| 263 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
|
1 |
out << ConfigCatalog(); |
| 264 |
|
1 |
return kExitSuccess; |
| 265 |
|
|
} |
| 266 |
3/3
✓ Branch 1 taken 103 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 101 times.
|
103 |
if (first == "backends") { |
| 267 |
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 |
if (args.size() != 1) { |
| 268 |
1/1
✓ Branch 2 taken 1 time.
|
1 |
throw std::invalid_argument("backends takes no arguments"); |
| 269 |
|
|
} |
| 270 |
1/1
✓ Branch 1 taken 1 time.
|
1 |
return ListBackends(out, err); |
| 271 |
|
|
} |
| 272 |
3/3
✓ Branch 1 taken 101 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 94 times.
|
101 |
if (first == "validate") { |
| 273 |
1/1
✓ Branch 1 taken 5 times.
|
7 |
return Validate(args, out, err); |
| 274 |
|
|
} |
| 275 |
1/1
✓ Branch 1 taken 83 times.
|
94 |
return Generate(args, out, err); |
| 276 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 |
} catch (const std::invalid_argument& error) { |
| 277 |
3/3
✓ Branch 1 taken 24 times.
✓ Branch 5 taken 24 times.
✓ Branch 8 taken 24 times.
|
24 |
err << "terraingen: " << error.what() << "\nRun 'terraingen --help' to see the usage.\n"; |
| 278 |
|
24 |
return kExitUsage; |
| 279 |
|
24 |
} |
| 280 |
|
|
} |
| 281 |
|
|
|
| 282 |
|
|
} // namespace terraingen::cli |
| 283 |
|
|
|