Merge "Don't show staged value if flag is RO" into main
diff --git a/ci/build_metadata b/ci/build_metadata
index 8136702..a8eb65d 100755
--- a/ci/build_metadata
+++ b/ci/build_metadata
@@ -21,5 +21,5 @@
export TARGET_BUILD_VARIANT=eng
build/soong/bin/m dist \
- code_metadata
+ all_teams
diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp
index 40b4464..e875c7b 100644
--- a/tools/aconfig/aconfig_storage_file/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/Android.bp
@@ -14,6 +14,7 @@
"libclap",
"libcxx",
"libaconfig_storage_protos",
+ "libserde",
],
}
@@ -36,7 +37,10 @@
name: "aconfig-storage",
defaults: ["aconfig_storage_file.defaults"],
srcs: ["src/main.rs"],
- rustlibs: ["libaconfig_storage_file"],
+ rustlibs: [
+ "libaconfig_storage_file",
+ "libserde_json",
+ ],
}
rust_test_host {
diff --git a/tools/aconfig/aconfig_storage_file/Cargo.toml b/tools/aconfig/aconfig_storage_file/Cargo.toml
index 192dfad..a405578 100644
--- a/tools/aconfig/aconfig_storage_file/Cargo.toml
+++ b/tools/aconfig/aconfig_storage_file/Cargo.toml
@@ -14,6 +14,8 @@
thiserror = "1.0.56"
clap = { version = "4.1.8", features = ["derive"] }
cxx = "1.0"
+serde = { version = "1.0.152", features = ["derive"] }
+serde_json = "1.0.93"
[[bin]]
name = "aconfig-storage"
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_info.rs b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
index beac38d..f090396 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_info.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
@@ -20,10 +20,11 @@
use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
use crate::{AconfigStorageError, StorageFileType};
use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
use std::fmt;
/// Flag info header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagInfoHeader {
pub version: u32,
pub container: String,
@@ -89,7 +90,7 @@
}
/// bit field for flag info
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FlagInfoBit {
HasServerOverride = 1 << 0,
IsReadWrite = 1 << 1,
@@ -97,7 +98,7 @@
}
/// Flag info node struct
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Clone, Serialize, Deserialize)]
pub struct FlagInfoNode {
pub attributes: u8,
}
@@ -138,7 +139,7 @@
}
/// Flag info list struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagInfoList {
pub header: FlagInfoHeader,
pub nodes: Vec<FlagInfoNode>,
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index 660edac..0588fe5 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -23,10 +23,11 @@
};
use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
use std::fmt;
/// Flag table header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagTableHeader {
pub version: u32,
pub container: String,
@@ -95,7 +96,7 @@
}
/// Flag table node struct
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Clone, Serialize, Deserialize)]
pub struct FlagTableNode {
pub package_id: u32,
pub flag_name: String,
@@ -154,7 +155,7 @@
}
}
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagTable {
pub header: FlagTableHeader,
pub buckets: Vec<Option<u32>>,
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index 506924b..b64c10e 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -20,10 +20,11 @@
use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
use crate::{AconfigStorageError, StorageFileType};
use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
use std::fmt;
/// Flag value header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagValueHeader {
pub version: u32,
pub container: String,
@@ -89,7 +90,7 @@
}
/// Flag value list struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct FlagValueList {
pub header: FlagValueHeader,
pub booleans: Vec<bool>,
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index b6367ff..cf52bc0 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -41,6 +41,7 @@
pub mod test_utils;
use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fs::File;
use std::hash::Hasher;
@@ -107,7 +108,7 @@
/// Flag type enum as stored by storage file
/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY. THE MAX IS U16.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum StoredFlagType {
ReadWriteBoolean = 0,
ReadOnlyBoolean = 1,
diff --git a/tools/aconfig/aconfig_storage_file/src/main.rs b/tools/aconfig/aconfig_storage_file/src/main.rs
index 8b9e38d..a9cfd19 100644
--- a/tools/aconfig/aconfig_storage_file/src/main.rs
+++ b/tools/aconfig/aconfig_storage_file/src/main.rs
@@ -20,9 +20,29 @@
list_flags, list_flags_with_info, read_file_to_bytes, AconfigStorageError, FlagInfoList,
FlagTable, FlagValueList, PackageTable, StorageFileType,
};
-
use clap::{builder::ArgAction, Arg, Command};
+use serde::Serialize;
+use serde_json;
+use std::fmt;
+use std::fs;
+use std::fs::File;
+use std::io::Write;
+/**
+ * Usage Examples
+ *
+ * Print file:
+ * $ aconfig-storage print --file=path/to/flag.map --type=flag_map
+ *
+ * List flags:
+ * $ aconfig-storage list --flag-map=path/to/flag.map \
+ * --flag-val=path/to/flag.val --package-map=path/to/package.map
+ *
+ * Write binary file for testing:
+ * $ aconfig-storage print --file=path/to/flag.map --type=flag_map --format=json > flag_map.json
+ * $ vim flag_map.json // Manually make updates
+ * $ aconfig-storage write-bytes --input-file=flag_map.json --output-file=path/to/flag.map --type=flag_map
+ */
fn cli() -> Command {
Command::new("aconfig-storage")
.subcommand_required(true)
@@ -34,7 +54,8 @@
.long("type")
.required(true)
.value_parser(|s: &str| StorageFileType::try_from(s)),
- ),
+ )
+ .arg(Arg::new("format").long("format").required(false).action(ArgAction::Set)),
)
.subcommand(
Command::new("list")
@@ -50,41 +71,75 @@
Arg::new("flag-info").long("flag-info").required(false).action(ArgAction::Set),
),
)
+ .subcommand(
+ Command::new("write-bytes")
+ // Where to write the output bytes. Suggest to use the StorageFileType names (e.g. flag.map).
+ .arg(
+ Arg::new("output-file")
+ .long("output-file")
+ .required(true)
+ .action(ArgAction::Set),
+ )
+ // Input file should be json.
+ .arg(
+ Arg::new("input-file").long("input-file").required(true).action(ArgAction::Set),
+ )
+ .arg(
+ Arg::new("type")
+ .long("type")
+ .required(true)
+ .value_parser(|s: &str| StorageFileType::try_from(s)),
+ ),
+ )
}
fn print_storage_file(
file_path: &str,
file_type: &StorageFileType,
+ as_json: bool,
) -> Result<(), AconfigStorageError> {
let bytes = read_file_to_bytes(file_path)?;
match file_type {
StorageFileType::PackageMap => {
let package_table = PackageTable::from_bytes(&bytes)?;
- println!("{:?}", package_table);
+ println!("{}", to_print_format(package_table, as_json));
}
StorageFileType::FlagMap => {
let flag_table = FlagTable::from_bytes(&bytes)?;
- println!("{:?}", flag_table);
+ println!("{}", to_print_format(flag_table, as_json));
}
StorageFileType::FlagVal => {
let flag_value = FlagValueList::from_bytes(&bytes)?;
- println!("{:?}", flag_value);
+ println!("{}", to_print_format(flag_value, as_json));
}
StorageFileType::FlagInfo => {
let flag_info = FlagInfoList::from_bytes(&bytes)?;
- println!("{:?}", flag_info);
+ println!("{}", to_print_format(flag_info, as_json));
}
}
Ok(())
}
+fn to_print_format<T>(file_contents: T, as_json: bool) -> String
+where
+ T: Serialize + fmt::Debug,
+{
+ if as_json {
+ serde_json::to_string(&file_contents).unwrap()
+ } else {
+ format!("{:?}", file_contents)
+ }
+}
+
fn main() -> Result<(), AconfigStorageError> {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("print", sub_matches)) => {
let file_path = sub_matches.get_one::<String>("file").unwrap();
let file_type = sub_matches.get_one::<StorageFileType>("type").unwrap();
- print_storage_file(file_path, file_type)?
+ let format = sub_matches.get_one::<String>("format");
+ let as_json: bool = format == Some(&"json".to_string());
+ print_storage_file(file_path, file_type, as_json)?
}
Some(("list", sub_matches)) => {
let package_map = sub_matches.get_one::<String>("package-map").unwrap();
@@ -96,10 +151,10 @@
let flags = list_flags_with_info(package_map, flag_map, flag_val, info_file)?;
for flag in flags.iter() {
println!(
- "{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}",
- flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
- flag.is_readwrite, flag.has_server_override, flag.has_local_override,
- );
+ "{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}",
+ flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
+ flag.is_readwrite, flag.has_server_override, flag.has_local_override,
+ );
}
}
None => {
@@ -113,6 +168,40 @@
}
}
}
+ // Converts JSON of the file into raw bytes (as is used on-device).
+ // Intended to generate/easily update these files for testing.
+ Some(("write-bytes", sub_matches)) => {
+ let input_file_path = sub_matches.get_one::<String>("input-file").unwrap();
+ let input_json = fs::read_to_string(input_file_path).unwrap();
+
+ let file_type = sub_matches.get_one::<StorageFileType>("type").unwrap();
+ let output_bytes: Vec<u8>;
+ match file_type {
+ StorageFileType::FlagVal => {
+ let list: FlagValueList = serde_json::from_str(&input_json).unwrap();
+ output_bytes = list.into_bytes();
+ }
+ StorageFileType::FlagInfo => {
+ let list: FlagInfoList = serde_json::from_str(&input_json).unwrap();
+ output_bytes = list.into_bytes();
+ }
+ StorageFileType::FlagMap => {
+ let table: FlagTable = serde_json::from_str(&input_json).unwrap();
+ output_bytes = table.into_bytes();
+ }
+ StorageFileType::PackageMap => {
+ let table: PackageTable = serde_json::from_str(&input_json).unwrap();
+ output_bytes = table.into_bytes();
+ }
+ }
+
+ let output_file_path = sub_matches.get_one::<String>("output-file").unwrap();
+ let file = File::create(output_file_path);
+ if file.is_err() {
+ panic!("can't make file");
+ }
+ let _ = file.unwrap().write_all(&output_bytes);
+ }
_ => unreachable!(),
}
Ok(())
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index 007f86e..a5bd9e6 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -20,10 +20,11 @@
use crate::{get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
use crate::{AconfigStorageError, StorageFileType};
use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
use std::fmt;
/// Package table header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct PackageTableHeader {
pub version: u32,
pub container: String,
@@ -92,7 +93,7 @@
}
/// Package table node struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct PackageTableNode {
pub package_name: String,
pub package_id: u32,
@@ -151,7 +152,7 @@
}
/// Package table struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
pub struct PackageTable {
pub header: PackageTableHeader,
pub buckets: Vec<Option<u32>>,