FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
parser.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include <cstdlib>
12#include <ranges>
13#include <set>
14#include <string>
15#include <expected>
16#include <print>
17
18
19#include "../macro.hpp"
20#include "interface.hpp"
21#include "cmd/help.hpp"
22
32namespace ns_parser
33{
34
38enum class FimCommand
39{
40 NONE,
41 EXEC,
42 ROOT,
43 PERMS,
44 ENV,
45 DESKTOP,
46 LAYER,
47 BIND,
48 NOTIFY,
49 CASEFOLD,
50 BOOT,
51 REMOTE,
52 RECIPE,
53 INSTANCE,
54 OVERLAY,
55 UNSHARE,
56 VERSION,
57 HELP
58};
59
66[[nodiscard]] inline Value<FimCommand> fim_command_from_string(std::string_view str)
67{
68 if (str == "fim-bind") return FimCommand::BIND;
69 if (str == "fim-boot") return FimCommand::BOOT;
70 if (str == "fim-casefold") return FimCommand::CASEFOLD;
71 if (str == "fim-desktop") return FimCommand::DESKTOP;
72 if (str == "fim-env") return FimCommand::ENV;
73 if (str == "fim-exec") return FimCommand::EXEC;
74 if (str == "fim-help") return FimCommand::HELP;
75 if (str == "fim-instance") return FimCommand::INSTANCE;
76 if (str == "fim-layer") return FimCommand::LAYER;
77 if (str == "fim-notify") return FimCommand::NOTIFY;
78 if (str == "fim-overlay") return FimCommand::OVERLAY;
79 if (str == "fim-perms") return FimCommand::PERMS;
80 if (str == "fim-recipe") return FimCommand::RECIPE;
81 if (str == "fim-remote") return FimCommand::REMOTE;
82 if (str == "fim-root") return FimCommand::ROOT;
83 if (str == "fim-unshare") return FimCommand::UNSHARE;
84 if (str == "fim-version") return FimCommand::VERSION;
85
86 return Error("C::Unknown command: {}", str);
87}
88
89using namespace ns_parser::ns_interface;
90
98{
99 private:
100 std::vector<std::string> m_data;
101 public:
107 VecArgs(char** begin, char** end)
108 {
109 if(begin != end)
110 {
111 m_data = std::vector<std::string>(begin,end);
112 }
113 }
114
122 template<ns_string::static_string Format, typename... Ts>
124 {
125 if(m_data.empty())
126 {
127 if constexpr (sizeof...(Ts) > 0)
128 {
129 return Error(Format, ns_string::to_string(ts)...);
130 }
131 else
132 {
133 return Error(Format.data);
134 }
135 }
136 std::string item = m_data.front();
137 m_data.erase(m_data.begin());
138 return item;
139 }
140
145 std::vector<std::string> const& data()
146 {
147 return m_data;
148 }
149
154 size_t size()
155 {
156 return m_data.size();
157 }
158
163 bool empty()
164 {
165 return m_data.empty();
166 }
167
171 void clear()
172 {
173 m_data.clear();
174 }
175};
176
177
185[[nodiscard]] inline Value<CmdType> parse(int argc , char** argv)
186{
187 if ( argc < 2 or not std::string_view{argv[1]}.starts_with("fim-"))
188 {
189 return CmdNone{};
190 }
191
192 VecArgs args(argv+1, argv+argc);
193
194 // Get command string and convert to enum
195 std::string cmd_str = Pop(args.pop_front<"C::Missing fim- command">());
196 FimCommand cmd = Pop(fim_command_from_string(cmd_str), "C::Invalid fim command");
197
198 switch(cmd)
199 {
200 case FimCommand::EXEC:
201 {
202 return CmdType(CmdExec(Pop(args.pop_front<"C::Incorrect number of arguments for fim-exec">())
203 , args.data()
204 ));
205 }
206
207 case FimCommand::ROOT:
208 {
209 return CmdType(CmdRoot(Pop(args.pop_front<"C::Incorrect number of arguments for fim-root">())
210 , args.data())
211 );
212 }
213
214 // Configure permissions for the container
215 case FimCommand::PERMS:
216 {
217 // Get op
218 CmdPermsOp op = Pop(
219 CmdPermsOp::from_string(Pop(args.pop_front<"C::Missing op for fim-perms (add,del,list,set,clear)">())), "C::Invalid perms operation"
220 );
221 auto f_process_permissions = [&] -> Value<std::set<CmdPerms::Permission>>
222 {
223 std::set<CmdPerms::Permission> permissions;
224 for(auto arg : ns_vector::from_string(Pop(args.pop_front<"C::No arguments for '{}' command">(op)), ','))
225 {
226 permissions.insert(Pop(CmdPerms::Permission::from_string(arg), "C::Invalid permission"));
227 }
228 return permissions;
229 };
230 // Process Ops
231 CmdPerms cmd_perms;
232 switch(op)
233 {
234 case CmdPermsOp::SET:
235 {
236 cmd_perms.sub_cmd = CmdPerms::Set { .permissions = Pop(f_process_permissions(), "C::Failed to process permissions") };
237 }
238 break;
239 case CmdPermsOp::ADD:
240 {
241 cmd_perms.sub_cmd = CmdPerms::Add { .permissions = Pop(f_process_permissions(), "C::Failed to process permissions") };
242 }
243 break;
244 case CmdPermsOp::DEL:
245 {
246 cmd_perms.sub_cmd = CmdPerms::Del { .permissions = Pop(f_process_permissions(), "C::Failed to process permissions") };
247 }
248 break;
249 case CmdPermsOp::LIST:
250 {
251 cmd_perms.sub_cmd = CmdPerms::List{};
252 }
253 break;
254 case CmdPermsOp::CLEAR:
255 {
256 cmd_perms.sub_cmd = CmdPerms::Clear{};
257 }
258 break;
259 case CmdPermsOp::NONE:
260 {
261 return Error("C::Invalid operation for permissions");
262 }
263 }
264 // Check for trailing arguments
265 return_if(not args.empty(), Error("C::Trailing arguments for fim-perms: {}", args.data()));
266 return CmdType{cmd_perms};
267 }
268
269 // Configure environment
270 case FimCommand::ENV:
271 {
272 // Get op
273 CmdEnvOp op = Pop(
274 CmdEnvOp::from_string(Pop(args.pop_front<"C::Missing op for 'fim-env' (add,del,list,set,clear)">())), "C::Invalid env operation"
275 );
276 // Gather arguments with key/values if any
277 auto f_process_variables = [&] -> Value<std::vector<std::string>>
278 {
279 return_if(args.empty(), Error("C::Missing arguments for '{}'", op));
280 std::vector<std::string> out = args.data();
281 args.clear();
282 return out;
283 };
284 // Process command
285 CmdEnv cmd_env;
286 switch(op)
287 {
288 case CmdEnvOp::SET:
289 {
290 cmd_env.sub_cmd = CmdEnv::Set { .variables = Pop(f_process_variables(), "C::Failed to process variables") };
291 }
292 break;
293 case CmdEnvOp::ADD:
294 {
295 cmd_env.sub_cmd = CmdEnv::Add { .variables = Pop(f_process_variables(), "C::Failed to process variables") };
296 }
297 break;
298 case CmdEnvOp::DEL:
299 {
300 cmd_env.sub_cmd = CmdEnv::Del { .variables = Pop(f_process_variables(), "C::Failed to process variables") };
301 }
302 break;
303 case CmdEnvOp::LIST:
304 {
305 cmd_env.sub_cmd = CmdEnv::List{};
306 }
307 break;
308 case CmdEnvOp::CLEAR:
309 {
310 cmd_env.sub_cmd = CmdEnv::Clear{};
311 }
312 break;
313 case CmdEnvOp::NONE:
314 {
315 return Error("C::Invalid operation for environment");
316 }
317 }
318 // Check for trailing arguments
319 return_if(not args.empty(), Error("C::Trailing arguments for fim-env: {}", args.data()));
320 // Check if is other command with valid args
321 return CmdType{cmd_env};
322 }
323
324 // Configure desktop
325 case FimCommand::DESKTOP:
326 {
327 // Check if is other command with valid args
328 CmdDesktop cmd;
329 // Get operation
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"
332 );
333 // Get operation specific arguments
334 switch(op)
335 {
336 case CmdDesktopOp::SETUP:
337 {
338 cmd.sub_cmd = CmdDesktop::Setup
339 {
340 .path_file_setup = Pop(args.pop_front<"C::Missing argument for 'setup' (/path/to/file.json)">())
341 };
342 }
343 break;
344 case CmdDesktopOp::ENABLE:
345 {
346 // Get comma separated argument list
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>>();
351 // Create items
352 std::set<ns_desktop::IntegrationItem> set_enable;
353 for(auto&& item : vec_items)
354 {
355 set_enable.insert(Pop(ns_desktop::IntegrationItem::from_string(item), "C::Invalid integration item"));
356 }
357 // Check for 'none'
358 if(set_enable.size() > 1 and set_enable.contains(ns_desktop::IntegrationItem::NONE))
359 {
360 return Error("C::'none' option should not be used with others");
361 }
362 cmd.sub_cmd = CmdDesktop::Enable
363 {
364 .set_enable = set_enable
365 };
366 }
367 break;
368 case CmdDesktopOp::DUMP:
369 {
370 // Get dump operation
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");
374 // Parse dump operation
375 switch(op_dump)
376 {
377 case CmdDesktopDump::ICON:
378 {
380 .path_file_icon = Pop(args.pop_front<"C::Missing argument for 'icon' /path/to/dump/file">())
381 }};
382 }
383 break;
384 case CmdDesktopDump::ENTRY:
385 {
386 cmd.sub_cmd = CmdDesktop::Dump { CmdDesktop::Dump::Entry{} };
387 }
388 break;
389 case CmdDesktopDump::MIMETYPE:
390 {
392 }
393 break;
394 case CmdDesktopDump::NONE: return Error("C::Invalid desktop dump operation");
395 }
396 }
397 break;
398 case CmdDesktopOp::CLEAN:
399 {
400 cmd.sub_cmd = CmdDesktop::Clean{};
401 }
402 break;
403 case CmdDesktopOp::NONE: return Error("C::Invalid desktop operation");
404 }
405 return_if(not args.empty(), Error("C::Trailing arguments for fim-desktop: {}", args.data()));
406 return CmdType(cmd);
407 }
408
409 // Manage layers
410 case FimCommand::LAYER:
411 {
412 // Create cmd
413 CmdLayer cmd;
414 // Get op
415 CmdLayerOp op = Pop(
416 CmdLayerOp::from_string(Pop(args.pop_front<"C::Missing op for 'fim-layer' (create,add,commit,list)">())), "C::Invalid layer operation"
417 );
418 // Process command
419 switch(op)
420 {
421 case CmdLayerOp::ADD:
422 {
423 constexpr ns_string::static_string error_msg = "C::add requires exactly one argument (/path/to/file.layer)";
424 cmd.sub_cmd = CmdLayer::Add
425 {
426 .path_file_src = (Pop(args.pop_front<error_msg>()))
427 };
428 return_if(not args.empty(), Error("C::{}", error_msg));
429 }
430 break;
431 case CmdLayerOp::CREATE:
432 {
433 constexpr ns_string::static_string error_msg = "C::create requires exactly two arguments (/path/to/dir /path/to/file.layer)";
434 cmd.sub_cmd = CmdLayer::Create
435 {
436 .path_dir_src = Pop(args.pop_front<error_msg>()),
437 .path_file_target = Pop(args.pop_front<error_msg>())
438 };
439 return_if(not args.empty(), Error("C::{}", error_msg));
440 }
441 break;
442 case CmdLayerOp::COMMIT:
443 {
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"
447 );
448 CmdLayer::Commit cmd_commit;
449 switch(commit_op)
450 {
451 case CmdLayerCommitOp::BINARY:
452 {
453 cmd_commit.sub_cmd = CmdLayer::Commit::Binary{};
454 }
455 break;
456 case CmdLayerCommitOp::LAYER:
457 {
458 cmd_commit.sub_cmd = CmdLayer::Commit::Layer{};
459 }
460 break;
461 case CmdLayerCommitOp::FILE:
462 {
463 cmd_commit.sub_cmd = CmdLayer::Commit::File{
464 .path_file_dst = Pop(args.pop_front<"C::Missing path for 'file' operation">())
465 };
466 }
467 break;
468 case CmdLayerCommitOp::NONE: return Error("C::Invalid commit operation");
469 }
470 return_if(not args.empty(), Error("C::Trailing arguments for fim-layer commit: {}", args.data()));
471 cmd.sub_cmd = cmd_commit;
472 }
473 break;
474 case CmdLayerOp::LIST:
475 {
476 cmd.sub_cmd = CmdLayer::List{};
477 return_if(not args.empty(), Error("C::Trailing arguments for fim-layer list: {}", args.data()));
478 }
479 break;
480 case CmdLayerOp::NONE: return Error("C::Invalid layer operation");
481 }
482 return CmdType(cmd);
483 }
484
485 // Bind a path or device to inside the flatimage
486 case FimCommand::BIND:
487 {
488 // Create command
489 CmdBind cmd;
490 // Check op
491 CmdBindOp op = Pop(
492 CmdBindOp::from_string(Pop(args.pop_front<"C::Missing op for 'fim-bind' command (add,del,list)">())) , "C::Invalid bind operation"
493 );
494 // Process command
495 switch(op)
496 {
497 case CmdBindOp::ADD:
498 {
499 constexpr ns_string::static_string msg = "C::Incorrect number of arguments for 'add' (<ro,rw,dev> <src> <dst>)";
500 cmd.sub_cmd = CmdBind::Add
501 {
502 .type = Pop(ns_db::ns_bind::Type::from_string(Pop(args.pop_front<msg>())), "C::Invalid bind type"),
503 .path_src = Pop(args.pop_front<msg>()),
504 .path_dst = Pop(args.pop_front<msg>())
505 };
506 return_if(not args.empty(), Error("C::{}", msg));
507 }
508 break;
509 case CmdBindOp::DEL:
510 {
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")
514 );
515 cmd.sub_cmd = CmdBind::Del
516 {
517 .index = Try(std::stoull(str_index), "C::Invalid index")
518 };
519 return_if(not args.empty(), Error("C::Incorrect number of arguments for 'del' (<index>)"));
520 }
521 break;
522 case CmdBindOp::LIST:
523 {
524 cmd.sub_cmd = CmdBind::List{};
525 return_if(not args.empty(), Error("C::'list' command takes no arguments"));
526 }
527 break;
528 case CmdBindOp::NONE: return Error("C::Invalid operation for bind");
529 }
530 return CmdType(cmd);
531 }
532
533 // Notifies with notify-send when the program starts
534 case FimCommand::NOTIFY:
535 {
536 constexpr ns_string::static_string msg = "C::Incorrect number of arguments for 'fim-notify' (<on|off>)";
537 auto cmd_notify = CmdType(CmdNotify{
538 Pop(CmdNotifySwitch::from_string(Pop(args.pop_front<msg>())), "C::Invalid notify switch")
539 });
540 return_if(not args.empty(), Error("C::{}", msg));
541 return cmd_notify;
542 }
543
544 // Enables or disable ignore case for paths (useful for wine)
545 case FimCommand::CASEFOLD:
546 {
547 constexpr ns_string::static_string msg = "C::Incorrect number of arguments for 'fim-casefold' (<on|off>)";
548 return_if(args.empty(), Error("C::{}", msg));
549 auto cmd_casefold = CmdType(CmdCaseFold{
550 Pop(CmdCaseFoldSwitch::from_string(Pop(args.pop_front<msg>())), "C::Invalid casefold switch")
551 });
552 return_if(not args.empty(), Error("C::Trailing arguments for fim-casefold: {}", args.data()));
553 return cmd_casefold;
554 }
555
556 // Set the default startup command
557 case FimCommand::BOOT:
558 {
559 // Check op
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");
563 // Build command
564 CmdBoot cmd_boot;
565 switch(op)
566 {
567 case CmdBootOp::SET:
568 {
569 cmd_boot.sub_cmd = CmdBoot::Set {
570 .program = Pop(args.pop_front<"C::Missing program for 'set' operation">()),
571 .args = args.data()
572 };
573 args.clear();
574 }
575 break;
576 case CmdBootOp::SHOW:
577 {
578 cmd_boot.sub_cmd = CmdBoot::Show{};
579 }
580 break;
581 case CmdBootOp::CLEAR:
582 {
583 cmd_boot.sub_cmd = CmdBoot::Clear{};
584 }
585 break;
586 case CmdBootOp::NONE: return Error("C::Invalid boot operation");
587 }
588 // Check for trailing arguments
589 return_if(not args.empty(), Error("C::Trailing arguments for fim-boot: {}", args.data()));
590 return cmd_boot;
591 }
592
593 // Set, show, or clear the remote URL
594 case FimCommand::REMOTE:
595 {
596 // Check op
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");
600 // Build command
601 CmdRemote cmd_remote;
602 switch(op)
603 {
604 case CmdRemoteOp::SET:
605 {
606 cmd_remote.sub_cmd = CmdRemote::Set {
607 .url = Pop(args.pop_front<"C::Missing URL for 'set' operation">())
608 };
609 }
610 break;
611 case CmdRemoteOp::SHOW:
612 {
613 cmd_remote.sub_cmd = CmdRemote::Show{};
614 }
615 break;
616 case CmdRemoteOp::CLEAR:
617 {
618 cmd_remote.sub_cmd = CmdRemote::Clear{};
619 }
620 break;
621 case CmdRemoteOp::NONE: return Error("C::Invalid remote operation");
622 }
623 // Check for trailing arguments
624 return_if(not args.empty(), Error("C::Trailing arguments for fim-remote: {}", args.data()));
625 return cmd_remote;
626 }
627
628 // Fetch and install recipes
629 case FimCommand::RECIPE:
630 {
631 // Check op
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");
635 // Build command
636 CmdRecipe cmd_recipe;
637 auto f_parse_recipes = [](auto& args) -> Value<std::vector<std::string>>
638 {
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"));
643 return recipes;
644 };
645 switch(op)
646 {
647 case CmdRecipeOp::FETCH:
648 {
649 cmd_recipe.sub_cmd = CmdRecipe::Fetch { .recipes = Pop(f_parse_recipes(args), "C::Invalid recipes") };
650 }
651 break;
652 case CmdRecipeOp::INFO:
653 {
654 cmd_recipe.sub_cmd = CmdRecipe::Info { .recipes = Pop(f_parse_recipes(args), "C::Invalid recipes") };
655 }
656 break;
657 case CmdRecipeOp::INSTALL:
658 {
659 cmd_recipe.sub_cmd = CmdRecipe::Install { .recipes = Pop(f_parse_recipes(args), "C::Invalid recipes") };
660 }
661 break;
662 case CmdRecipeOp::NONE: return Error("C::Invalid recipe operation");
663 }
664 // Check for trailing arguments
665 return_if(not args.empty(), Error("C::Trailing arguments for fim-recipe: {}", args.data()));
666 return cmd_recipe;
667 }
668
669 // Run a command in an existing instance
670 case FimCommand::INSTANCE:
671 {
672 constexpr ns_string::static_string msg = "C::Missing op for 'fim-instance' (<exec|list>)";
673 CmdInstanceOp op = Pop(CmdInstanceOp::from_string(Pop(args.pop_front<msg>())), "C::Invalid instance operation");
674 CmdInstance cmd;
675 switch(op)
676 {
677 case CmdInstanceOp::EXEC:
678 {
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'"));
682 cmd.sub_cmd = CmdInstance::Exec
683 {
684 .id = Try(std::stoi(str_id), "C::Invalid instance ID"),
685 .args = args.data(),
686 };
687 args.clear();
688 }
689 break;
690 case CmdInstanceOp::LIST:
691 {
692 cmd.sub_cmd = CmdInstance::List{};
693 }
694 break;
695 case CmdInstanceOp::NONE: return Error("C::Invalid instance operation");
696 }
697 return_if(not args.empty(), Error("C::Trailing arguments for fim-instance: {}", args.data()));
698 return CmdType(cmd);
699 }
700
701 // Select or show the current overlay filesystem
702 case FimCommand::OVERLAY:
703 {
704 constexpr ns_string::static_string msg = "C::Missing op for 'fim-overlay' (<set|show>)";
705 // Get op
706 CmdOverlayOp op = Pop(CmdOverlayOp::from_string(Pop(args.pop_front<msg>())), "C::Invalid overlay operation");
707 // Build command
708 CmdOverlay cmd;
709 switch(op)
710 {
711 case CmdOverlayOp::SET:
712 {
713 cmd.sub_cmd = CmdOverlay::Set
714 {
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")
718 };
719 }
720 break;
721 case CmdOverlayOp::SHOW:
722 {
723 cmd.sub_cmd = CmdOverlay::Show{};
724 }
725 break;
726 case CmdOverlayOp::NONE:
727 {
728 return Error("C::Invalid operation for fim-overlay");
729 }
730 }
731 return_if(not args.empty(), Error("C::Trailing arguments for fim-overlay: {}", args.data()));
732 return CmdType(cmd);
733 }
734
735 // Configure unshare namespace options
736 case FimCommand::UNSHARE:
737 {
738 // Get op
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"
741 );
742 auto f_process_unshares = [&] -> Value<std::set<CmdUnshare::Unshare>>
743 {
744 std::set<CmdUnshare::Unshare> unshares;
745 for(auto arg : ns_vector::from_string(Pop(args.pop_front<"C::No arguments for '{}' command">(op)), ','))
746 {
747 unshares.insert(Pop(CmdUnshare::Unshare::from_string(arg), "C::Invalid unshare option"));
748 }
749 return unshares;
750 };
751 // Process Ops
752 CmdUnshare cmd_unshare;
753 switch(op)
754 {
755 case CmdUnshareOp::SET:
756 {
757 cmd_unshare.sub_cmd = CmdUnshare::Set { .unshares = Pop(f_process_unshares(), "C::Failed to process unshare options") };
758 }
759 break;
760 case CmdUnshareOp::ADD:
761 {
762 cmd_unshare.sub_cmd = CmdUnshare::Add { .unshares = Pop(f_process_unshares(), "C::Failed to process unshare options") };
763 }
764 break;
765 case CmdUnshareOp::DEL:
766 {
767 cmd_unshare.sub_cmd = CmdUnshare::Del { .unshares = Pop(f_process_unshares(), "C::Failed to process unshare options") };
768 }
769 break;
770 case CmdUnshareOp::LIST:
771 {
772 cmd_unshare.sub_cmd = CmdUnshare::List{};
773 }
774 break;
775 case CmdUnshareOp::CLEAR:
776 {
777 cmd_unshare.sub_cmd = CmdUnshare::Clear{};
778 }
779 break;
780 case CmdUnshareOp::NONE:
781 {
782 return Error("C::Invalid operation for unshare");
783 }
784 }
785 // Check for trailing arguments
786 return_if(not args.empty(), Error("C::Trailing arguments for fim-unshare: {}", args.data()));
787 return CmdType{cmd_unshare};
788 }
789
790 // Select or show the current overlay filesystem
791 case FimCommand::VERSION:
792 {
793 constexpr ns_string::static_string msg = "C::Missing op for 'fim-version' (<short|full|deps>)";
794 // Get op
795 CmdVersionOp op = Pop(CmdVersionOp::from_string(Pop(args.pop_front<msg>())), "C::Invalid version operation");
796 // Build command
797 CmdVersion cmd;
798 switch(op)
799 {
800 case CmdVersionOp::SHORT: cmd.sub_cmd = CmdVersion::Short{}; break;
801 case CmdVersionOp::FULL: cmd.sub_cmd = CmdVersion::Full{}; break;
802 case CmdVersionOp::DEPS: cmd.sub_cmd = CmdVersion::Deps{}; break;
803 case CmdVersionOp::NONE: return Error("C::Invalid operation for fim-version");
804 }
805 return_if(not args.empty(), Error("C::Trailing arguments for fim-version: {}", args.data()));
806 return CmdType(cmd);
807 }
808
809 // Use the default startup command
810 case FimCommand::HELP:
811 {
812 if (args.empty())
813 {
814 std::cerr << ns_cmd::ns_help::help_usage() << '\n';
815 return CmdType(CmdExit{});
816 }
817
818 std::string help_topic = Pop(args.pop_front<"C::Missing argument for 'fim-help'">());
819 std::string message;
820
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(); }
837 else
838 {
839 return Error("C::Invalid argument for help command: {}", help_topic);
840 }
841
842 std::cout << message;
843 return CmdType(CmdExit{});
844 }
845
846 case FimCommand::NONE:
847 default:
848 return Error("C::Unknown command");
849 }
850}
851
852} // namespace ns_parser
853
854/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/
Vector-based argument container with pop operations.
Definition parser.hpp:98
VecArgs(char **begin, char **end)
Constructs a VecArgs from an iterator range.
Definition parser.hpp:107
bool empty()
Checks if the argument vector is empty.
Definition parser.hpp:163
void clear()
Clears all arguments.
Definition parser.hpp:171
size_t size()
Returns the number of arguments.
Definition parser.hpp:154
std::vector< std::string > const & data()
Returns a const reference to the underlying data.
Definition parser.hpp:145
Value< std::string > pop_front(Ts &&... ts)
Pops the front element with formatted error message.
Definition parser.hpp:123
Help strings for FlatImage commands.
Interfaces of FlatImage commands.
Simplified macros for common control flow patterns with optional logging.
Command interface definitions and argument structures.
FlatImage command parsing and execution engine.
Definition executor.hpp:43
FimCommand
Enumeration of FlatImage command types.
Definition parser.hpp:39
Value< FimCommand > fim_command_from_string(std::string_view str)
Convert string to FimCommand enum.
Definition parser.hpp:66
Value< CmdType > parse(int argc, char **argv)
Parses FlatImage commands.
Definition parser.hpp:185
std::string to_string(T &&t) noexcept
Converts a type to a string.
Definition string.hpp:97
R from_string(ns_concept::StringRepresentable auto &&t, char delimiter) noexcept
Creates a range from a string.
Definition vector.hpp:84
Enhanced expected type with integrated logging capabilities.
Definition expected.hpp:44
Compile-time string container with fixed size.
Definition string.hpp:35