Loading tools/aconfig/aflags/src/device_config_source.rs +16 −15 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ use crate::{Flag, FlagPermission, FlagSource, ValuePickedFrom}; use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom}; use aconfig_protos::ProtoFlagPermission as ProtoPermission; use aconfig_protos::ProtoFlagState as ProtoState; use aconfig_protos::ProtoParsedFlag; Loading @@ -40,10 +40,9 @@ fn convert_parsed_flag(flag: &ProtoParsedFlag) -> Flag { }; let value = match flag.state() { ProtoState::ENABLED => "true", ProtoState::DISABLED => "false", } .to_string(); ProtoState::ENABLED => FlagValue::Enabled, ProtoState::DISABLED => FlagValue::Disabled, }; let permission = match flag.permission() { ProtoPermission::READ_ONLY => FlagPermission::ReadOnly, Loading Loading @@ -86,14 +85,16 @@ fn read_pb_files() -> Result<Vec<Flag>> { Ok(flags.values().cloned().collect()) } fn parse_device_config(raw: &str) -> Result<HashMap<String, String>> { fn parse_device_config(raw: &str) -> Result<HashMap<String, FlagValue>> { let mut flags = HashMap::new(); let regex = Regex::new(r"(?m)^([[[:alnum:]]_]+/[[[:alnum:]]_\.]+)=(true|false)$")?; for capture in regex.captures_iter(raw) { let key = capture.get(1).ok_or(anyhow!("invalid device_config output"))?.as_str().to_string(); let value = capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str(); flags.insert(key, value.to_string()); let value = FlagValue::try_from( capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str(), )?; flags.insert(key, value); } Ok(flags) } Loading @@ -112,24 +113,24 @@ fn read_device_config_output(command: &[&str]) -> Result<String> { Ok(str::from_utf8(&output.stdout)?.to_string()) } fn read_device_config_flags() -> Result<HashMap<String, String>> { fn read_device_config_flags() -> Result<HashMap<String, FlagValue>> { let list_output = read_device_config_output(&["list"])?; parse_device_config(&list_output) } fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, String>) -> Vec<Flag> { fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, FlagValue>) -> Vec<Flag> { pb_flags .iter() .map(|f| { dc_flags .get(&format!("{}/{}.{}", f.namespace, f.package, f.name)) .map(|value| { if value.eq(&f.value) { if *value == f.value { Flag { value_picked_from: ValuePickedFrom::Default, ..f.clone() } } else { Flag { value_picked_from: ValuePickedFrom::Server, value: value.to_string(), value: *value, ..f.clone() } } Loading Loading @@ -167,9 +168,9 @@ namespace_two/android.flag_one=true namespace_two/android.flag_two=nonsense "#; let expected = HashMap::from([ ("namespace_one/com.foo.bar.flag_one".to_string(), "true".to_string()), ("namespace_one/com.foo.bar.flag_two".to_string(), "false".to_string()), ("namespace_two/android.flag_one".to_string(), "true".to_string()), ("namespace_one/com.foo.bar.flag_one".to_string(), FlagValue::Enabled), ("namespace_one/com.foo.bar.flag_two".to_string(), FlagValue::Disabled), ("namespace_two/android.flag_one".to_string(), FlagValue::Enabled), ]); let actual = parse_device_config(input).unwrap(); assert_eq!(expected, actual); Loading tools/aconfig/aflags/src/main.rs +30 −3 Original line number Diff line number Diff line Loading @@ -52,13 +52,40 @@ impl ToString for ValuePickedFrom { } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] enum FlagValue { Enabled, Disabled, } impl TryFrom<&str> for FlagValue { type Error = anyhow::Error; fn try_from(value: &str) -> std::result::Result<Self, Self::Error> { match value { "true" | "enabled" => Ok(Self::Enabled), "false" | "disabled" => Ok(Self::Disabled), _ => Err(anyhow!("cannot convert string '{}' to FlagValue", value)), } } } impl ToString for FlagValue { fn to_string(&self) -> String { match &self { Self::Enabled => "enabled".into(), Self::Disabled => "disabled".into(), } } } #[derive(Clone)] struct Flag { namespace: String, name: String, package: String, container: String, value: String, value: FlagValue, permission: FlagPermission, value_picked_from: ValuePickedFrom, } Loading Loading @@ -126,7 +153,7 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { let full_name = flag.qualified_name(); let p0 = info.longest_flag_col + 1; let val = &flag.value; let val = flag.value.to_string(); let p1 = info.longest_val_col + 1; let value_picked_from = flag.value_picked_from.to_string(); Loading Loading @@ -161,7 +188,7 @@ fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; 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.len()).max().unwrap_or(0), longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0), longest_value_picked_from_col: flags .iter() .map(|f| f.value_picked_from.to_string().len()) Loading Loading
tools/aconfig/aflags/src/device_config_source.rs +16 −15 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ use crate::{Flag, FlagPermission, FlagSource, ValuePickedFrom}; use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom}; use aconfig_protos::ProtoFlagPermission as ProtoPermission; use aconfig_protos::ProtoFlagState as ProtoState; use aconfig_protos::ProtoParsedFlag; Loading @@ -40,10 +40,9 @@ fn convert_parsed_flag(flag: &ProtoParsedFlag) -> Flag { }; let value = match flag.state() { ProtoState::ENABLED => "true", ProtoState::DISABLED => "false", } .to_string(); ProtoState::ENABLED => FlagValue::Enabled, ProtoState::DISABLED => FlagValue::Disabled, }; let permission = match flag.permission() { ProtoPermission::READ_ONLY => FlagPermission::ReadOnly, Loading Loading @@ -86,14 +85,16 @@ fn read_pb_files() -> Result<Vec<Flag>> { Ok(flags.values().cloned().collect()) } fn parse_device_config(raw: &str) -> Result<HashMap<String, String>> { fn parse_device_config(raw: &str) -> Result<HashMap<String, FlagValue>> { let mut flags = HashMap::new(); let regex = Regex::new(r"(?m)^([[[:alnum:]]_]+/[[[:alnum:]]_\.]+)=(true|false)$")?; for capture in regex.captures_iter(raw) { let key = capture.get(1).ok_or(anyhow!("invalid device_config output"))?.as_str().to_string(); let value = capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str(); flags.insert(key, value.to_string()); let value = FlagValue::try_from( capture.get(2).ok_or(anyhow!("invalid device_config output"))?.as_str(), )?; flags.insert(key, value); } Ok(flags) } Loading @@ -112,24 +113,24 @@ fn read_device_config_output(command: &[&str]) -> Result<String> { Ok(str::from_utf8(&output.stdout)?.to_string()) } fn read_device_config_flags() -> Result<HashMap<String, String>> { fn read_device_config_flags() -> Result<HashMap<String, FlagValue>> { let list_output = read_device_config_output(&["list"])?; parse_device_config(&list_output) } fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, String>) -> Vec<Flag> { fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, FlagValue>) -> Vec<Flag> { pb_flags .iter() .map(|f| { dc_flags .get(&format!("{}/{}.{}", f.namespace, f.package, f.name)) .map(|value| { if value.eq(&f.value) { if *value == f.value { Flag { value_picked_from: ValuePickedFrom::Default, ..f.clone() } } else { Flag { value_picked_from: ValuePickedFrom::Server, value: value.to_string(), value: *value, ..f.clone() } } Loading Loading @@ -167,9 +168,9 @@ namespace_two/android.flag_one=true namespace_two/android.flag_two=nonsense "#; let expected = HashMap::from([ ("namespace_one/com.foo.bar.flag_one".to_string(), "true".to_string()), ("namespace_one/com.foo.bar.flag_two".to_string(), "false".to_string()), ("namespace_two/android.flag_one".to_string(), "true".to_string()), ("namespace_one/com.foo.bar.flag_one".to_string(), FlagValue::Enabled), ("namespace_one/com.foo.bar.flag_two".to_string(), FlagValue::Disabled), ("namespace_two/android.flag_one".to_string(), FlagValue::Enabled), ]); let actual = parse_device_config(input).unwrap(); assert_eq!(expected, actual); Loading
tools/aconfig/aflags/src/main.rs +30 −3 Original line number Diff line number Diff line Loading @@ -52,13 +52,40 @@ impl ToString for ValuePickedFrom { } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] enum FlagValue { Enabled, Disabled, } impl TryFrom<&str> for FlagValue { type Error = anyhow::Error; fn try_from(value: &str) -> std::result::Result<Self, Self::Error> { match value { "true" | "enabled" => Ok(Self::Enabled), "false" | "disabled" => Ok(Self::Disabled), _ => Err(anyhow!("cannot convert string '{}' to FlagValue", value)), } } } impl ToString for FlagValue { fn to_string(&self) -> String { match &self { Self::Enabled => "enabled".into(), Self::Disabled => "disabled".into(), } } } #[derive(Clone)] struct Flag { namespace: String, name: String, package: String, container: String, value: String, value: FlagValue, permission: FlagPermission, value_picked_from: ValuePickedFrom, } Loading Loading @@ -126,7 +153,7 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { let full_name = flag.qualified_name(); let p0 = info.longest_flag_col + 1; let val = &flag.value; let val = flag.value.to_string(); let p1 = info.longest_val_col + 1; let value_picked_from = flag.value_picked_from.to_string(); Loading Loading @@ -161,7 +188,7 @@ fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; 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.len()).max().unwrap_or(0), longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0), longest_value_picked_from_col: flags .iter() .map(|f| f.value_picked_from.to_string().len()) Loading