blob: 0bdb0b5f573270683db8a6c280b26d283d6190de [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;
Dennis Shen1dc9ad42023-05-12 00:21:55 +000027use crate::codegen_cpp::generate_cpp_code;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020028use crate::codegen_java::generate_java_code;
Mårten Kongstad30950782023-05-09 13:31:29 +020029use crate::protos::ProtoParsedFlags;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020030
Mårten Kongstad76adff22023-05-08 10:57:24 +020031#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020032pub enum Source {
33 #[allow(dead_code)] // only used in unit tests
34 Memory,
35 File(String),
36}
37
38impl fmt::Display for Source {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 match self {
41 Self::Memory => write!(f, "<memory>"),
42 Self::File(path) => write!(f, "{}", path),
43 }
44 }
45}
46
47pub struct Input {
48 pub source: Source,
49 pub reader: Box<dyn Read>,
50}
51
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020052pub struct OutputFile {
53 pub path: PathBuf, // relative to some root directory only main knows about
54 pub contents: Vec<u8>,
55}
56
Mårten Kongstad30950782023-05-09 13:31:29 +020057pub fn create_cache(
Mårten Kongstad30950782023-05-09 13:31:29 +020058 namespace: &str,
Mårten Kongstadfa23d292023-05-11 14:47:02 +020059 declarations: Vec<Input>,
60 values: Vec<Input>,
Mårten Kongstad30950782023-05-09 13:31:29 +020061) -> Result<Cache> {
Mårten Kongstade17ba5f2023-05-16 12:52:43 +020062 let mut cache = Cache::new(namespace.to_owned())?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020063
Mårten Kongstadfa23d292023-05-11 14:47:02 +020064 for mut input in declarations {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020065 let mut contents = String::new();
66 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020067 let dec_list = FlagDeclarations::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020068 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020069 ensure!(
Mårten Kongstadfa23d292023-05-11 14:47:02 +020070 namespace == dec_list.namespace,
Mårten Kongstad30950782023-05-09 13:31:29 +020071 "Failed to parse {}: expected namespace {}, got {}",
72 input.source,
73 namespace,
Mårten Kongstadfa23d292023-05-11 14:47:02 +020074 dec_list.namespace
Mårten Kongstad30950782023-05-09 13:31:29 +020075 );
Mårten Kongstadfa23d292023-05-11 14:47:02 +020076 for d in dec_list.flags.into_iter() {
77 cache.add_flag_declaration(input.source.clone(), d)?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020078 }
79 }
80
Mårten Kongstadfa23d292023-05-11 14:47:02 +020081 for mut input in values {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020082 let mut contents = String::new();
83 input.reader.read_to_string(&mut contents)?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020084 let values_list = FlagValue::try_from_text_proto_list(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020085 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +020086 for v in values_list {
87 // TODO: warn about flag values that do not take effect?
88 let _ = cache.add_flag_value(input.source.clone(), v);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020089 }
90 }
91
92 Ok(cache)
93}
94
Dennis Shen1dc9ad42023-05-12 00:21:55 +000095pub fn create_java_lib(cache: &Cache) -> Result<OutputFile> {
Zhi Doueb744892023-05-10 04:02:33 +000096 generate_java_code(cache)
97}
98
Dennis Shen1dc9ad42023-05-12 00:21:55 +000099pub fn create_cpp_lib(cache: &Cache) -> Result<OutputFile> {
100 generate_cpp_code(cache)
101}
102
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200103#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200104pub enum DumpFormat {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200105 Text,
106 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +0200107 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200108}
109
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200110pub fn dump_cache(cache: Cache, format: DumpFormat) -> Result<Vec<u8>> {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200111 match format {
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200112 DumpFormat::Text => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200113 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200114 for item in cache.iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200115 lines.push(format!("{}: {:?}\n", item.name, item.state));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200116 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200117 Ok(lines.concat().into())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200118 }
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200119 DumpFormat::Debug => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200120 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200121 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +0200122 lines.push(format!("{:?}\n", item));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200123 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200124 Ok(lines.concat().into())
125 }
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200126 DumpFormat::Protobuf => {
Mårten Kongstad30950782023-05-09 13:31:29 +0200127 let parsed_flags: ProtoParsedFlags = cache.into();
Mårten Kongstada1029092023-05-08 11:51:59 +0200128 let mut output = vec![];
Mårten Kongstad30950782023-05-09 13:31:29 +0200129 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstada1029092023-05-08 11:51:59 +0200130 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200131 }
132 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200138 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200139
Mårten Kongstada1029092023-05-08 11:51:59 +0200140 fn create_test_cache() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200141 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200142 namespace: "ns"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200143 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200144 name: "a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200145 description: "Description of a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200146 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200147 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200148 name: "b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200149 description: "Description of b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200150 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200151 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200152 let declarations = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200153 let o = r#"
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200154 flag_value {
Mårten Kongstad30950782023-05-09 13:31:29 +0200155 namespace: "ns"
156 name: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200157 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200158 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200159 }
160 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200161 let values = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
162 create_cache("ns", declarations, values).unwrap()
Mårten Kongstada1029092023-05-08 11:51:59 +0200163 }
164
165 #[test]
166 fn test_create_cache() {
167 let cache = create_test_cache(); // calls create_cache
Mårten Kongstad30950782023-05-09 13:31:29 +0200168 let item = cache.iter().find(|&item| item.name == "a").unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200169 assert_eq!(FlagState::Disabled, item.state);
170 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200171 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200172
173 #[test]
174 fn test_dump_text_format() {
175 let cache = create_test_cache();
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200176 let bytes = dump_cache(cache, DumpFormat::Text).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200177 let text = std::str::from_utf8(&bytes).unwrap();
178 assert!(text.contains("a: Disabled"));
179 }
180
181 #[test]
182 fn test_dump_protobuf_format() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200183 use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
Mårten Kongstada1029092023-05-08 11:51:59 +0200184 use protobuf::Message;
185
186 let cache = create_test_cache();
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200187 let bytes = dump_cache(cache, DumpFormat::Protobuf).unwrap();
Mårten Kongstad30950782023-05-09 13:31:29 +0200188 let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200189
190 assert_eq!(
191 vec!["a".to_string(), "b".to_string()],
Mårten Kongstad30950782023-05-09 13:31:29 +0200192 actual.parsed_flag.iter().map(|item| item.name.clone().unwrap()).collect::<Vec<_>>()
Mårten Kongstada1029092023-05-08 11:51:59 +0200193 );
Mårten Kongstad30950782023-05-09 13:31:29 +0200194
195 let item =
196 actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
197 assert_eq!(item.namespace(), "ns");
198 assert_eq!(item.name(), "b");
199 assert_eq!(item.description(), "Description of b");
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200200 assert_eq!(item.state(), ProtoFlagState::DISABLED);
201 assert_eq!(item.permission(), ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200202 let mut tp = ProtoTracepoint::new();
203 tp.set_source("<memory>".to_string());
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200204 tp.set_state(ProtoFlagState::DISABLED);
205 tp.set_permission(ProtoFlagPermission::READ_WRITE);
Mårten Kongstad30950782023-05-09 13:31:29 +0200206 assert_eq!(item.trace, vec![tp]);
Mårten Kongstada1029092023-05-08 11:51:59 +0200207 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200208}