Skip to content

Commit e26857d

Browse files
ElestriasMarkuu-s
authored andcommitted
Merge remote-traking branch 'tmp/cli' into feature/cli
Signed-off-by: elestrias <[email protected]>
1 parent 18e194b commit e26857d

File tree

17 files changed

+415
-94
lines changed

17 files changed

+415
-94
lines changed

core/api/rpc/info.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ namespace fc::api::rpc {
2828
address = info.substr(0, i);
2929
token = info.substr(i + 1);
3030
} else if (!repo.empty()) {
31-
boost::filesystem::load_string_file(repo / "api", address);
32-
boost::filesystem::load_string_file(repo / "token", token);
31+
try {
32+
boost::filesystem::load_string_file(repo / "api", address);
33+
boost::filesystem::load_string_file(repo / "token", token);
34+
} catch (...) {
35+
return {};
36+
}
3337
} else {
3438
return {};
3539
}

core/cli/cli.hpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <memory>
1212
#include <typeindex>
1313

14+
<<<<<<< HEAD
1415
#define CLI_TRY(valueName, maybeResult) \
1516
auto valueName##OUTCOME_TRY = maybeResult; \
1617
if (valueName##OUTCOME_TRY.has_error()) throw std::invalid_argument(""); \
@@ -20,6 +21,53 @@
2021
auto valueName##OUTCOME_TRY = maybeResult; \
2122
if (valueName##OUTCOME_TRY.has_error()) throw std::invalid_argument(textError); \
2223
auto valueName = valueName##OUTCOME_TRY.value();
24+
=======
25+
#include "cli/try.hpp"
26+
27+
#define CLI_BOOL(NAME, DESCRIPTION) \
28+
struct { \
29+
bool _{}; \
30+
void operator()(Opts &opts) { \
31+
opts.add_options()(NAME, po::bool_switch(&_), DESCRIPTION); \
32+
} \
33+
operator bool() const { \
34+
return _; \
35+
} \
36+
}
37+
#define CLI_DEFAULT(NAME, DESCRIPTION, TYPE, INIT) \
38+
struct { \
39+
TYPE _ INIT; \
40+
void operator()(Opts &opts) { \
41+
opts.add_options()(NAME, po::value(&_), DESCRIPTION); \
42+
} \
43+
auto &operator*() const { \
44+
return _; \
45+
} \
46+
auto *operator->() const { \
47+
return &_; \
48+
} \
49+
}
50+
#define CLI_OPTIONAL(NAME, DESCRIPTION, TYPE) \
51+
struct { \
52+
boost::optional<TYPE> _; \
53+
void operator()(Opts &opts) { \
54+
opts.add_options()(NAME, po::value(&_), DESCRIPTION); \
55+
} \
56+
operator bool() const { \
57+
return _.operator bool(); \
58+
} \
59+
auto &operator*() const { \
60+
if (!_) { \
61+
throw ::fc::cli::CliError{"--{} argument is required but missing", \
62+
NAME}; \
63+
} \
64+
return *_; \
65+
} \
66+
auto *operator->() const { \
67+
return &**this; \
68+
} \
69+
}
70+
>>>>>>> aa902706 (options)
2371

2472
#define CLI_OPTS() ::fc::cli::Opts opts()
2573
#define CLI_RUN() \
@@ -48,6 +96,30 @@ namespace fc::cli {
4896
// note: Args is defined inside command
4997
using Argv = std::vector<std::string>;
5098

99+
const std::string &cliArgv(const Argv &argv,
100+
size_t i,
101+
const std::string_view &name) {
102+
if (i < argv.size()) {
103+
return argv[i];
104+
}
105+
throw CliError{"positional argument {} is required but missing", name};
106+
}
107+
template <typename T>
108+
T cliArgv(const std::string &arg, const std::string_view &name) {
109+
boost::any out;
110+
try {
111+
po::value<T>()->xparse(out, Argv{arg});
112+
} catch (po::validation_error &e) {
113+
e.set_option_name(std::string{name});
114+
throw;
115+
}
116+
return boost::any_cast<T>(out);
117+
}
118+
template <typename T>
119+
T cliArgv(const Argv &argv, size_t i, const std::string_view &name) {
120+
return cliArgv<T>(cliArgv(argv, i, name), name);
121+
}
122+
51123
struct Empty {
52124
struct Args {
53125
CLI_OPTS() {

core/cli/node/_tree.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#pragma once
77

8+
#include "cli/node/client.hpp"
89
#include "cli/node/net.hpp"
910
#include "cli/tree.hpp"
1011
#include "cli/node/client.hpp"
@@ -17,10 +18,17 @@ namespace fc::cli::_node {
1718
})},
1819
{"client",
1920
tree<Group>({
21+
<<<<<<< HEAD
2022
{"retrieve", tree<clientRetrieve>()},
2123
{"import", tree<clientImportData>()},
2224
{"generate-car", tree<clientGenerateCar>()},
2325
{"local", tree<clientLocal>()},
26+
=======
27+
{"retrieve", tree<Node_client_retrieve>()},
28+
{"import", tree<Node_client_importData>()},
29+
{"generate-car", tree<Node_client_generateCar>()},
30+
{"local", tree<Node_client_local>()},
31+
>>>>>>> b414cb63 (example client)
2432
})},
2533
})};
2634
} // namespace fc::cli::_node

