blob: 1e2a7a00a87ebadb617e8c11b41842e46392cd26 [file] [log] [blame]
Ted Bauer4dbf58a2024-02-08 18:46:52 +00001/*
2 * Copyright (C) 2024 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
17//! `aflags` is a device binary to read and write aconfig flags.
18
19use anyhow::Result;
20use clap::Parser;
21
22mod device_config_source;
23use device_config_source::DeviceConfigSource;
24
25#[derive(Clone)]
26enum FlagPermission {
27 ReadOnly,
28 ReadWrite,
29}
30
31impl ToString for FlagPermission {
32 fn to_string(&self) -> String {
33 match &self {
34 Self::ReadOnly => "read-only".into(),
35 Self::ReadWrite => "read-write".into(),
36 }
37 }
38}
39
40#[derive(Clone)]
41enum ValuePickedFrom {
42 Default,
43 Server,
44}
45
46impl ToString for ValuePickedFrom {
47 fn to_string(&self) -> String {
48 match &self {
49 Self::Default => "default".into(),
50 Self::Server => "server".into(),
51 }
52 }
53}
54
55#[derive(Clone)]
56struct Flag {
57 namespace: String,
58 name: String,
59 package: String,
60 container: String,
61 value: String,
62 permission: FlagPermission,
63 value_picked_from: ValuePickedFrom,
64}
65
66trait FlagSource {
67 fn list_flags() -> Result<Vec<Flag>>;
68}
69
70const ABOUT_TEXT: &str = "Tool for reading and writing flags.
71
72Rows in the table from the `list` command follow this format:
73
74 package flag_name value provenance permission container
75
76 * `package`: package set for this flag in its .aconfig definition.
77 * `flag_name`: flag name, also set in definition.
78 * `value`: the value read from the flag.
79 * `provenance`: one of:
80 + `default`: the flag value comes from its build-time default.
81 + `server`: the flag value comes from a server override.
82 * `permission`: read-write or read-only.
83 * `container`: the container for the flag, configured in its definition.
84";
85
86#[derive(Parser, Debug)]
87#[clap(long_about=ABOUT_TEXT)]
88struct Cli {
89 #[clap(subcommand)]
90 command: Command,
91}
92
93#[derive(Parser, Debug)]
94enum Command {
95 /// List all aconfig flags on this device.
96 List,
97}
98
99struct PaddingInfo {
100 longest_package_col: usize,
101 longest_name_col: usize,
102 longest_val_col: usize,
103 longest_value_picked_from_col: usize,
104 longest_permission_col: usize,
105}
106
107fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String {
108 let pkg = &flag.package;
109 let p0 = info.longest_package_col + 1;
110
111 let name = &flag.name;
112 let p1 = info.longest_name_col + 1;
113
114 let val = flag.value.to_string();
115 let p2 = info.longest_val_col + 1;
116
117 let value_picked_from = flag.value_picked_from.to_string();
118 let p3 = info.longest_value_picked_from_col + 1;
119
120 let perm = flag.permission.to_string();
121 let p4 = info.longest_permission_col + 1;
122
123 let container = &flag.container;
124
125 format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n")
126}
127
128fn list() -> Result<String> {
129 let flags = DeviceConfigSource::list_flags()?;
130 let padding_info = PaddingInfo {
131 longest_package_col: flags.iter().map(|f| f.package.len()).max().unwrap_or(0),
132 longest_name_col: flags.iter().map(|f| f.name.len()).max().unwrap_or(0),
133 longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
134 longest_value_picked_from_col: flags
135 .iter()
136 .map(|f| f.value_picked_from.to_string().len())
137 .max()
138 .unwrap_or(0),
139 longest_permission_col: flags
140 .iter()
141 .map(|f| f.permission.to_string().len())
142 .max()
143 .unwrap_or(0),
144 };
145
146 let mut result = String::from("");
147 for flag in flags {
148 let row = format_flag_row(&flag, &padding_info);
149 result.push_str(&row);
150 }
151 Ok(result)
152}
153
154fn main() {
155 let cli = Cli::parse();
156 let output = match cli.command {
157 Command::List => list(),
158 };
159 match output {
160 Ok(text) => println!("{text}"),
161 Err(msg) => println!("Error: {}", msg),
162 }
163}