Loading tools/aconfig/aflags/src/aconfig_storage_source.rs +104 −22 Original line number Diff line number Diff line use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom}; use anyhow::{anyhow, Result}; use std::collections::HashMap; use std::fs::File; use std::io::Read; pub struct AconfigStorageSource {} use aconfig_storage_file::protos::ProtoStorageFileInfo; use aconfig_storage_file::protos::ProtoStorageFiles; use aconfig_storage_file::FlagValueAndInfoSummary; static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb"; static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/storage_records.pb"; fn read_default_values(file_info: ProtoStorageFileInfo) -> Result<HashMap<String, FlagValue>> { let package_map = file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?; let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?; let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?; let mut result = HashMap::new(); for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { let value = FlagValue::try_from(listed_flag.flag_value.as_str())?; result.insert(listed_flag.package_name + &listed_flag.flag_name, value); } Ok(result) } fn read_next_boot_values( listed_flags: &[FlagValueAndInfoSummary], ) -> Result<HashMap<String, FlagValue>> { let mut result = HashMap::new(); for flag in listed_flags { result.insert( flag.package_name.clone() + &flag.flag_name, FlagValue::try_from(flag.flag_value.as_str())?, ); } Ok(result) } fn reconcile( default_values: HashMap<String, FlagValue>, next_boot_values: HashMap<String, FlagValue>, flags_current_boot: &[FlagValueAndInfoSummary], container: &str, ) -> Result<Vec<Flag>> { let mut result = Vec::new(); for listed_flag in flags_current_boot { let default_value = default_values .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name)) .copied(); let name = listed_flag.flag_name.clone(); let package = listed_flag.package_name.clone(); let value = FlagValue::try_from(listed_flag.flag_value.as_str())?; let container = container.to_string(); let staged_value = next_boot_values .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name)) .filter(|&v| value != *v) .copied(); let permission = if listed_flag.is_readwrite { FlagPermission::ReadWrite } else { FlagPermission::ReadOnly }; let value_picked_from = if Some(value) == default_value { ValuePickedFrom::Default } else { ValuePickedFrom::Server }; result.push(Flag { name, package, value, container, staged_value, permission, value_picked_from, // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. namespace: "-".to_string(), }); } Ok(result) } impl FlagSource for AconfigStorageSource { fn list_flags() -> Result<Vec<Flag>> { Loading @@ -20,30 +97,35 @@ impl FlagSource for AconfigStorageSource { let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?; for file_info in storage_file_info.files { let package_map = file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?; let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?; let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?; let default_values = read_default_values(file_info.clone())?; let container = file_info.container.ok_or(anyhow!("storage file is missing container"))?; let package_map = format!("/metadata/aconfig/maps/{container}.package.map"); let flag_map = format!("/metadata/aconfig/maps/{container}.flag.map"); let flag_info = format!("/metadata/aconfig/boot/{container}.info"); for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { result.push(Flag { name: listed_flag.flag_name, package: listed_flag.package_name, value: FlagValue::try_from(listed_flag.flag_value.as_str())?, container: container.to_string(), let flag_val_current_boot = format!("/metadata/aconfig/boot/{container}.val"); let flag_val_next_boot = format!("/metadata/aconfig/flags/{container}.val"); // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. namespace: "-".to_string(), let flags_next_boot = aconfig_storage_file::list_flags_with_info( &package_map, &flag_map, &flag_val_next_boot, &flag_info, )?; let flags_current_boot = aconfig_storage_file::list_flags_with_info( &package_map, &flag_map, &flag_val_current_boot, &flag_info, )?; // TODO(b/324436145): Populate with real values once API is available. staged_value: None, permission: FlagPermission::ReadOnly, value_picked_from: ValuePickedFrom::Default, }); } let next_boot_values = read_next_boot_values(&flags_next_boot)?; let processed_flags = reconcile(default_values, next_boot_values, &flags_current_boot, &container)?; result.extend(processed_flags); } Ok(result) Loading tools/aconfig/aflags/src/main.rs +3 −1 Original line number Diff line number Diff line Loading @@ -286,7 +286,9 @@ fn main() -> Result<()> { let cli = Cli::parse(); let output = match cli.command { Command::List { use_new_storage: true, container } => { list(FlagSourceType::AconfigStorage, container).map(Some) list(FlagSourceType::AconfigStorage, container) .map_err(|_| anyhow!("storage may not be enabled")) .map(Some) } Command::List { use_new_storage: false, container } => { list(FlagSourceType::DeviceConfig, container).map(Some) Loading Loading
tools/aconfig/aflags/src/aconfig_storage_source.rs +104 −22 Original line number Diff line number Diff line use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom}; use anyhow::{anyhow, Result}; use std::collections::HashMap; use std::fs::File; use std::io::Read; pub struct AconfigStorageSource {} use aconfig_storage_file::protos::ProtoStorageFileInfo; use aconfig_storage_file::protos::ProtoStorageFiles; use aconfig_storage_file::FlagValueAndInfoSummary; static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb"; static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/storage_records.pb"; fn read_default_values(file_info: ProtoStorageFileInfo) -> Result<HashMap<String, FlagValue>> { let package_map = file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?; let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?; let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?; let mut result = HashMap::new(); for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { let value = FlagValue::try_from(listed_flag.flag_value.as_str())?; result.insert(listed_flag.package_name + &listed_flag.flag_name, value); } Ok(result) } fn read_next_boot_values( listed_flags: &[FlagValueAndInfoSummary], ) -> Result<HashMap<String, FlagValue>> { let mut result = HashMap::new(); for flag in listed_flags { result.insert( flag.package_name.clone() + &flag.flag_name, FlagValue::try_from(flag.flag_value.as_str())?, ); } Ok(result) } fn reconcile( default_values: HashMap<String, FlagValue>, next_boot_values: HashMap<String, FlagValue>, flags_current_boot: &[FlagValueAndInfoSummary], container: &str, ) -> Result<Vec<Flag>> { let mut result = Vec::new(); for listed_flag in flags_current_boot { let default_value = default_values .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name)) .copied(); let name = listed_flag.flag_name.clone(); let package = listed_flag.package_name.clone(); let value = FlagValue::try_from(listed_flag.flag_value.as_str())?; let container = container.to_string(); let staged_value = next_boot_values .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name)) .filter(|&v| value != *v) .copied(); let permission = if listed_flag.is_readwrite { FlagPermission::ReadWrite } else { FlagPermission::ReadOnly }; let value_picked_from = if Some(value) == default_value { ValuePickedFrom::Default } else { ValuePickedFrom::Server }; result.push(Flag { name, package, value, container, staged_value, permission, value_picked_from, // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. namespace: "-".to_string(), }); } Ok(result) } impl FlagSource for AconfigStorageSource { fn list_flags() -> Result<Vec<Flag>> { Loading @@ -20,30 +97,35 @@ impl FlagSource for AconfigStorageSource { let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?; for file_info in storage_file_info.files { let package_map = file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?; let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?; let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?; let default_values = read_default_values(file_info.clone())?; let container = file_info.container.ok_or(anyhow!("storage file is missing container"))?; let package_map = format!("/metadata/aconfig/maps/{container}.package.map"); let flag_map = format!("/metadata/aconfig/maps/{container}.flag.map"); let flag_info = format!("/metadata/aconfig/boot/{container}.info"); for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { result.push(Flag { name: listed_flag.flag_name, package: listed_flag.package_name, value: FlagValue::try_from(listed_flag.flag_value.as_str())?, container: container.to_string(), let flag_val_current_boot = format!("/metadata/aconfig/boot/{container}.val"); let flag_val_next_boot = format!("/metadata/aconfig/flags/{container}.val"); // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. namespace: "-".to_string(), let flags_next_boot = aconfig_storage_file::list_flags_with_info( &package_map, &flag_map, &flag_val_next_boot, &flag_info, )?; let flags_current_boot = aconfig_storage_file::list_flags_with_info( &package_map, &flag_map, &flag_val_current_boot, &flag_info, )?; // TODO(b/324436145): Populate with real values once API is available. staged_value: None, permission: FlagPermission::ReadOnly, value_picked_from: ValuePickedFrom::Default, }); } let next_boot_values = read_next_boot_values(&flags_next_boot)?; let processed_flags = reconcile(default_values, next_boot_values, &flags_current_boot, &container)?; result.extend(processed_flags); } Ok(result) Loading
tools/aconfig/aflags/src/main.rs +3 −1 Original line number Diff line number Diff line Loading @@ -286,7 +286,9 @@ fn main() -> Result<()> { let cli = Cli::parse(); let output = match cli.command { Command::List { use_new_storage: true, container } => { list(FlagSourceType::AconfigStorage, container).map(Some) list(FlagSourceType::AconfigStorage, container) .map_err(|_| anyhow!("storage may not be enabled")) .map(Some) } Command::List { use_new_storage: false, container } => { list(FlagSourceType::DeviceConfig, container).map(Some) Loading