core/cli/node/client.hpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<<<<<<< HEAD
12
//
23
// Created by Ruslan Gilvanov on 12.02.2022.
34

@@ -20,6 +21,7 @@ namespace fc::cli::_node {
2021
boost::filesystem::path path;
2122
std::string provider;
2223
bool car{};
24+
std::string root;
2325

2426
CLI_OPTS() {
2527
Opts opts;
@@ -39,12 +41,14 @@ namespace fc::cli::_node {
3941
option("car",
4042
po::bool_switch(&car),
4143
"store result of retrieval deal to car file");
44+
option("root-CID", po::value(&root), "Specifies root CID for retrieval deal");
4245
return opts;
4346
}
4447
};
4548

4649
CLI_RUN() {
4750
Node::Api api{argm};
51+
CLI_TRY_TEXT(root, CID::fromString(args.root), "Invalid root CID: " + args.root);
4852
CLI_TRY_TEXT(cid,
4953
CID::fromString(args.piece_cid),
5054
"Invalid piece CID: " + args.piece_cid)
@@ -118,6 +122,104 @@ namespace fc::cli::_node {
118122
}
119123
};
120124

125+
struct clientFind{
126+
struct Args{
127+
128+
CLI_OPTS(){
129+
Opts opts;
130+
auto option{opts.add_options()};
131+
132+
}
133+
};
134+
135+
};
136+
137+
138+
139+
121140

122141

142+
143+
144+
=======
145+
/**
146+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
147+
* SPDX-License-Identifier: Apache-2.0
148+
*/
149+
150+
#pragma once
151+
152+
#include "cli/node/node.hpp"
153+
154+
namespace fc::cli::_node {
155+
struct Node_client_retrieve {
156+
struct Args {
157+
CLI_OPTIONAL("from", "", Address) from;
158+
CLI_OPTIONAL("provider", "", Address) provider;
159+
CLI_OPTIONAL("pieceCid", "", CID) piece_cid;
160+
CLI_OPTIONAL("maxPrice", "", AttoFil) max_price;
161+
CLI_OPTIONAL("data-selector", "", std::string) data_selector;
162+
CLI_BOOL("car", "") car;
163+
CLI_BOOL("allow-local", "") allow_local;
164+
CLI_BOOL("car-export-merkle-proof", "") car_export_merkle_proof;
165+
166+
CLI_OPTS() {
167+
Opts opts;
168+
from(opts);
169+
provider(opts);
170+
piece_cid(opts);
171+
allow_local(opts);
172+
car(opts);
173+
max_price(opts);
174+
data_selector(opts);
175+
car_export_merkle_proof(opts);
176+
return opts;
177+
}
178+
};
179+
CLI_RUN() {
180+
auto data_cid{cliArgv<CID>(argv, 0, "dataCid")};
181+
auto path{cliArgv<boost::filesystem::path>(argv, 1, "path")};
182+
if (args.max_price) {
183+
fmt::print("max price is {}fil ({}attofil)\n",
184+
args.max_price->fil,
185+
args.max_price->atto());
186+
}
187+
fmt::print("retrieving {} to {} {}\n",
188+
data_cid,
189+
args.car ? "car" : "file",
190+
path);
191+
fmt::print("TODO: implement\n");
192+
}
193+
};
194+
195+
struct Node_client_importData {
196+
struct Args {
197+
CLI_BOOL("car", "") car;
198+
199+
CLI_OPTS() {
200+
Opts opts;
201+
car(opts);
202+
return opts;
203+
}
204+
};
205+
CLI_RUN() {
206+
auto path{cliArgv<boost::filesystem::path>(argv, 0, "inputPath")};
207+
fmt::print("TODO: implement\n");
208+
}
209+
};
210+
211+
struct Node_client_generateCar : Empty {
212+
CLI_RUN() {
213+
auto input_path{cliArgv<boost::filesystem::path>(argv, 0, "inputPath")};
214+
auto output_path{cliArgv<boost::filesystem::path>(argv, 1, "outputPath")};
215+
fmt::print("TODO: implement\n");
216+
}
217+
};
218+
219+
struct Node_client_local : Empty {
220+
CLI_RUN() {
221+
fmt::print("TODO: implement\n");
222+
}
223+
};
224+
>>>>>>> b414cb63 (example client)
123225
} // namespace fc::cli::_node

core/cli/node/net.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace fc::cli::_node {
1111
struct Node_net_listen : Empty {
1212
CLI_RUN() {
1313
Node::Api api{argm};
14-
const auto peer{api._->NetAddrsListen().value()};
14+
const auto peer{cliTry(api._->NetAddrsListen())};
1515
for (const auto &addr : peer.addresses) {
1616
fmt::print("{}\n", addr.getStringAddress());
1717
}

core/cli/node/node.hpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,26 @@
1010
#include "api/rpc/client_setup.hpp"
1111
#include "api/rpc/info.hpp"
1212
#include "cli/cli.hpp"
13+
#include "cli/try.hpp"
14+
#include "cli/validate/address.hpp"
15+
#include "cli/validate/cid.hpp"
16+
#include "common/libp2p/multi/multiaddress_fmt.hpp"
1317
#include "node/node_version.hpp"
18+
#include "primitives/atto_fil.hpp"
1419

1520
namespace fc::cli::_node {
21+
using api::Address;
22+
using primitives::AttoFil;
23+
1624
struct Node {
1725
struct Args {
18-
bool version{};
19-
boost::optional<boost::filesystem::path> repo;
26+
CLI_BOOL("version", "") version;
27+
CLI_DEFAULT("repo", "", boost::filesystem::path, ) repo;
2028

2129
CLI_OPTS() {
2230
Opts opts;
23-
auto opt{opts.add_options()};
24-
opt("version,v", po::bool_switch(&version));
25-
opt("repo", po::value(&repo));
31+
version(opts);
32+
repo(opts);
2633
return opts;
2734
}
2835
};
@@ -42,11 +49,14 @@ namespace fc::cli::_node {
4249
Api(const ArgsMap &argm) {
4350
const auto &args{argm.of<Node>()};
4451
const auto info{
45-
*api::rpc::loadInfo(args.repo.value_or(""), "FULLNODE_API_INFO")};
52+
cliTry(api::rpc::loadInfo(*args.repo, "FULLNODE_API_INFO").o,
53+
"api info is missing")};
4654
_ = std::make_shared<api::FullNodeApi>();
4755
wsc = std::make_shared<api::rpc::Client>(*thread.io);
4856
wsc->setup(*_);
49-
wsc->connect(info.first, "/rpc/v1", info.second).value();
57+
cliTry(wsc->connect(info.first, "/rpc/v1", info.second),
58+
"connecting to {}",
59+
info.first);
5060
}
5161
};
5262
};

core/cli/run.hpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55

66
#pragma once
77

8-
#include <fmt/format.h>
9-
#include <fmt/ostream.h>
108
#include <boost/program_options/parsers.hpp>
119
#include <boost/program_options/variables_map.hpp>
1210

1311
#include "cli/tree.hpp"
12+
#include "cli/try.hpp"
1413

1514
namespace fc::cli {
1615
inline bool isDash(const std::string &s) {
@@ -20,7 +19,8 @@ namespace fc::cli {
2019
return s.size() == 2 && s[0] == '-' && s[1] == '-';
2120
}
2221
// note: returns first positional arg or end
23-
inline Argv::iterator hackBoost(const Opts &opts,
22+
inline Argv::iterator hackBoost(po::variables_map &vm,
23+
const Opts &opts,
2424
Argv::iterator begin,
2525
Argv::iterator end) {
2626
po::parsed_options parsed{&opts};
@@ -49,9 +49,7 @@ namespace fc::cli {
4949
begin += option.original_tokens.size();
5050
}
5151
}
52-
po::variables_map vm;
5352
po::store(parsed, vm);
54-
po::notify(vm);
5553
return begin;
5654
}
5755

@@ -64,12 +62,18 @@ namespace fc::cli {
6462
while (true) {
6563
auto args{tree->args()};
6664
auto option{args.opts.add_options()};
67-
bool help{};
68-
// note: help doesn't work with required options
69-
option("help,h", po::bool_switch(&help));
70-
argv_it = hackBoost(args.opts, argv_it, argv.end());
71-
argm._.emplace(args._);
65+
option("help,h", "print help");
66+
po::variables_map vm;
67+
try {
68+
argv_it = hackBoost(vm, args.opts, argv_it, argv.end());
69+
} catch (po::error &e) {
70+
fmt::print("{}: {}\n", fmt::join(cmds, " "), e.what());
71+
return;
72+
}
73+
const auto help{vm.count("help") != 0};
7274
if (!help) {
75+
po::notify(vm);
76+
argm._.emplace(args._);
7377
if (argv_it != argv.end()) {
7478
auto sub_it{tree->sub.find(*argv_it)};
7579
if (sub_it != tree->sub.end()) {
@@ -83,6 +87,12 @@ namespace fc::cli {
8387
try {
8488
return tree->run(argm, {argv_it, argv.end()});
8589
} catch (ShowHelp &) {
90+
} catch (po::error &e) {
91+
fmt::print("{}: {}\n", fmt::join(cmds, " "), e.what());
92+
return;
93+
} catch (CliError &e) {
94+
fmt::print("{}: {}\n", fmt::join(cmds, " "), e.what());
95+
return;
8696
}
8797
}
8898
}

0 commit comments

Comments
 (0)