blob: 475d9b85e35b719207572cd641471568ef540775 [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;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020023use std::path::PathBuf;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020024
Mårten Kongstadfa23d292023-05-11 14:47:02 +020025use crate::aconfig::{FlagDeclarations, FlagValue};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020026use crate::cache::Cache;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020027use crate::codegen_java::generate_java_code;
Mårten Kongstad30950782023-05-09 13:31:29 +020028use crate::protos::ProtoParsedFlags;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020029
Mårten Kongstad76adff22023-05-08 10:57:24 +020030#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020031pub enum Source {
32 #[allow(dead_code)] // only used in unit tests
33 Memory,
34 File(String),
35}
36
37impl fmt::Display for Source {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 match self {
40 Self::Memory => write!(f, "<memory>"),
41 Self::File(path) => write!(f, "{}", path),
42 }
43 }
44}
45
46pub struct Input {
47 pub source: Source,
48 pub reader: Box<dyn Read>,
49}
50
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020051pub struct OutputFile {
52 pub path: PathBuf, // relative to some root directory only main knows about
53 pub contents: Vec<u8>,
54}
55
Mårten Kongstad30950782023-05-09 13:31:29 +020056pub fn create_cache(
Mårten Kongstad30950782023-05-09 13:31:29 +020057 namespace: &str,
Mårten Kongstadfa23d292023-05-11 14:47:02 +020058 declarations: Vec<Input>,
59 values: Vec<Input>,
Mårten Kongstad30950782023-05-09 13:31:29 +020060) -> Result<Cache> {
Mårten Kongstadfa23d292023-05-11 14:47:02 +020061 let mut cache = Cache::new(namespace.to_owned());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020062
Mårten Kongstadfa23d292023-05-11 14:47:02 +020063 for mut input in declarations {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020064 let mut contents = String::new();
65 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020066 let dec_list = FlagDeclarations::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020067 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020068 ensure!(
Mårten Kongstadfa23d292023-05-11 14:47:02 +020069 namespace == dec_list.namespace,
Mårten Kongstad30950782023-05-09 13:31:29 +020070 "Failed to parse {}: expected namespace {}, got {}",
71 input.source,
72 namespace,
Mårten Kongstadfa23d292023-05-11 14:47:02 +020073 dec_list.namespace
Mårten Kongstad30950782023-05-09 13:31:29 +020074 );
Mårten Kongstadfa23d292023-05-11 14:47:02 +020075 for d in dec_list.flags.into_iter() {
76 cache.add_flag_declaration(input.source.clone(), d)?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020077 }
78 }
79
Mårten Kongstadfa23d292023-05-11 14:47:02 +020080 for mut input in values {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020081 let mut contents = String::new();
82 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020083 let values_list = FlagValue::try_from_text_proto_list(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020084 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020085 for v in values_list {
86 // TODO: warn about flag values that do not take effect?
87 let _ = cache.add_flag_value(input.source.clone(), v);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020088 }
89 }
90
91 Ok(cache)
92}
93
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020094pub fn generate_code(cache: &Cache) -> Result<OutputFile> {
Zhi Doueb744892023-05-10 04:02:33 +000095 generate_java_code(cache)
96}
97
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020098#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
99pub enum Format {
100 Text,
101 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +0200102 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200103}
104
Mårten Kongstada1029092023-05-08 11:51:59 +0200105pub fn dump_cache(cache: Cache, format: Format) -> Result<Vec<u8>> {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200106 match format {
107 Format::Text => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200108 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200109 for item in cache.iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200110 lines.push(format!("{}: {:?}\n", item.name, item.state));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200111 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200112 Ok(lines.concat().into())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200113 }
114 Format::Debug => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200115 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200116 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +0200117 lines.push(format!("{:?}\n", item));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200118 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200119 Ok(lines.concat().into())
120 }
121 Format::Protobuf => {
Mårten Kongstad30950782023-05-09 13:31:29 +0200122 let parsed_flags: ProtoParsedFlags = cache.into();
Mårten Kongstada1029092023-05-08 11:51:59 +0200123 let mut output = vec![];
Mårten Kongstad30950782023-05-09 13:31:29 +0200124 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstada1029092023-05-08 11:51:59 +0200125 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200126 }
127 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200133 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200134
Mårten Kongstada1029092023-05-08 11:51:59 +0200135 fn create_test_cache() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200136 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200137 namespace: "ns"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200138 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200139 name: "a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200140 description: "Description of a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200141 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200142 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200143 name: "b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200144 description: "Description of b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200145 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200146 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200147 let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200148 let o = r#"
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200149 flag_value {
Mårten Kongstad30950782023-05-09 13:31:29 +0200150 namespace: "ns"
151 name: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200152 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200153 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200154 }
155 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200156 let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
157 create_cache("ns", declarations, values).unwrap()
Mårten Kongstada1029092023-05-08 11:51:59 +0200158 }
159
160 #[test]
161 fn test_create_cache() {
162 let cache = create_test_cache(); // calls create_cache
Mårten Kongstad30950782023-05-09 13:31:29 +0200163 let item = cache.iter().find(|&item| item.name == "a").unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200164 assert_eq!(FlagState::Disabled, item.state);
165 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200166 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200167
168 #[test]
169 fn test_dump_text_format() {
170 let cache = create_test_cache();
171 let bytes = dump_cache(cache, Format::Text).unwrap();
172 let text = std::str::from_utf8(&bytes).unwrap();
173 assert!(text.contains("a: Disabled"));
174 }
175
176 #[test]
177 fn test_dump_protobuf_format() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200178 use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
Mårten Kongstada1029092023-05-08 11:51:59 +0200179 use protobuf::Message;
180
181 let cache = create_test_cache();
182 let bytes = dump_cache(cache, Format::Protobuf).unwrap();
Mårten Kongstad30950782023-05-09 13:31:29 +0200183 let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200184
185 assert_eq!(
186 vec!["a".to_string(), "b".to_string()],
Mårten Kongstad30950782023-05-09 13:31:29 +0200187 actual.parsed_flag.iter().map(|item| item.name.clone().unwrap()).collect::<Vec<_>>()
Mårten Kongstada1029092023-05-08 11:51:59 +0200188 );
Mårten Kongstad30950782023-05-09 13:31:29 +0200189
190 let item =
191 actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
192 assert_eq!(item.namespace(), "ns");
193 assert_eq!(item.name(), "b");
194 assert_eq!(item.description(), "Description of b");
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200195 assert_eq!(item.state(), ProtoFlagState::DISABLED);
196 assert_eq!(item.permission(), ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200197 let mut tp = ProtoTracepoint::new();
198 tp.set_source("<memory>".to_string());
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200199 tp.set_state(ProtoFlagState::DISABLED);
200 tp.set_permission(ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200201 assert_eq!(item.trace, vec![tp]);
Mårten Kongstada1029092023-05-08 11:51:59 +0200202 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200203}