aconfig: add create-device-config-defaults command
DeviceConfig is the backend for READ_WRITE flags. Add a new command "create-device-config-defaults" to create a file that DeviceConfig will read to pre-populate its data store on first init. This will be used to quickly switch flag values during CI tests: rebuilding and reflashing a device would have the same effect, but would be costlier. This feature is not expected to be used outside CI tests. Note: because DeviceConfig only works with READ_WRITE flags, the generated file excludes READ_ONLY flags. Bug: 285468565 Test: atest aconfig.test Change-Id: I4caff1a10647b8da0ce4e3615678993a957a92dd
This commit is contained in:
@@ -22,8 +22,8 @@ use std::fmt;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::aconfig::{FlagDeclarations, FlagValue};
|
||||
use crate::cache::{Cache, CacheBuilder};
|
||||
use crate::aconfig::{FlagDeclarations, FlagState, FlagValue, Permission};
|
||||
use crate::cache::{Cache, CacheBuilder, Item};
|
||||
use crate::codegen_cpp::generate_cpp_code;
|
||||
use crate::codegen_java::generate_java_code;
|
||||
use crate::codegen_rust::generate_rust_code;
|
||||
@@ -105,6 +105,24 @@ pub fn create_rust_lib(cache: Cache) -> Result<OutputFile> {
|
||||
generate_rust_code(&cache)
|
||||
}
|
||||
|
||||
pub fn create_device_config_defaults(caches: Vec<Cache>) -> Result<Vec<u8>> {
|
||||
let mut output = Vec::new();
|
||||
for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
|
||||
{
|
||||
let line = format!(
|
||||
"{}/{}:{}\n",
|
||||
item.namespace,
|
||||
item.name,
|
||||
match item.state {
|
||||
FlagState::Enabled => "enabled",
|
||||
FlagState::Disabled => "disabled",
|
||||
}
|
||||
);
|
||||
output.extend_from_slice(line.as_bytes());
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
|
||||
pub enum DumpFormat {
|
||||
Text,
|
||||
@@ -112,29 +130,26 @@ pub enum DumpFormat {
|
||||
Protobuf,
|
||||
}
|
||||
|
||||
pub fn dump_cache(mut caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
|
||||
pub fn dump_cache(caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
|
||||
let mut output = Vec::new();
|
||||
caches.sort_by_cached_key(|cache| cache.namespace().to_string());
|
||||
for cache in caches.into_iter() {
|
||||
match format {
|
||||
DumpFormat::Text => {
|
||||
let mut lines = vec![];
|
||||
for item in cache.iter() {
|
||||
lines.push(format!(
|
||||
"{}/{}: {:?} {:?}\n",
|
||||
item.namespace, item.name, item.state, item.permission
|
||||
));
|
||||
}
|
||||
output.append(&mut lines.concat().into());
|
||||
match format {
|
||||
DumpFormat::Text => {
|
||||
for item in sort_and_iter_items(caches) {
|
||||
let line = format!(
|
||||
"{}/{}: {:?} {:?}\n",
|
||||
item.namespace, item.name, item.state, item.permission
|
||||
);
|
||||
output.extend_from_slice(line.as_bytes());
|
||||
}
|
||||
DumpFormat::Debug => {
|
||||
let mut lines = vec![];
|
||||
for item in cache.iter() {
|
||||
lines.push(format!("{:#?}\n", item));
|
||||
}
|
||||
output.append(&mut lines.concat().into());
|
||||
}
|
||||
DumpFormat::Debug => {
|
||||
for item in sort_and_iter_items(caches) {
|
||||
let line = format!("{:#?}\n", item);
|
||||
output.extend_from_slice(line.as_bytes());
|
||||
}
|
||||
DumpFormat::Protobuf => {
|
||||
}
|
||||
DumpFormat::Protobuf => {
|
||||
for cache in sort_and_iter_caches(caches) {
|
||||
let parsed_flags: ProtoParsedFlags = cache.into();
|
||||
parsed_flags.write_to_vec(&mut output)?;
|
||||
}
|
||||
@@ -143,6 +158,15 @@ pub fn dump_cache(mut caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>>
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn sort_and_iter_items(caches: Vec<Cache>) -> impl Iterator<Item = Item> {
|
||||
sort_and_iter_caches(caches).flat_map(|cache| cache.into_iter())
|
||||
}
|
||||
|
||||
fn sort_and_iter_caches(mut caches: Vec<Cache>) -> impl Iterator<Item = Cache> {
|
||||
caches.sort_by_cached_key(|cache| cache.namespace().to_string());
|
||||
caches.into_iter()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -202,6 +226,14 @@ mod tests {
|
||||
assert_eq!(Permission::ReadOnly, item.permission);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_device_config_defaults() {
|
||||
let caches = vec![crate::test::create_cache()];
|
||||
let bytes = create_device_config_defaults(caches).unwrap();
|
||||
let text = std::str::from_utf8(&bytes).unwrap();
|
||||
assert_eq!("test/disabled_rw:disabled\ntest/enabled_rw:enabled\n", text);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dump_text_format() {
|
||||
let caches = vec![create_test_cache_ns1()];
|
||||
|
||||
@@ -64,6 +64,11 @@ fn cli() -> Command {
|
||||
.arg(Arg::new("cache").long("cache").required(true))
|
||||
.arg(Arg::new("out").long("out").required(true)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("create-device-config-defaults")
|
||||
.arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
|
||||
.arg(Arg::new("out").long("out").default_value("-")),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("dump")
|
||||
.arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
|
||||
@@ -111,6 +116,15 @@ fn write_output_file_realtive_to_dir(root: &Path, output_file: &OutputFile) -> R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_output_to_file_or_stdout(path: &str, data: &[u8]) -> Result<()> {
|
||||
if path == "-" {
|
||||
io::stdout().write_all(data)?;
|
||||
} else {
|
||||
fs::File::create(path)?.write_all(data)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let matches = cli().get_matches();
|
||||
match matches.subcommand() {
|
||||
@@ -147,6 +161,17 @@ fn main() -> Result<()> {
|
||||
let generated_file = commands::create_rust_lib(cache)?;
|
||||
write_output_file_realtive_to_dir(&dir, &generated_file)?;
|
||||
}
|
||||
Some(("create-device-config-defaults", sub_matches)) => {
|
||||
let mut caches = Vec::new();
|
||||
for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
|
||||
let file = fs::File::open(path)?;
|
||||
let cache = Cache::read_from_reader(file)?;
|
||||
caches.push(cache);
|
||||
}
|
||||
let output = commands::create_device_config_defaults(caches)?;
|
||||
let path = get_required_arg::<String>(sub_matches, "out")?;
|
||||
write_output_to_file_or_stdout(path, &output)?;
|
||||
}
|
||||
Some(("dump", sub_matches)) => {
|
||||
let mut caches = Vec::new();
|
||||
for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
|
||||
@@ -157,12 +182,7 @@ fn main() -> Result<()> {
|
||||
let format = get_required_arg::<DumpFormat>(sub_matches, "format")?;
|
||||
let output = commands::dump_cache(caches, *format)?;
|
||||
let path = get_required_arg::<String>(sub_matches, "out")?;
|
||||
let mut file: Box<dyn Write> = if *path == "-" {
|
||||
Box::new(io::stdout())
|
||||
} else {
|
||||
Box::new(fs::File::create(path)?)
|
||||
};
|
||||
file.write_all(&output)?;
|
||||
write_output_to_file_or_stdout(path, &output)?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user