blob: 1487e723a89ac87b14042f9e55c20968d175ecb1 [file] [log] [blame]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +02001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mårten Kongstad30950782023-05-09 13:31:29 +020017use anyhow::{ensure, Context, Result};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020018use clap::ValueEnum;
Mårten Kongstada1029092023-05-08 11:51:59 +020019use protobuf::Message;
Mårten Kongstad76adff22023-05-08 10:57:24 +020020use serde::{Deserialize, Serialize};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020021use std::fmt;
22use std::io::Read;
23
Mårten Kongstad30950782023-05-09 13:31:29 +020024use crate::aconfig::{Namespace, Override};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020025use crate::cache::Cache;
Zhi Doueb744892023-05-10 04:02:33 +000026use crate::codegen_java::{generate_java_code, GeneratedFile};
Mårten Kongstad30950782023-05-09 13:31:29 +020027use crate::protos::ProtoParsedFlags;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020028
Mårten Kongstad76adff22023-05-08 10:57:24 +020029#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020030pub enum Source {
31 #[allow(dead_code)] // only used in unit tests
32 Memory,
33 File(String),
34}
35
36impl fmt::Display for Source {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 match self {
39 Self::Memory => write!(f, "<memory>"),
40 Self::File(path) => write!(f, "{}", path),
41 }
42 }
43}
44
45pub struct Input {
46 pub source: Source,
47 pub reader: Box<dyn Read>,
48}
49
Mårten Kongstad30950782023-05-09 13:31:29 +020050pub fn create_cache(
51 build_id: u32,
52 namespace: &str,
53 aconfigs: Vec<Input>,
54 overrides: Vec<Input>,
55) -> Result<Cache> {
56 let mut cache = Cache::new(build_id, namespace.to_owned());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020057
58 for mut input in aconfigs {
59 let mut contents = String::new();
60 input.reader.read_to_string(&mut contents)?;
Mårten Kongstad30950782023-05-09 13:31:29 +020061 let ns = Namespace::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020062 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020063 ensure!(
64 namespace == ns.namespace,
65 "Failed to parse {}: expected namespace {}, got {}",
66 input.source,
67 namespace,
68 ns.namespace
69 );
70 for flag in ns.flags.into_iter() {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020071 cache.add_flag(input.source.clone(), flag)?;
72 }
73 }
74
75 for mut input in overrides {
76 let mut contents = String::new();
77 input.reader.read_to_string(&mut contents)?;
78 let overrides = Override::try_from_text_proto_list(&contents)
79 .with_context(|| format!("Failed to parse {}", input.source))?;
80 for override_ in overrides {
81 cache.add_override(input.source.clone(), override_)?;
82 }
83 }
84
85 Ok(cache)
86}
87
Zhi Doueb744892023-05-10 04:02:33 +000088pub fn generate_code(cache: &Cache) -> Result<GeneratedFile> {
89 generate_java_code(cache)
90}
91
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020092#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
93pub enum Format {
94 Text,
95 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +020096 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020097}
98
Mårten Kongstada1029092023-05-08 11:51:59 +020099pub fn dump_cache(cache: Cache, format: Format) -> Result<Vec<u8>> {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200100 match format {
101 Format::Text => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200102 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200103 for item in cache.iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200104 lines.push(format!("{}: {:?}\n", item.name, item.state));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200105 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200106 Ok(lines.concat().into())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200107 }
108 Format::Debug => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200109 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200110 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +0200111 lines.push(format!("{:?}\n", item));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200112 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200113 Ok(lines.concat().into())
114 }
115 Format::Protobuf => {
Mårten Kongstad30950782023-05-09 13:31:29 +0200116 let parsed_flags: ProtoParsedFlags = cache.into();
Mårten Kongstada1029092023-05-08 11:51:59 +0200117 let mut output = vec![];
Mårten Kongstad30950782023-05-09 13:31:29 +0200118 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstada1029092023-05-08 11:51:59 +0200119 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200120 }
121 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200127 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200128
Mårten Kongstada1029092023-05-08 11:51:59 +0200129 fn create_test_cache() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200130 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200131 namespace: "ns"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200132 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200133 name: "a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200134 description: "Description of a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200135 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200136 state: ENABLED
137 permission: READ_WRITE
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200138 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200139 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200140 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200141 name: "b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200142 description: "Description of b"
143 value {
144 state: ENABLED
145 permission: READ_ONLY
146 }
147 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200148 "#;
149 let aconfigs = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
150 let o = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200151 flag_override {
152 namespace: "ns"
153 name: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200154 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200155 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200156 }
157 "#;
158 let overrides = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
Mårten Kongstad30950782023-05-09 13:31:29 +0200159 create_cache(1, "ns", aconfigs, overrides).unwrap()
Mårten Kongstada1029092023-05-08 11:51:59 +0200160 }
161
162 #[test]
163 fn test_create_cache() {
164 let cache = create_test_cache(); // calls create_cache
Mårten Kongstad30950782023-05-09 13:31:29 +0200165 let item = cache.iter().find(|&item| item.name == "a").unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200166 assert_eq!(FlagState::Disabled, item.state);
167 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200168 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200169
170 #[test]
171 fn test_dump_text_format() {
172 let cache = create_test_cache();
173 let bytes = dump_cache(cache, Format::Text).unwrap();
174 let text = std::str::from_utf8(&bytes).unwrap();
175 assert!(text.contains("a: Disabled"));
176 }
177
178 #[test]
179 fn test_dump_protobuf_format() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200180 use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
Mårten Kongstada1029092023-05-08 11:51:59 +0200181 use protobuf::Message;
182
183 let cache = create_test_cache();
184 let bytes = dump_cache(cache, Format::Protobuf).unwrap();
Mårten Kongstad30950782023-05-09 13:31:29 +0200185 let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200186
187 assert_eq!(
188 vec!["a".to_string(), "b".to_string()],
Mårten Kongstad30950782023-05-09 13:31:29 +0200189 actual.parsed_flag.iter().map(|item| item.name.clone().unwrap()).collect::<Vec<_>>()
Mårten Kongstada1029092023-05-08 11:51:59 +0200190 );
Mårten Kongstad30950782023-05-09 13:31:29 +0200191
192 let item =
193 actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
194 assert_eq!(item.namespace(), "ns");
195 assert_eq!(item.name(), "b");
196 assert_eq!(item.description(), "Description of b");
197 assert_eq!(item.state(), ProtoFlagState::ENABLED);
198 assert_eq!(item.permission(), ProtoFlagPermission::READ_ONLY);
199 let mut tp = ProtoTracepoint::new();
200 tp.set_source("<memory>".to_string());
201 tp.set_state(ProtoFlagState::ENABLED);
202 tp.set_permission(ProtoFlagPermission::READ_ONLY);
203 assert_eq!(item.trace, vec![tp]);
Mårten Kongstada1029092023-05-08 11:51:59 +0200204 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200205}