agent_os_kernel/
command_registry.rs1use crate::vfs::{VfsResult, VirtualFileSystem};
2use std::collections::BTreeMap;
3
4const COMMAND_STUB: &[u8] = b"#!/bin/sh\n# kernel command stub\n";
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct CommandDriver {
8 name: String,
9 commands: Vec<String>,
10}
11
12impl CommandDriver {
13 pub fn new<N, I, C>(name: N, commands: I) -> Self
14 where
15 N: Into<String>,
16 I: IntoIterator<Item = C>,
17 C: Into<String>,
18 {
19 Self {
20 name: name.into(),
21 commands: commands.into_iter().map(Into::into).collect(),
22 }
23 }
24
25 pub fn name(&self) -> &str {
26 &self.name
27 }
28
29 pub fn commands(&self) -> &[String] {
30 &self.commands
31 }
32}
33
34#[derive(Debug, Default, Clone)]
35pub struct CommandRegistry {
36 commands: BTreeMap<String, CommandDriver>,
37 warnings: Vec<String>,
38}
39
40impl CommandRegistry {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn register(&mut self, driver: CommandDriver) {
46 for command in &driver.commands {
47 if let Some(existing) = self.commands.get(command) {
48 self.warnings.push(format!(
49 "command \"{command}\" overridden: {} -> {}",
50 existing.name(),
51 driver.name()
52 ));
53 }
54
55 self.commands.insert(command.clone(), driver.clone());
56 }
57 }
58
59 pub fn warnings(&self) -> &[String] {
60 &self.warnings
61 }
62
63 pub fn resolve(&self, command: &str) -> Option<&CommandDriver> {
64 self.commands.get(command)
65 }
66
67 pub fn list(&self) -> BTreeMap<String, String> {
68 self.commands
69 .iter()
70 .map(|(command, driver)| (command.clone(), driver.name().to_owned()))
71 .collect()
72 }
73
74 pub fn populate_bin<F>(&self, vfs: &mut F) -> VfsResult<()>
75 where
76 F: VirtualFileSystem,
77 {
78 self.populate_commands(vfs, self.commands.keys())
79 }
80
81 pub fn populate_driver_bin<F>(&self, vfs: &mut F, driver: &CommandDriver) -> VfsResult<()>
82 where
83 F: VirtualFileSystem,
84 {
85 self.populate_commands(vfs, driver.commands())
86 }
87
88 fn populate_commands<F, I, S>(&self, vfs: &mut F, commands: I) -> VfsResult<()>
89 where
90 F: VirtualFileSystem,
91 I: IntoIterator<Item = S>,
92 S: AsRef<str>,
93 {
94 if !vfs.exists("/bin") {
95 vfs.mkdir("/bin", true)?;
96 }
97
98 for command in commands {
99 let path = format!("/bin/{}", command.as_ref());
100 if !vfs.exists(&path) {
101 vfs.write_file(&path, COMMAND_STUB.to_vec())?;
102 let _ = vfs.chmod(&path, 0o755);
103 }
104 }
105
106 Ok(())
107 }
108}