blob: 645d39540db3af30be75643c9dc36cbcacfa016b [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
17use anyhow::{Context, Result};
18use 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
24use crate::aconfig::{Flag, Override};
25use crate::cache::Cache;
Mårten Kongstada1029092023-05-08 11:51:59 +020026use crate::protos::ProtoDump;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020027
Mårten Kongstad76adff22023-05-08 10:57:24 +020028#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020029pub enum Source {
30 #[allow(dead_code)] // only used in unit tests
31 Memory,
32 File(String),
33}
34
35impl fmt::Display for Source {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self {
38 Self::Memory => write!(f, "<memory>"),
39 Self::File(path) => write!(f, "{}", path),
40 }
41 }
42}
43
44pub struct Input {
45 pub source: Source,
46 pub reader: Box<dyn Read>,
47}
48
Mårten Kongstad09c28d12023-05-04 13:29:26 +020049pub fn create_cache(build_id: u32, aconfigs: Vec<Input>, overrides: Vec<Input>) -> Result<Cache> {
50 let mut cache = Cache::new(build_id);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020051
52 for mut input in aconfigs {
53 let mut contents = String::new();
54 input.reader.read_to_string(&mut contents)?;
55 let flags = Flag::try_from_text_proto_list(&contents)
56 .with_context(|| format!("Failed to parse {}", input.source))?;
57 for flag in flags {
58 cache.add_flag(input.source.clone(), flag)?;
59 }
60 }
61
62 for mut input in overrides {
63 let mut contents = String::new();
64 input.reader.read_to_string(&mut contents)?;
65 let overrides = Override::try_from_text_proto_list(&contents)
66 .with_context(|| format!("Failed to parse {}", input.source))?;
67 for override_ in overrides {
68 cache.add_override(input.source.clone(), override_)?;
69 }
70 }
71
72 Ok(cache)
73}
74
75#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
76pub enum Format {
77 Text,
78 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +020079 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020080}
81
Mårten Kongstada1029092023-05-08 11:51:59 +020082pub fn dump_cache(cache: Cache, format: Format) -> Result<Vec<u8>> {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020083 match format {
84 Format::Text => {
Mårten Kongstada1029092023-05-08 11:51:59 +020085 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020086 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +020087 lines.push(format!("{}: {:?}\n", item.id, item.state));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020088 }
Mårten Kongstada1029092023-05-08 11:51:59 +020089 Ok(lines.concat().into())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020090 }
91 Format::Debug => {
Mårten Kongstada1029092023-05-08 11:51:59 +020092 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020093 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +020094 lines.push(format!("{:?}\n", item));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020095 }
Mårten Kongstada1029092023-05-08 11:51:59 +020096 Ok(lines.concat().into())
97 }
98 Format::Protobuf => {
99 let dump: ProtoDump = cache.into();
100 let mut output = vec![];
101 dump.write_to_vec(&mut output)?;
102 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200103 }
104 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200110 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200111
Mårten Kongstada1029092023-05-08 11:51:59 +0200112 fn create_test_cache() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200113 let s = r#"
114 flag {
115 id: "a"
116 description: "Description of a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200117 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200118 state: ENABLED
119 permission: READ_WRITE
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200120 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200121 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200122 flag {
123 id: "b"
124 description: "Description of b"
125 value {
126 state: ENABLED
127 permission: READ_ONLY
128 }
129 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200130 "#;
131 let aconfigs = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
132 let o = r#"
133 override {
134 id: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200135 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200136 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200137 }
138 "#;
139 let overrides = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
Mårten Kongstada1029092023-05-08 11:51:59 +0200140 create_cache(1, aconfigs, overrides).unwrap()
141 }
142
143 #[test]
144 fn test_create_cache() {
145 let cache = create_test_cache(); // calls create_cache
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200146 let item = cache.iter().find(|&item| item.id == "a").unwrap();
147 assert_eq!(FlagState::Disabled, item.state);
148 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200149 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200150
151 #[test]
152 fn test_dump_text_format() {
153 let cache = create_test_cache();
154 let bytes = dump_cache(cache, Format::Text).unwrap();
155 let text = std::str::from_utf8(&bytes).unwrap();
156 assert!(text.contains("a: Disabled"));
157 }
158
159 #[test]
160 fn test_dump_protobuf_format() {
161 use protobuf::Message;
162
163 let cache = create_test_cache();
164 let bytes = dump_cache(cache, Format::Protobuf).unwrap();
165 let actual = ProtoDump::parse_from_bytes(&bytes).unwrap();
166
167 assert_eq!(
168 vec!["a".to_string(), "b".to_string()],
169 actual.item.iter().map(|item| item.id.clone().unwrap()).collect::<Vec<_>>()
170 );
171 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200172}