diff --git a/tools/aconfig/src/cache.rs b/tools/aconfig/src/cache.rs index 44ad3dd005..972ba41d5d 100644 --- a/tools/aconfig/src/cache.rs +++ b/tools/aconfig/src/cache.rs @@ -179,7 +179,6 @@ impl CacheBuilder { #[cfg(test)] mod tests { use super::*; - use crate::aconfig::{FlagState, Permission}; #[test] fn test_add_flag_declaration() { diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs index fe4231b647..a48e464e6b 100644 --- a/tools/aconfig/src/codegen_rust.rs +++ b/tools/aconfig/src/codegen_rust.rs @@ -79,28 +79,10 @@ fn create_template_parsed_flag(namespace: &str, item: &Item) -> TemplateParsedFl #[cfg(test)] mod tests { use super::*; - use crate::commands::{create_cache, Input, Source}; #[test] fn test_generate_rust_code() { - let cache = create_cache( - "test", - vec![Input { - source: Source::File("testdata/test.aconfig".to_string()), - reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()), - }], - vec![ - Input { - source: Source::File("testdata/first.values".to_string()), - reader: Box::new(include_bytes!("../testdata/first.values").as_slice()), - }, - Input { - source: Source::File("testdata/test.aconfig".to_string()), - reader: Box::new(include_bytes!("../testdata/second.values").as_slice()), - }, - ], - ) - .unwrap(); + let cache = crate::test::create_cache(); let generated = generate_rust_code(&cache).unwrap(); assert_eq!("src/lib.rs", format!("{}", generated.path.display())); let expected = r#" diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs index cce1d7f43c..3ae72c67fa 100644 --- a/tools/aconfig/src/commands.rs +++ b/tools/aconfig/src/commands.rs @@ -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; @@ -93,16 +93,52 @@ pub fn create_cache( Ok(builder.build()) } -pub fn create_java_lib(cache: &Cache) -> Result { - generate_java_code(cache) +pub fn create_java_lib(cache: Cache) -> Result { + generate_java_code(&cache) } -pub fn create_cpp_lib(cache: &Cache) -> Result { - generate_cpp_code(cache) +pub fn create_cpp_lib(cache: Cache) -> Result { + generate_cpp_code(&cache) } -pub fn create_rust_lib(cache: &Cache) -> Result { - generate_rust_code(cache) +pub fn create_rust_lib(cache: Cache) -> Result { + generate_rust_code(&cache) +} + +pub fn create_device_config_defaults(caches: Vec) -> Result> { + 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) +} + +pub fn create_device_config_sysprops(caches: Vec) -> Result> { + let mut output = Vec::new(); + for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite) + { + let line = format!( + "persist.device_config.{}.{}={}\n", + item.namespace, + item.name, + match item.state { + FlagState::Enabled => "true", + FlagState::Disabled => "false", + } + ); + output.extend_from_slice(line.as_bytes()); + } + Ok(output) } #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] @@ -112,29 +148,26 @@ pub enum DumpFormat { Protobuf, } -pub fn dump_cache(mut caches: Vec, format: DumpFormat) -> Result> { +pub fn dump_cache(caches: Vec, format: DumpFormat) -> Result> { 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 +176,15 @@ pub fn dump_cache(mut caches: Vec, format: DumpFormat) -> Result> Ok(output) } +fn sort_and_iter_items(caches: Vec) -> impl Iterator { + sort_and_iter_caches(caches).flat_map(|cache| cache.into_iter()) +} + +fn sort_and_iter_caches(mut caches: Vec) -> impl Iterator { + caches.sort_by_cached_key(|cache| cache.namespace().to_string()); + caches.into_iter() +} + #[cfg(test)] mod tests { use super::*; @@ -202,6 +244,22 @@ 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_create_device_config_sysprops() { + let caches = vec![crate::test::create_cache()]; + let bytes = create_device_config_sysprops(caches).unwrap(); + let text = std::str::from_utf8(&bytes).unwrap(); + assert_eq!("persist.device_config.test.disabled_rw=false\npersist.device_config.test.enabled_rw=true\n", text); + } + #[test] fn test_dump_text_format() { let caches = vec![create_test_cache_ns1()]; diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs index 1d2ec95fec..dab01918f0 100644 --- a/tools/aconfig/src/main.rs +++ b/tools/aconfig/src/main.rs @@ -33,6 +33,9 @@ mod codegen_rust; mod commands; mod protos; +#[cfg(test)] +mod test; + use crate::cache::Cache; use commands::{DumpFormat, Input, OutputFile, Source}; @@ -61,6 +64,16 @@ 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("create-device-config-sysprops") + .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)) @@ -108,6 +121,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() { @@ -125,7 +147,7 @@ fn main() -> Result<()> { let file = fs::File::open(path)?; let cache = Cache::read_from_reader(file)?; let dir = PathBuf::from(get_required_arg::(sub_matches, "out")?); - let generated_file = commands::create_java_lib(&cache)?; + let generated_file = commands::create_java_lib(cache)?; write_output_file_realtive_to_dir(&dir, &generated_file)?; } Some(("create-cpp-lib", sub_matches)) => { @@ -133,7 +155,7 @@ fn main() -> Result<()> { let file = fs::File::open(path)?; let cache = Cache::read_from_reader(file)?; let dir = PathBuf::from(get_required_arg::(sub_matches, "out")?); - let generated_file = commands::create_cpp_lib(&cache)?; + let generated_file = commands::create_cpp_lib(cache)?; write_output_file_realtive_to_dir(&dir, &generated_file)?; } Some(("create-rust-lib", sub_matches)) => { @@ -141,9 +163,31 @@ fn main() -> Result<()> { let file = fs::File::open(path)?; let cache = Cache::read_from_reader(file)?; let dir = PathBuf::from(get_required_arg::(sub_matches, "out")?); - let generated_file = commands::create_rust_lib(&cache)?; + 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::("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::(sub_matches, "out")?; + write_output_to_file_or_stdout(path, &output)?; + } + Some(("create-device-config-sysprops", sub_matches)) => { + let mut caches = Vec::new(); + for path in sub_matches.get_many::("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_sysprops(caches)?; + let path = get_required_arg::(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::("cache").unwrap_or_default() { @@ -154,12 +198,7 @@ fn main() -> Result<()> { let format = get_required_arg::(sub_matches, "format")?; let output = commands::dump_cache(caches, *format)?; let path = get_required_arg::(sub_matches, "out")?; - let mut file: Box = 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!(), } diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs new file mode 100644 index 0000000000..621381afb6 --- /dev/null +++ b/tools/aconfig/src/test.rs @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#[cfg(test)] +pub mod test_utils { + use crate::cache::Cache; + use crate::commands::{Input, Source}; + + pub fn create_cache() -> Cache { + crate::commands::create_cache( + "test", + vec![Input { + source: Source::File("testdata/test.aconfig".to_string()), + reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()), + }], + vec![ + Input { + source: Source::File("testdata/first.values".to_string()), + reader: Box::new(include_bytes!("../testdata/first.values").as_slice()), + }, + Input { + source: Source::File("testdata/test.aconfig".to_string()), + reader: Box::new(include_bytes!("../testdata/second.values").as_slice()), + }, + ], + ) + .unwrap() + } +} + +#[cfg(test)] +pub use test_utils::*;