aboutsummaryrefslogtreecommitdiff
path: root/tools/aconfig/aflags/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aconfig/aflags/src/main.rs')
-rw-r--r--tools/aconfig/aflags/src/main.rs173
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);
+ }
}