diff options
Diffstat (limited to 'tools/aconfig/aflags/src/main.rs')
-rw-r--r-- | tools/aconfig/aflags/src/main.rs | 173 |
1 files changed, 147 insertions, 26 deletions
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs index 4ce0d35ba1..810f2e31e6 100644 --- a/tools/aconfig/aflags/src/main.rs +++ b/tools/aconfig/aflags/src/main.rs @@ -33,12 +33,16 @@ enum FlagPermission { ReadWrite, } -impl ToString for FlagPermission { - fn to_string(&self) -> String { - match &self { - Self::ReadOnly => "read-only".into(), - Self::ReadWrite => "read-write".into(), - } +impl std::fmt::Display for FlagPermission { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::ReadOnly => "read-only", + Self::ReadWrite => "read-write", + } + ) } } @@ -48,12 +52,16 @@ enum ValuePickedFrom { Server, } -impl ToString for ValuePickedFrom { - fn to_string(&self) -> String { - match &self { - Self::Default => "default".into(), - Self::Server => "server".into(), - } +impl std::fmt::Display for ValuePickedFrom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::Default => "default", + Self::Server => "server", + } + ) } } @@ -75,12 +83,16 @@ impl TryFrom<&str> for FlagValue { } } -impl ToString for FlagValue { - fn to_string(&self) -> String { - match &self { - Self::Enabled => "enabled".into(), - Self::Disabled => "disabled".into(), - } +impl std::fmt::Display for FlagValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::Enabled => "enabled", + Self::Disabled => "disabled", + } + ) } } @@ -103,7 +115,7 @@ impl Flag { fn display_staged_value(&self) -> String { match self.staged_value { - Some(v) => format!("(->{})", v.to_string()), + Some(v) => format!("(->{})", v), None => "-".to_string(), } } @@ -153,6 +165,10 @@ enum Command { /// Read from the new flag storage. #[clap(long)] use_new_storage: bool, + + /// Optionally filter by container name. + #[clap(short = 'c', long = "container")] + container: Option<String>, }, /// Enable an aconfig flag on this device, on the next boot. @@ -176,6 +192,23 @@ struct PaddingInfo { longest_permission_col: usize, } +struct Filter { + container: Option<String>, +} + +impl Filter { + fn apply(&self, flags: &[Flag]) -> Vec<Flag> { + flags + .iter() + .filter(|flag| match &self.container { + Some(c) => flag.container == *c, + None => true, + }) + .cloned() + .collect() + } +} + fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { let full_name = flag.qualified_name(); let p0 = info.longest_flag_col + 1; @@ -200,8 +233,6 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { } fn set_flag(qualified_name: &str, value: &str) -> Result<()> { - ensure!(nix::unistd::Uid::current().is_root(), "must be root to mutate flags"); - let flags_binding = DeviceConfigSource::list_flags()?; let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or( anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"), @@ -215,11 +246,12 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> { Ok(()) } -fn list(source_type: FlagSourceType) -> Result<String> { - let flags = match source_type { +fn list(source_type: FlagSourceType, container: Option<String>) -> Result<String> { + let flags_unfiltered = match source_type { FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?, FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?, }; + let flags = (Filter { container }).apply(&flags_unfiltered); let padding_info = PaddingInfo { longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0), longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0), @@ -248,11 +280,17 @@ fn list(source_type: FlagSourceType) -> Result<String> { Ok(result) } -fn main() { +fn main() -> Result<()> { + ensure!(nix::unistd::Uid::current().is_root(), "must be root"); + let cli = Cli::parse(); let output = match cli.command { - Command::List { use_new_storage: true } => list(FlagSourceType::AconfigStorage).map(Some), - Command::List { use_new_storage: false } => list(FlagSourceType::DeviceConfig).map(Some), + Command::List { use_new_storage: true, container } => { + list(FlagSourceType::AconfigStorage, container).map(Some) + } + Command::List { use_new_storage: false, container } => { + list(FlagSourceType::DeviceConfig, container).map(Some) + } Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None), Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None), }; @@ -261,4 +299,87 @@ fn main() { Ok(None) => (), Err(message) => println!("Error: {message}"), } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_filter_container() { + let flags = vec![ + Flag { + namespace: "namespace".to_string(), + name: "test1".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test2".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "not_system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test3".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + ]; + + assert_eq!((Filter { container: Some("system".to_string()) }).apply(&flags).len(), 2); + } + + #[test] + fn test_filter_no_container() { + let flags = vec![ + Flag { + namespace: "namespace".to_string(), + name: "test1".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test2".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "not_system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test3".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + ]; + + assert_eq!((Filter { container: None }).apply(&flags).len(), 3); + } } |