187 if ( argc < 2 or not std::string_view{argv[1]}.starts_with(
"fim-"))
192 VecArgs args(argv+1, argv+argc);
195 std::string cmd_str = Pop(args.
pop_front<
"C::Missing fim- command">());
200 case FimCommand::EXEC:
202 return CmdType(
CmdExec(Pop(args.
pop_front<
"C::Incorrect number of arguments for fim-exec">())
207 case FimCommand::ROOT:
209 return CmdType(
CmdRoot(Pop(args.
pop_front<
"C::Incorrect number of arguments for fim-root">())
215 case FimCommand::PERMS:
219 CmdPermsOp::from_string(Pop(args.
pop_front<
"C::Missing op for fim-perms (add,del,list,set,clear)">())),
"C::Invalid perms operation"
223 std::set<CmdPerms::Permission> permissions;
226 permissions.insert(Pop(CmdPerms::Permission::from_string(arg),
"C::Invalid permission"));
234 case CmdPermsOp::SET:
236 cmd_perms.sub_cmd =
CmdPerms::Set { .permissions = Pop(f_process_permissions(),
"C::Failed to process permissions") };
239 case CmdPermsOp::ADD:
241 cmd_perms.sub_cmd =
CmdPerms::Add { .permissions = Pop(f_process_permissions(),
"C::Failed to process permissions") };
244 case CmdPermsOp::DEL:
246 cmd_perms.sub_cmd =
CmdPerms::Del { .permissions = Pop(f_process_permissions(),
"C::Failed to process permissions") };
249 case CmdPermsOp::LIST:
254 case CmdPermsOp::CLEAR:
259 case CmdPermsOp::NONE:
261 return Error(
"C::Invalid operation for permissions");
265 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-perms: {}", args.
data()));
266 return CmdType{cmd_perms};
270 case FimCommand::ENV:
274 CmdEnvOp::from_string(Pop(args.
pop_front<
"C::Missing op for 'fim-env' (add,del,list,set,clear)">())),
"C::Invalid env operation"
279 return_if(args.
empty(), Error(
"C::Missing arguments for '{}'", op));
280 std::vector<std::string> out = args.
data();
290 cmd_env.sub_cmd =
CmdEnv::Set { .variables = Pop(f_process_variables(),
"C::Failed to process variables") };
295 cmd_env.sub_cmd =
CmdEnv::Add { .variables = Pop(f_process_variables(),
"C::Failed to process variables") };
300 cmd_env.sub_cmd =
CmdEnv::Del { .variables = Pop(f_process_variables(),
"C::Failed to process variables") };
308 case CmdEnvOp::CLEAR:
315 return Error(
"C::Invalid operation for environment");
319 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-env: {}", args.
data()));
321 return CmdType{cmd_env};
325 case FimCommand::DESKTOP:
330 CmdDesktopOp op = Pop(CmdDesktopOp::from_string(
331 Pop(args.
pop_front<
"C::Missing op for 'fim-desktop' (enable,setup,clean,dump)">())),
"C::Invalid desktop operation"
336 case CmdDesktopOp::SETUP:
340 .path_file_setup = Pop(args.
pop_front<
"C::Missing argument for 'setup' (/path/to/file.json)">())
344 case CmdDesktopOp::ENABLE:
347 std::vector<std::string> vec_items =
348 Pop(args.
pop_front<
"C::Missing arguments for 'enable' (entry,mimetype,icon,none)">())
349 | std::views::split(
',')
350 | std::ranges::to<std::vector<std::string>>();
352 std::set<ns_desktop::IntegrationItem> set_enable;
353 for(
auto&& item : vec_items)
355 set_enable.insert(Pop(ns_desktop::IntegrationItem::from_string(item),
"C::Invalid integration item"));
358 if(set_enable.size() > 1 and set_enable.contains(ns_desktop::IntegrationItem::NONE))
360 return Error(
"C::'none' option should not be used with others");
364 .set_enable = set_enable
368 case CmdDesktopOp::DUMP:
371 CmdDesktopDump op_dump = Pop(CmdDesktopDump::from_string(
372 Pop(args.
pop_front<
"C::Missing arguments for 'dump' (entry,mimetype,icon)">())
373 ),
"C::Invalid dump operation");
377 case CmdDesktopDump::ICON:
380 .path_file_icon = Pop(args.
pop_front<
"C::Missing argument for 'icon' /path/to/dump/file">())
384 case CmdDesktopDump::ENTRY:
389 case CmdDesktopDump::MIMETYPE:
394 case CmdDesktopDump::NONE:
return Error(
"C::Invalid desktop dump operation");
398 case CmdDesktopOp::CLEAN:
403 case CmdDesktopOp::NONE:
return Error(
"C::Invalid desktop operation");
405 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-desktop: {}", args.
data()));
410 case FimCommand::LAYER:
416 CmdLayerOp::from_string(Pop(args.
pop_front<
"C::Missing op for 'fim-layer' (create,add,commit,list)">())),
"C::Invalid layer operation"
421 case CmdLayerOp::ADD:
426 .path_file_src = (Pop(args.
pop_front<error_msg>()))
428 return_if(not args.
empty(), Error(
"C::{}", error_msg));
431 case CmdLayerOp::CREATE:
433 constexpr ns_string::static_string error_msg =
"C::create requires exactly two arguments (/path/to/dir /path/to/file.layer)";
436 .path_dir_src = Pop(args.
pop_front<error_msg>()),
437 .path_file_target = Pop(args.
pop_front<error_msg>())
439 return_if(not args.
empty(), Error(
"C::{}", error_msg));
442 case CmdLayerOp::COMMIT:
444 CmdLayerCommitOp commit_op = Pop(
445 CmdLayerCommitOp::from_string(Pop(args.
pop_front<
"C::Missing op for 'commit' (binary,layer,file)">()))
446 ,
"C::Invalid commit operation"
451 case CmdLayerCommitOp::BINARY:
456 case CmdLayerCommitOp::LAYER:
461 case CmdLayerCommitOp::FILE:
464 .path_file_dst = Pop(args.
pop_front<
"C::Missing path for 'file' operation">())
468 case CmdLayerCommitOp::NONE:
return Error(
"C::Invalid commit operation");
470 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-layer commit: {}", args.
data()));
471 cmd.sub_cmd = cmd_commit;
474 case CmdLayerOp::LIST:
477 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-layer list: {}", args.
data()));
480 case CmdLayerOp::NONE:
return Error(
"C::Invalid layer operation");
486 case FimCommand::BIND:
492 CmdBindOp::from_string(Pop(args.
pop_front<
"C::Missing op for 'fim-bind' command (add,del,list)">())) ,
"C::Invalid bind operation"
502 .type = Pop(ns_db::ns_bind::Type::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid bind type"),
506 return_if(not args.
empty(), Error(
"C::{}", msg));
511 std::string str_index = Pop(args.
pop_front<
"C::Incorrect number of arguments for 'del' (<index>)">());
512 return_if(not std::ranges::all_of(str_index, ::isdigit)
513 , Error(
"C::Index argument for 'del' is not a number")
517 .index = Try(std::stoull(str_index),
"C::Invalid index")
519 return_if(not args.
empty(), Error(
"C::Incorrect number of arguments for 'del' (<index>)"));
522 case CmdBindOp::LIST:
525 return_if(not args.
empty(), Error(
"C::'list' command takes no arguments"));
528 case CmdBindOp::NONE:
return Error(
"C::Invalid operation for bind");
534 case FimCommand::NOTIFY:
538 Pop(CmdNotifySwitch::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid notify switch")
540 return_if(not args.
empty(), Error(
"C::{}", msg));
545 case FimCommand::CASEFOLD:
548 return_if(args.
empty(), Error(
"C::{}", msg));
550 Pop(CmdCaseFoldSwitch::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid casefold switch")
552 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-casefold: {}", args.
data()));
557 case FimCommand::BOOT:
560 CmdBootOp op = Pop(CmdBootOp::from_string(
561 Pop(args.
pop_front<
"C::Missing op for 'fim-boot' (<set|show|clear>)">())
562 ),
"C::Invalid boot operation");
570 .program = Pop(args.
pop_front<
"C::Missing program for 'set' operation">()),
576 case CmdBootOp::SHOW:
581 case CmdBootOp::CLEAR:
586 case CmdBootOp::NONE:
return Error(
"C::Invalid boot operation");
589 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-boot: {}", args.
data()));
594 case FimCommand::REMOTE:
597 CmdRemoteOp op = Pop(CmdRemoteOp::from_string(
598 Pop(args.
pop_front<
"C::Missing op for 'fim-remote' (<set|show|clear>)">())
599 ),
"C::Invalid remote operation");
604 case CmdRemoteOp::SET:
607 .url = Pop(args.
pop_front<
"C::Missing URL for 'set' operation">())
611 case CmdRemoteOp::SHOW:
616 case CmdRemoteOp::CLEAR:
621 case CmdRemoteOp::NONE:
return Error(
"C::Invalid remote operation");
624 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-remote: {}", args.
data()));
629 case FimCommand::RECIPE:
632 CmdRecipeOp op = Pop(CmdRecipeOp::from_string(
633 Pop(args.
pop_front<
"C::Missing op for 'fim-recipe' (<fetch|info|install>)">())
634 ),
"C::Invalid recipe operation");
637 auto f_parse_recipes = [](
auto& args) ->
Value<std::vector<std::string>>
639 std::vector<std::string> recipes = Pop(args.template pop_front<"C::Missing recipe for operation">())
640 | std::views::split(
',')
641 | std::ranges::to<std::vector<std::string>>();
642 return_if(recipes.empty(), Error(
"C::Recipe argument is empty"));
647 case CmdRecipeOp::FETCH:
649 cmd_recipe.sub_cmd =
CmdRecipe::Fetch { .recipes = Pop(f_parse_recipes(args),
"C::Invalid recipes") };
652 case CmdRecipeOp::INFO:
654 cmd_recipe.sub_cmd =
CmdRecipe::Info { .recipes = Pop(f_parse_recipes(args),
"C::Invalid recipes") };
657 case CmdRecipeOp::INSTALL:
659 cmd_recipe.sub_cmd =
CmdRecipe::Install { .recipes = Pop(f_parse_recipes(args),
"C::Invalid recipes") };
662 case CmdRecipeOp::NONE:
return Error(
"C::Invalid recipe operation");
665 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-recipe: {}", args.
data()));
670 case FimCommand::INSTANCE:
673 CmdInstanceOp op = Pop(CmdInstanceOp::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid instance operation");
677 case CmdInstanceOp::EXEC:
679 std::string str_id = Pop(args.
pop_front<
"C::Missing 'id' argument for 'fim-instance'">());
680 return_if(not std::ranges::all_of(str_id, ::isdigit), Error(
"C::Id argument must be a digit"));
681 return_if(args.
empty(), Error(
"C::Missing 'cmd' argument for 'fim-instance'"));
684 .id = Try(std::stoi(str_id),
"C::Invalid instance ID"),
690 case CmdInstanceOp::LIST:
695 case CmdInstanceOp::NONE:
return Error(
"C::Invalid instance operation");
697 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-instance: {}", args.
data()));
702 case FimCommand::OVERLAY:
706 CmdOverlayOp op = Pop(CmdOverlayOp::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid overlay operation");
711 case CmdOverlayOp::SET:
715 .overlay = Pop(ns_reserved::ns_overlay::OverlayType::from_string(
716 Pop(args.
pop_front<
"C::Missing argument for 'set'">())
717 ),
"C::Invalid overlay type")
721 case CmdOverlayOp::SHOW:
726 case CmdOverlayOp::NONE:
728 return Error(
"C::Invalid operation for fim-overlay");
731 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-overlay: {}", args.
data()));
736 case FimCommand::UNSHARE:
739 CmdUnshareOp op = Pop(
740 CmdUnshareOp::from_string(Pop(args.
pop_front<
"C::Missing op for fim-unshare (add,clear,del,list,set)">())),
"C::Invalid unshare operation"
744 std::set<CmdUnshare::Unshare> unshares;
747 unshares.insert(Pop(CmdUnshare::Unshare::from_string(arg),
"C::Invalid unshare option"));
755 case CmdUnshareOp::SET:
757 cmd_unshare.sub_cmd =
CmdUnshare::Set { .unshares = Pop(f_process_unshares(),
"C::Failed to process unshare options") };
760 case CmdUnshareOp::ADD:
762 cmd_unshare.sub_cmd =
CmdUnshare::Add { .unshares = Pop(f_process_unshares(),
"C::Failed to process unshare options") };
765 case CmdUnshareOp::DEL:
767 cmd_unshare.sub_cmd =
CmdUnshare::Del { .unshares = Pop(f_process_unshares(),
"C::Failed to process unshare options") };
770 case CmdUnshareOp::LIST:
775 case CmdUnshareOp::CLEAR:
780 case CmdUnshareOp::NONE:
782 return Error(
"C::Invalid operation for unshare");
786 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-unshare: {}", args.
data()));
787 return CmdType{cmd_unshare};
791 case FimCommand::VERSION:
795 CmdVersionOp op = Pop(CmdVersionOp::from_string(Pop(args.
pop_front<msg>())),
"C::Invalid version operation");
803 case CmdVersionOp::NONE:
return Error(
"C::Invalid operation for fim-version");
805 return_if(not args.
empty(), Error(
"C::Trailing arguments for fim-version: {}", args.
data()));
810 case FimCommand::HELP:
814 std::cerr << ns_cmd::ns_help::help_usage() <<
'\n';
818 std::string help_topic = Pop(args.
pop_front<
"C::Missing argument for 'fim-help'">());
821 if (help_topic ==
"bind") { message = ns_cmd::ns_help::bind_usage(); }
822 else if (help_topic ==
"boot") { message = ns_cmd::ns_help::boot_usage(); }
823 else if (help_topic ==
"casefold") { message = ns_cmd::ns_help::casefold_usage(); }
824 else if (help_topic ==
"desktop") { message = ns_cmd::ns_help::desktop_usage(); }
825 else if (help_topic ==
"env") { message = ns_cmd::ns_help::env_usage(); }
826 else if (help_topic ==
"exec") { message = ns_cmd::ns_help::exec_usage(); }
827 else if (help_topic ==
"instance") { message = ns_cmd::ns_help::instance_usage(); }
828 else if (help_topic ==
"layer") { message = ns_cmd::ns_help::layer_usage(); }
829 else if (help_topic ==
"notify") { message = ns_cmd::ns_help::notify_usage(); }
830 else if (help_topic ==
"overlay") { message = ns_cmd::ns_help::overlay_usage(); }
831 else if (help_topic ==
"perms") { message = ns_cmd::ns_help::perms_usage(); }
832 else if (help_topic ==
"recipe") { message = ns_cmd::ns_help::recipe_usage(); }
833 else if (help_topic ==
"remote") { message = ns_cmd::ns_help::remote_usage(); }
834 else if (help_topic ==
"root") { message = ns_cmd::ns_help::root_usage(); }
835 else if (help_topic ==
"unshare") { message = ns_cmd::ns_help::unshare_usage(); }
836 else if (help_topic ==
"version") { message = ns_cmd::ns_help::version_usage(); }
839 return Error(
"C::Invalid argument for help command: {}", help_topic);
842 std::cout << message;
846 case FimCommand::NONE:
848 return Error(
"C::Unknown command");