| 178 | } |
| 179 | |
| 180 | po::variables_map parse_command_line(int argc, char* argv[]) { |
| 181 | auto const default_minimum_slice_size = 64 * 1024 * 1024L; |
| 182 | auto const default_thread_count = [] { |
| 183 | auto constexpr kFallbackThreadCount = 2; |
| 184 | auto constexpr kThreadsPerCore = 2; |
| 185 | auto const count = std::thread::hardware_concurrency(); |
| 186 | if (count == 0) return kFallbackThreadCount; |
| 187 | return static_cast<int>(count * kThreadsPerCore); |
| 188 | }(); |
| 189 | |
| 190 | po::positional_options_description positional; |
| 191 | for (auto const* name : kPositional) positional.add(name, 1); |
| 192 | po::options_description desc( |
| 193 | "Download a single GCS object using multiple slices"); |
| 194 | desc.add_options()("help", "produce help message") |
| 195 | // |
| 196 | ("bucket", po::value<std::string>()->required(), |
| 197 | "set the GCS bucket to download from") |
| 198 | // |
| 199 | ("object", po::value<std::string>()->required(), |
| 200 | "set the GCS object to download") |
| 201 | // |
| 202 | ("destination", po::value<std::string>()->required(), |
| 203 | "set the destination file to download into") |
| 204 | // |
| 205 | ("thread-count", po::value<int>()->default_value(default_thread_count), |
| 206 | "number of parallel streams for the download") |
| 207 | // |
| 208 | ("minimum-slice-size", |
| 209 | po::value<std::int64_t>()->default_value(default_minimum_slice_size), |
| 210 | "minimum slice size"); |
| 211 | |
| 212 | // parse the input into the map |
| 213 | po::variables_map vm; |
| 214 | |
| 215 | // run notify() for all registered options in the map |
| 216 | try { |
| 217 | po::parsed_options parsed = po::command_line_parser(argc, argv) |
| 218 | .options(desc) |
| 219 | .positional(positional) |
| 220 | .run(); |
| 221 | po::store(parsed, vm); |
| 222 | po::notify(vm); |
| 223 | } catch (std::exception const& ex) { |
| 224 | // if required arguments are missing but help is desired, just print help |
| 225 | if (vm.count("help") > 0 or argc == 1) usage(argv[0], desc); |
| 226 | usage(argv[0], desc, ex.what()); |
| 227 | } |
| 228 | |
| 229 | if (vm.count("help") != 0) usage(argv[0], desc); |
| 230 | |
| 231 | for (std::string opt : kPositional) { |
| 232 | if (not vm[opt].as<std::string>().empty()) continue; |
| 233 | usage(argv[0], desc, fmt::format("the {} argument cannot be empty", opt)); |
| 234 | } |
| 235 | |
| 236 | if (vm["thread-count"].as<int>() == 0) { |
| 237 | usage(argv[0], desc, "the --thread-count option cannot be zero"); |