Skip to content

Commit d1b96b0

Browse files
Jason Coposkytrel
Jason Coposky
authored andcommittedAug 11, 2020
[#5] add repl command
1 parent 8c590cc commit d1b96b0

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed
 

‎CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ add_subdirectory(commands/cp)
7070
add_subdirectory(commands/get)
7171
add_subdirectory(commands/ls)
7272
add_subdirectory(commands/put)
73+
add_subdirectory(commands/repl)
7374
add_subdirectory(commands/rm)
7475
add_subdirectory(commands/touch)
7576

‎commands/repl/CMakeLists.txt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
project(irods_cli_repl)
2+
3+
set(CLI_MODULE_NAME irods_cli_repl)
4+
5+
add_library(${CLI_MODULE_NAME} MODULE ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
6+
7+
set_target_properties(${CLI_MODULE_NAME} PROPERTIES CXX_STANDARD ${IRODS_CXX_STANDARD}
8+
VERSION 0.0.1
9+
SOVERSION 0)
10+
11+
target_compile_options(${CLI_MODULE_NAME} PRIVATE -Wno-write-strings -nostdinc++)
12+
13+
target_compile_definitions(${CLI_MODULE_NAME} PRIVATE ${IRODS_COMPILE_DEFINITIONS})
14+
15+
target_include_directories(${CLI_MODULE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include
16+
${IRODS_INCLUDE_DIRS}
17+
${IRODS_EXTERNALS_FULLPATH_CLANG}/include/c++/v1
18+
${IRODS_EXTERNALS_FULLPATH_JSON}/include
19+
${IRODS_EXTERNALS_FULLPATH_BOOST}/include)
20+
21+
target_link_libraries(${CLI_MODULE_NAME} PRIVATE irods_common
22+
irods_plugin_dependencies
23+
irods_client
24+
${IRODS_EXTERNALS_FULLPATH_BOOST}/lib/libboost_filesystem.so
25+
${IRODS_EXTERNALS_FULLPATH_BOOST}/lib/libboost_system.so
26+
${IRODS_EXTERNALS_FULLPATH_BOOST}/lib/libboost_program_options.so)
27+
28+
# Installation
29+
install(TARGETS ${CLI_MODULE_NAME}
30+
DESTINATION ${IRODS_CLI_COMMANDS_INSTALL_DIR}
31+
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
32+
GROUP_READ GROUP_EXECUTE
33+
WORLD_READ WORLD_EXECUTE)
34+

‎commands/repl/main.cpp

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#include "command.hpp"
2+
3+
#include <irods/rodsClient.h>
4+
#include <irods/connection_pool.hpp>
5+
#include <irods/filesystem.hpp>
6+
#include <irods/irods_exception.hpp>
7+
8+
#include <boost/program_options.hpp>
9+
#include <boost/dll.hpp>
10+
#include <boost/progress.hpp>
11+
12+
#include "experimental_plugin_framework.hpp"
13+
14+
#include <iostream>
15+
#include <string>
16+
17+
namespace fs = irods::experimental::filesystem;
18+
namespace po = boost::program_options;
19+
namespace ia = irods::experimental::api;
20+
21+
namespace {
22+
std::atomic_bool exit_flag{};
23+
24+
void handle_signal(int sig)
25+
{
26+
exit_flag = true;
27+
}
28+
}
29+
30+
31+
32+
namespace irods::cli
33+
{
34+
void print_progress(const std::string& p)
35+
{
36+
static boost::progress_display prog{100};
37+
try {
38+
auto x = std::stoi(p.c_str(), nullptr, 10);
39+
while(prog.count() != x) {
40+
++prog;
41+
}
42+
}
43+
catch(...) {
44+
}
45+
} // print_progress
46+
47+
class cp : public command
48+
{
49+
public:
50+
auto name() const noexcept -> std::string_view override
51+
{
52+
return "repl";
53+
}
54+
55+
auto description() const noexcept -> std::string_view override
56+
{
57+
return "Replicates collections or data objects";
58+
}
59+
60+
auto help_text() const noexcept -> std::string_view override
61+
{
62+
auto help =R"(
63+
Given a fully qualified path, replicate the collection or object
64+
65+
irods repl [options] --source_resource <originating replica location> fully_qualified_logical_path
66+
--all : update all replicas of a given data object
67+
--admin_mode : operate as an administrator to replicate user data
68+
--destination_resource : target resource for the replication
69+
--logical_path : fully qualified logical path of the data object
70+
--number_of_threads : number of threads to use in recursive operations
71+
--progress : request progress as a percentage
72+
--source_resource : origin of the data object(s)
73+
--update : update a specific replica on destination resource)";
74+
75+
return help;
76+
77+
}
78+
79+
auto execute(const std::vector<std::string>& args) -> int override
80+
{
81+
signal(SIGINT, handle_signal);
82+
signal(SIGHUP, handle_signal);
83+
signal(SIGTERM, handle_signal);
84+
85+
bool update_all_replicas{false};
86+
bool admin_mode{false};
87+
bool update_one_replica{false};
88+
bool progress_flag{false};
89+
int thread_count{4};
90+
91+
std::string source_resource{}, destination_resource{};
92+
93+
using rep_type = fs::object_time_type::duration::rep;
94+
95+
po::options_description desc{""};
96+
desc.add_options()
97+
("update_all_replicas", po::bool_switch(&update_all_replicas), "update all replicas of a given data object")
98+
("admin_mode", po::bool_switch(&admin_mode), "operate as an administrator to replicate user data")
99+
("destination_resource", po::value<std::string>(&destination_resource), "target resource for the replication")
100+
("logical_path", po::value<std::string>(), "fully qualified logical path of the data object")
101+
("number_of_threads", po::value<int>(&thread_count), "number of threads to use in recursive operations")
102+
("progress", po::bool_switch(&progress_flag), "request progress as a percentage")
103+
("source_resource", po::value<std::string>(&source_resource), "origin of the data object(s)")
104+
("update_one_replica", po::bool_switch(&update_one_replica), "update a specific replica on destination resource");
105+
106+
po::positional_options_description pod;
107+
pod.add("logical_path", 1);
108+
109+
po::variables_map vm;
110+
po::store(po::command_line_parser(args).options(desc).positional(pod).run(), vm);
111+
po::notify(vm);
112+
113+
if (vm.count("logical_path") == 0) {
114+
std::cerr << "Error: Missing source logical path.\n";
115+
return 1;
116+
}
117+
118+
rodsEnv env;
119+
120+
if (getRodsEnv(&env) < 0) {
121+
std::cerr << "Error: Could not get an iRODS environment.\n";
122+
return 1;
123+
}
124+
125+
if(source_resource.empty()) {
126+
std::cerr << "Error: missing --source_resource.\n";
127+
return 1;
128+
}
129+
130+
if(update_all_replicas && update_one_replica) {
131+
std::cerr << "Error: update_all_replicas and update_one_replica are incompatible\n";
132+
return 1;
133+
}
134+
135+
if(!update_all_replicas && destination_resource.empty()) {
136+
std::cerr << "Error: destination_resource is missing.\n";
137+
return 1;
138+
}
139+
140+
if(update_all_replicas && !destination_resource.empty()) {
141+
std::cerr << "Error: cannot specify destination_resource with update_all_replicas.\n";
142+
return 1;
143+
}
144+
145+
irods::connection_pool conn_pool{1, env.rodsHost, env.rodsPort, env.rodsUserName, env.rodsZone, 600};
146+
auto conn = conn_pool.get_connection();
147+
148+
const auto logical_path = vm["logical_path"].as<std::string>();
149+
150+
{
151+
const auto object_status = fs::client::status(conn, logical_path);
152+
153+
if (!fs::client::is_collection(object_status) && !fs::client::is_data_object(object_status)) {
154+
std::cerr << "Error: Logical path does not point to a collection or data object. Do you need a fully qualified path?\n";
155+
return 1;
156+
}
157+
}
158+
159+
std::string progress{};
160+
161+
auto progress_handler = progress_flag ? print_progress : [](const std::string&) {};
162+
163+
auto request = json{{"logical_path", logical_path},
164+
{"source_resource", source_resource},
165+
{"progress", progress_flag}};
166+
167+
if(!destination_resource.empty()) {
168+
request["destination_resource"] = destination_resource;
169+
}
170+
171+
if(admin_mode) {
172+
request["admin_mode"] = true;
173+
}
174+
175+
if(update_one_replica) {
176+
request["update_one_replica"] = true;
177+
}
178+
179+
if(update_all_replicas) {
180+
request["update_all_replicas"] = true;
181+
}
182+
183+
184+
auto cli = ia::client{};
185+
auto rep = cli(conn,
186+
exit_flag,
187+
progress_handler,
188+
request,
189+
"replicate");
190+
191+
if(exit_flag) {
192+
std::cout << "Operation Cancelled.\n";
193+
}
194+
195+
if(rep.contains("errors")) {
196+
for(auto e : rep.at("errors")) {
197+
std::cout << e << "\n";
198+
}
199+
}
200+
201+
return 0;
202+
}
203+
204+
}; // class cp
205+
206+
} // namespace irods::cli
207+
208+
// TODO Need to investigate whether this is truely required.
209+
extern "C" BOOST_SYMBOL_EXPORT irods::cli::cp cli_impl;
210+
irods::cli::cp cli_impl;
211+

0 commit comments

Comments
 (0)
Please sign in to comment.