xref: /aosp_15_r20/build/make/tools/aconfig/aflags/src/main.rs (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker /*
2*9e94795aSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*9e94795aSAndroid Build Coastguard Worker  *
4*9e94795aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*9e94795aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*9e94795aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*9e94795aSAndroid Build Coastguard Worker  *
8*9e94795aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*9e94795aSAndroid Build Coastguard Worker  *
10*9e94795aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*9e94795aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*9e94795aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9e94795aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*9e94795aSAndroid Build Coastguard Worker  * limitations under the License.
15*9e94795aSAndroid Build Coastguard Worker  */
16*9e94795aSAndroid Build Coastguard Worker 
17*9e94795aSAndroid Build Coastguard Worker //! `aflags` is a device binary to read and write aconfig flags.
18*9e94795aSAndroid Build Coastguard Worker 
19*9e94795aSAndroid Build Coastguard Worker use anyhow::{anyhow, ensure, Result};
20*9e94795aSAndroid Build Coastguard Worker use clap::Parser;
21*9e94795aSAndroid Build Coastguard Worker 
22*9e94795aSAndroid Build Coastguard Worker mod device_config_source;
23*9e94795aSAndroid Build Coastguard Worker use device_config_source::DeviceConfigSource;
24*9e94795aSAndroid Build Coastguard Worker 
25*9e94795aSAndroid Build Coastguard Worker mod aconfig_storage_source;
26*9e94795aSAndroid Build Coastguard Worker use aconfig_storage_source::AconfigStorageSource;
27*9e94795aSAndroid Build Coastguard Worker 
28*9e94795aSAndroid Build Coastguard Worker mod load_protos;
29*9e94795aSAndroid Build Coastguard Worker 
30*9e94795aSAndroid Build Coastguard Worker #[derive(Clone, PartialEq, Debug)]
31*9e94795aSAndroid Build Coastguard Worker enum FlagPermission {
32*9e94795aSAndroid Build Coastguard Worker     ReadOnly,
33*9e94795aSAndroid Build Coastguard Worker     ReadWrite,
34*9e94795aSAndroid Build Coastguard Worker }
35*9e94795aSAndroid Build Coastguard Worker 
36*9e94795aSAndroid Build Coastguard Worker impl std::fmt::Display for FlagPermission {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result37*9e94795aSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38*9e94795aSAndroid Build Coastguard Worker         write!(
39*9e94795aSAndroid Build Coastguard Worker             f,
40*9e94795aSAndroid Build Coastguard Worker             "{}",
41*9e94795aSAndroid Build Coastguard Worker             match &self {
42*9e94795aSAndroid Build Coastguard Worker                 Self::ReadOnly => "read-only",
43*9e94795aSAndroid Build Coastguard Worker                 Self::ReadWrite => "read-write",
44*9e94795aSAndroid Build Coastguard Worker             }
45*9e94795aSAndroid Build Coastguard Worker         )
46*9e94795aSAndroid Build Coastguard Worker     }
47*9e94795aSAndroid Build Coastguard Worker }
48*9e94795aSAndroid Build Coastguard Worker 
49*9e94795aSAndroid Build Coastguard Worker #[derive(Clone, Debug)]
50*9e94795aSAndroid Build Coastguard Worker enum ValuePickedFrom {
51*9e94795aSAndroid Build Coastguard Worker     Default,
52*9e94795aSAndroid Build Coastguard Worker     Server,
53*9e94795aSAndroid Build Coastguard Worker     Local,
54*9e94795aSAndroid Build Coastguard Worker }
55*9e94795aSAndroid Build Coastguard Worker 
56*9e94795aSAndroid Build Coastguard Worker impl std::fmt::Display for ValuePickedFrom {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result57*9e94795aSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58*9e94795aSAndroid Build Coastguard Worker         write!(
59*9e94795aSAndroid Build Coastguard Worker             f,
60*9e94795aSAndroid Build Coastguard Worker             "{}",
61*9e94795aSAndroid Build Coastguard Worker             match &self {
62*9e94795aSAndroid Build Coastguard Worker                 Self::Default => "default",
63*9e94795aSAndroid Build Coastguard Worker                 Self::Server => "server",
64*9e94795aSAndroid Build Coastguard Worker                 Self::Local => "local",
65*9e94795aSAndroid Build Coastguard Worker             }
66*9e94795aSAndroid Build Coastguard Worker         )
67*9e94795aSAndroid Build Coastguard Worker     }
68*9e94795aSAndroid Build Coastguard Worker }
69*9e94795aSAndroid Build Coastguard Worker 
70*9e94795aSAndroid Build Coastguard Worker #[derive(Clone, Copy, PartialEq, Eq, Debug)]
71*9e94795aSAndroid Build Coastguard Worker enum FlagValue {
72*9e94795aSAndroid Build Coastguard Worker     Enabled,
73*9e94795aSAndroid Build Coastguard Worker     Disabled,
74*9e94795aSAndroid Build Coastguard Worker }
75*9e94795aSAndroid Build Coastguard Worker 
76*9e94795aSAndroid Build Coastguard Worker impl TryFrom<&str> for FlagValue {
77*9e94795aSAndroid Build Coastguard Worker     type Error = anyhow::Error;
78*9e94795aSAndroid Build Coastguard Worker 
try_from(value: &str) -> std::result::Result<Self, Self::Error>79*9e94795aSAndroid Build Coastguard Worker     fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
80*9e94795aSAndroid Build Coastguard Worker         match value {
81*9e94795aSAndroid Build Coastguard Worker             "true" | "enabled" => Ok(Self::Enabled),
82*9e94795aSAndroid Build Coastguard Worker             "false" | "disabled" => Ok(Self::Disabled),
83*9e94795aSAndroid Build Coastguard Worker             _ => Err(anyhow!("cannot convert string '{}' to FlagValue", value)),
84*9e94795aSAndroid Build Coastguard Worker         }
85*9e94795aSAndroid Build Coastguard Worker     }
86*9e94795aSAndroid Build Coastguard Worker }
87*9e94795aSAndroid Build Coastguard Worker 
88*9e94795aSAndroid Build Coastguard Worker impl std::fmt::Display for FlagValue {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result89*9e94795aSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90*9e94795aSAndroid Build Coastguard Worker         write!(
91*9e94795aSAndroid Build Coastguard Worker             f,
92*9e94795aSAndroid Build Coastguard Worker             "{}",
93*9e94795aSAndroid Build Coastguard Worker             match &self {
94*9e94795aSAndroid Build Coastguard Worker                 Self::Enabled => "enabled",
95*9e94795aSAndroid Build Coastguard Worker                 Self::Disabled => "disabled",
96*9e94795aSAndroid Build Coastguard Worker             }
97*9e94795aSAndroid Build Coastguard Worker         )
98*9e94795aSAndroid Build Coastguard Worker     }
99*9e94795aSAndroid Build Coastguard Worker }
100*9e94795aSAndroid Build Coastguard Worker 
101*9e94795aSAndroid Build Coastguard Worker #[derive(Clone, Debug)]
102*9e94795aSAndroid Build Coastguard Worker struct Flag {
103*9e94795aSAndroid Build Coastguard Worker     namespace: String,
104*9e94795aSAndroid Build Coastguard Worker     name: String,
105*9e94795aSAndroid Build Coastguard Worker     package: String,
106*9e94795aSAndroid Build Coastguard Worker     container: String,
107*9e94795aSAndroid Build Coastguard Worker     value: FlagValue,
108*9e94795aSAndroid Build Coastguard Worker     staged_value: Option<FlagValue>,
109*9e94795aSAndroid Build Coastguard Worker     permission: FlagPermission,
110*9e94795aSAndroid Build Coastguard Worker     value_picked_from: ValuePickedFrom,
111*9e94795aSAndroid Build Coastguard Worker }
112*9e94795aSAndroid Build Coastguard Worker 
113*9e94795aSAndroid Build Coastguard Worker impl Flag {
qualified_name(&self) -> String114*9e94795aSAndroid Build Coastguard Worker     fn qualified_name(&self) -> String {
115*9e94795aSAndroid Build Coastguard Worker         format!("{}.{}", self.package, self.name)
116*9e94795aSAndroid Build Coastguard Worker     }
117*9e94795aSAndroid Build Coastguard Worker 
display_staged_value(&self) -> String118*9e94795aSAndroid Build Coastguard Worker     fn display_staged_value(&self) -> String {
119*9e94795aSAndroid Build Coastguard Worker         match (&self.permission, self.staged_value) {
120*9e94795aSAndroid Build Coastguard Worker             (FlagPermission::ReadOnly, _) => "-".to_string(),
121*9e94795aSAndroid Build Coastguard Worker             (FlagPermission::ReadWrite, None) => "-".to_string(),
122*9e94795aSAndroid Build Coastguard Worker             (FlagPermission::ReadWrite, Some(v)) => format!("(->{})", v),
123*9e94795aSAndroid Build Coastguard Worker         }
124*9e94795aSAndroid Build Coastguard Worker     }
125*9e94795aSAndroid Build Coastguard Worker }
126*9e94795aSAndroid Build Coastguard Worker 
127*9e94795aSAndroid Build Coastguard Worker trait FlagSource {
list_flags() -> Result<Vec<Flag>>128*9e94795aSAndroid Build Coastguard Worker     fn list_flags() -> Result<Vec<Flag>>;
override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>129*9e94795aSAndroid Build Coastguard Worker     fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
130*9e94795aSAndroid Build Coastguard Worker }
131*9e94795aSAndroid Build Coastguard Worker 
132*9e94795aSAndroid Build Coastguard Worker enum FlagSourceType {
133*9e94795aSAndroid Build Coastguard Worker     DeviceConfig,
134*9e94795aSAndroid Build Coastguard Worker     AconfigStorage,
135*9e94795aSAndroid Build Coastguard Worker }
136*9e94795aSAndroid Build Coastguard Worker 
137*9e94795aSAndroid Build Coastguard Worker const ABOUT_TEXT: &str = "Tool for reading and writing flags.
138*9e94795aSAndroid Build Coastguard Worker 
139*9e94795aSAndroid Build Coastguard Worker Rows in the table from the `list` command follow this format:
140*9e94795aSAndroid Build Coastguard Worker 
141*9e94795aSAndroid Build Coastguard Worker   package flag_name value provenance permission container
142*9e94795aSAndroid Build Coastguard Worker 
143*9e94795aSAndroid Build Coastguard Worker   * `package`: package set for this flag in its .aconfig definition.
144*9e94795aSAndroid Build Coastguard Worker   * `flag_name`: flag name, also set in definition.
145*9e94795aSAndroid Build Coastguard Worker   * `value`: the value read from the flag.
146*9e94795aSAndroid Build Coastguard Worker   * `staged_value`: the value on next boot:
147*9e94795aSAndroid Build Coastguard Worker     + `-`: same as current value
148*9e94795aSAndroid Build Coastguard Worker     + `(->enabled) flipped to enabled on boot.
149*9e94795aSAndroid Build Coastguard Worker     + `(->disabled) flipped to disabled on boot.
150*9e94795aSAndroid Build Coastguard Worker   * `provenance`: one of:
151*9e94795aSAndroid Build Coastguard Worker     + `default`: the flag value comes from its build-time default.
152*9e94795aSAndroid Build Coastguard Worker     + `server`: the flag value comes from a server override.
153*9e94795aSAndroid Build Coastguard Worker   * `permission`: read-write or read-only.
154*9e94795aSAndroid Build Coastguard Worker   * `container`: the container for the flag, configured in its definition.
155*9e94795aSAndroid Build Coastguard Worker ";
156*9e94795aSAndroid Build Coastguard Worker 
157*9e94795aSAndroid Build Coastguard Worker #[derive(Parser, Debug)]
158*9e94795aSAndroid Build Coastguard Worker #[clap(long_about=ABOUT_TEXT)]
159*9e94795aSAndroid Build Coastguard Worker struct Cli {
160*9e94795aSAndroid Build Coastguard Worker     #[clap(subcommand)]
161*9e94795aSAndroid Build Coastguard Worker     command: Command,
162*9e94795aSAndroid Build Coastguard Worker }
163*9e94795aSAndroid Build Coastguard Worker 
164*9e94795aSAndroid Build Coastguard Worker #[derive(Parser, Debug)]
165*9e94795aSAndroid Build Coastguard Worker enum Command {
166*9e94795aSAndroid Build Coastguard Worker     /// List all aconfig flags on this device.
167*9e94795aSAndroid Build Coastguard Worker     List {
168*9e94795aSAndroid Build Coastguard Worker         /// Optionally filter by container name.
169*9e94795aSAndroid Build Coastguard Worker         #[clap(short = 'c', long = "container")]
170*9e94795aSAndroid Build Coastguard Worker         container: Option<String>,
171*9e94795aSAndroid Build Coastguard Worker     },
172*9e94795aSAndroid Build Coastguard Worker 
173*9e94795aSAndroid Build Coastguard Worker     /// Enable an aconfig flag on this device, on the next boot.
174*9e94795aSAndroid Build Coastguard Worker     Enable {
175*9e94795aSAndroid Build Coastguard Worker         /// <package>.<flag_name>
176*9e94795aSAndroid Build Coastguard Worker         qualified_name: String,
177*9e94795aSAndroid Build Coastguard Worker     },
178*9e94795aSAndroid Build Coastguard Worker 
179*9e94795aSAndroid Build Coastguard Worker     /// Disable an aconfig flag on this device, on the next boot.
180*9e94795aSAndroid Build Coastguard Worker     Disable {
181*9e94795aSAndroid Build Coastguard Worker         /// <package>.<flag_name>
182*9e94795aSAndroid Build Coastguard Worker         qualified_name: String,
183*9e94795aSAndroid Build Coastguard Worker     },
184*9e94795aSAndroid Build Coastguard Worker 
185*9e94795aSAndroid Build Coastguard Worker     /// Display which flag storage backs aconfig flags.
186*9e94795aSAndroid Build Coastguard Worker     WhichBacking,
187*9e94795aSAndroid Build Coastguard Worker }
188*9e94795aSAndroid Build Coastguard Worker 
189*9e94795aSAndroid Build Coastguard Worker struct PaddingInfo {
190*9e94795aSAndroid Build Coastguard Worker     longest_flag_col: usize,
191*9e94795aSAndroid Build Coastguard Worker     longest_val_col: usize,
192*9e94795aSAndroid Build Coastguard Worker     longest_staged_val_col: usize,
193*9e94795aSAndroid Build Coastguard Worker     longest_value_picked_from_col: usize,
194*9e94795aSAndroid Build Coastguard Worker     longest_permission_col: usize,
195*9e94795aSAndroid Build Coastguard Worker }
196*9e94795aSAndroid Build Coastguard Worker 
197*9e94795aSAndroid Build Coastguard Worker struct Filter {
198*9e94795aSAndroid Build Coastguard Worker     container: Option<String>,
199*9e94795aSAndroid Build Coastguard Worker }
200*9e94795aSAndroid Build Coastguard Worker 
201*9e94795aSAndroid Build Coastguard Worker impl Filter {
apply(&self, flags: &[Flag]) -> Vec<Flag>202*9e94795aSAndroid Build Coastguard Worker     fn apply(&self, flags: &[Flag]) -> Vec<Flag> {
203*9e94795aSAndroid Build Coastguard Worker         flags
204*9e94795aSAndroid Build Coastguard Worker             .iter()
205*9e94795aSAndroid Build Coastguard Worker             .filter(|flag| match &self.container {
206*9e94795aSAndroid Build Coastguard Worker                 Some(c) => flag.container == *c,
207*9e94795aSAndroid Build Coastguard Worker                 None => true,
208*9e94795aSAndroid Build Coastguard Worker             })
209*9e94795aSAndroid Build Coastguard Worker             .cloned()
210*9e94795aSAndroid Build Coastguard Worker             .collect()
211*9e94795aSAndroid Build Coastguard Worker     }
212*9e94795aSAndroid Build Coastguard Worker }
213*9e94795aSAndroid Build Coastguard Worker 
format_flag_row(flag: &Flag, info: &PaddingInfo) -> String214*9e94795aSAndroid Build Coastguard Worker fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String {
215*9e94795aSAndroid Build Coastguard Worker     let full_name = flag.qualified_name();
216*9e94795aSAndroid Build Coastguard Worker     let p0 = info.longest_flag_col + 1;
217*9e94795aSAndroid Build Coastguard Worker 
218*9e94795aSAndroid Build Coastguard Worker     let val = flag.value.to_string();
219*9e94795aSAndroid Build Coastguard Worker     let p1 = info.longest_val_col + 1;
220*9e94795aSAndroid Build Coastguard Worker 
221*9e94795aSAndroid Build Coastguard Worker     let staged_val = flag.display_staged_value();
222*9e94795aSAndroid Build Coastguard Worker     let p2 = info.longest_staged_val_col + 1;
223*9e94795aSAndroid Build Coastguard Worker 
224*9e94795aSAndroid Build Coastguard Worker     let value_picked_from = flag.value_picked_from.to_string();
225*9e94795aSAndroid Build Coastguard Worker     let p3 = info.longest_value_picked_from_col + 1;
226*9e94795aSAndroid Build Coastguard Worker 
227*9e94795aSAndroid Build Coastguard Worker     let perm = flag.permission.to_string();
228*9e94795aSAndroid Build Coastguard Worker     let p4 = info.longest_permission_col + 1;
229*9e94795aSAndroid Build Coastguard Worker 
230*9e94795aSAndroid Build Coastguard Worker     let container = &flag.container;
231*9e94795aSAndroid Build Coastguard Worker 
232*9e94795aSAndroid Build Coastguard Worker     format!(
233*9e94795aSAndroid Build Coastguard Worker         "{full_name:p0$}{val:p1$}{staged_val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n"
234*9e94795aSAndroid Build Coastguard Worker     )
235*9e94795aSAndroid Build Coastguard Worker }
236*9e94795aSAndroid Build Coastguard Worker 
set_flag(qualified_name: &str, value: &str) -> Result<()>237*9e94795aSAndroid Build Coastguard Worker fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
238*9e94795aSAndroid Build Coastguard Worker     let flags_binding = DeviceConfigSource::list_flags()?;
239*9e94795aSAndroid Build Coastguard Worker     let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or(
240*9e94795aSAndroid Build Coastguard Worker         anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"),
241*9e94795aSAndroid Build Coastguard Worker     )?;
242*9e94795aSAndroid Build Coastguard Worker 
243*9e94795aSAndroid Build Coastguard Worker     ensure!(flag.permission == FlagPermission::ReadWrite,
244*9e94795aSAndroid Build Coastguard Worker             format!("could not write flag '{qualified_name}', it is read-only for the current release configuration."));
245*9e94795aSAndroid Build Coastguard Worker 
246*9e94795aSAndroid Build Coastguard Worker     DeviceConfigSource::override_flag(&flag.namespace, qualified_name, value)?;
247*9e94795aSAndroid Build Coastguard Worker 
248*9e94795aSAndroid Build Coastguard Worker     Ok(())
249*9e94795aSAndroid Build Coastguard Worker }
250*9e94795aSAndroid Build Coastguard Worker 
list(source_type: FlagSourceType, container: Option<String>) -> Result<String>251*9e94795aSAndroid Build Coastguard Worker fn list(source_type: FlagSourceType, container: Option<String>) -> Result<String> {
252*9e94795aSAndroid Build Coastguard Worker     let flags_unfiltered = match source_type {
253*9e94795aSAndroid Build Coastguard Worker         FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?,
254*9e94795aSAndroid Build Coastguard Worker         FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?,
255*9e94795aSAndroid Build Coastguard Worker     };
256*9e94795aSAndroid Build Coastguard Worker 
257*9e94795aSAndroid Build Coastguard Worker     if let Some(ref c) = container {
258*9e94795aSAndroid Build Coastguard Worker         ensure!(
259*9e94795aSAndroid Build Coastguard Worker             load_protos::list_containers()?.contains(c),
260*9e94795aSAndroid Build Coastguard Worker             format!("container '{}' not found", &c)
261*9e94795aSAndroid Build Coastguard Worker         );
262*9e94795aSAndroid Build Coastguard Worker     }
263*9e94795aSAndroid Build Coastguard Worker 
264*9e94795aSAndroid Build Coastguard Worker     let flags = (Filter { container }).apply(&flags_unfiltered);
265*9e94795aSAndroid Build Coastguard Worker     let padding_info = PaddingInfo {
266*9e94795aSAndroid Build Coastguard Worker         longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
267*9e94795aSAndroid Build Coastguard Worker         longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
268*9e94795aSAndroid Build Coastguard Worker         longest_staged_val_col: flags
269*9e94795aSAndroid Build Coastguard Worker             .iter()
270*9e94795aSAndroid Build Coastguard Worker             .map(|f| f.display_staged_value().len())
271*9e94795aSAndroid Build Coastguard Worker             .max()
272*9e94795aSAndroid Build Coastguard Worker             .unwrap_or(0),
273*9e94795aSAndroid Build Coastguard Worker         longest_value_picked_from_col: flags
274*9e94795aSAndroid Build Coastguard Worker             .iter()
275*9e94795aSAndroid Build Coastguard Worker             .map(|f| f.value_picked_from.to_string().len())
276*9e94795aSAndroid Build Coastguard Worker             .max()
277*9e94795aSAndroid Build Coastguard Worker             .unwrap_or(0),
278*9e94795aSAndroid Build Coastguard Worker         longest_permission_col: flags
279*9e94795aSAndroid Build Coastguard Worker             .iter()
280*9e94795aSAndroid Build Coastguard Worker             .map(|f| f.permission.to_string().len())
281*9e94795aSAndroid Build Coastguard Worker             .max()
282*9e94795aSAndroid Build Coastguard Worker             .unwrap_or(0),
283*9e94795aSAndroid Build Coastguard Worker     };
284*9e94795aSAndroid Build Coastguard Worker 
285*9e94795aSAndroid Build Coastguard Worker     let mut result = String::from("");
286*9e94795aSAndroid Build Coastguard Worker     for flag in flags {
287*9e94795aSAndroid Build Coastguard Worker         let row = format_flag_row(&flag, &padding_info);
288*9e94795aSAndroid Build Coastguard Worker         result.push_str(&row);
289*9e94795aSAndroid Build Coastguard Worker     }
290*9e94795aSAndroid Build Coastguard Worker     Ok(result)
291*9e94795aSAndroid Build Coastguard Worker }
292*9e94795aSAndroid Build Coastguard Worker 
display_which_backing() -> String293*9e94795aSAndroid Build Coastguard Worker fn display_which_backing() -> String {
294*9e94795aSAndroid Build Coastguard Worker     if aconfig_flags::auto_generated::enable_only_new_storage() {
295*9e94795aSAndroid Build Coastguard Worker         "aconfig_storage".to_string()
296*9e94795aSAndroid Build Coastguard Worker     } else {
297*9e94795aSAndroid Build Coastguard Worker         "device_config".to_string()
298*9e94795aSAndroid Build Coastguard Worker     }
299*9e94795aSAndroid Build Coastguard Worker }
300*9e94795aSAndroid Build Coastguard Worker 
main() -> Result<()>301*9e94795aSAndroid Build Coastguard Worker fn main() -> Result<()> {
302*9e94795aSAndroid Build Coastguard Worker     ensure!(nix::unistd::Uid::current().is_root(), "must be root");
303*9e94795aSAndroid Build Coastguard Worker 
304*9e94795aSAndroid Build Coastguard Worker     let cli = Cli::parse();
305*9e94795aSAndroid Build Coastguard Worker     let output = match cli.command {
306*9e94795aSAndroid Build Coastguard Worker         Command::List { container } => {
307*9e94795aSAndroid Build Coastguard Worker             if aconfig_flags::auto_generated::enable_only_new_storage() {
308*9e94795aSAndroid Build Coastguard Worker                 list(FlagSourceType::AconfigStorage, container)
309*9e94795aSAndroid Build Coastguard Worker                     .map_err(|err| anyhow!("could not list flags: {err}"))
310*9e94795aSAndroid Build Coastguard Worker                     .map(Some)
311*9e94795aSAndroid Build Coastguard Worker             } else {
312*9e94795aSAndroid Build Coastguard Worker                 list(FlagSourceType::DeviceConfig, container).map(Some)
313*9e94795aSAndroid Build Coastguard Worker             }
314*9e94795aSAndroid Build Coastguard Worker         }
315*9e94795aSAndroid Build Coastguard Worker         Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
316*9e94795aSAndroid Build Coastguard Worker         Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
317*9e94795aSAndroid Build Coastguard Worker         Command::WhichBacking => Ok(Some(display_which_backing())),
318*9e94795aSAndroid Build Coastguard Worker     };
319*9e94795aSAndroid Build Coastguard Worker     match output {
320*9e94795aSAndroid Build Coastguard Worker         Ok(Some(text)) => println!("{text}"),
321*9e94795aSAndroid Build Coastguard Worker         Ok(None) => (),
322*9e94795aSAndroid Build Coastguard Worker         Err(message) => println!("Error: {message}"),
323*9e94795aSAndroid Build Coastguard Worker     }
324*9e94795aSAndroid Build Coastguard Worker 
325*9e94795aSAndroid Build Coastguard Worker     Ok(())
326*9e94795aSAndroid Build Coastguard Worker }
327*9e94795aSAndroid Build Coastguard Worker 
328*9e94795aSAndroid Build Coastguard Worker #[cfg(test)]
329*9e94795aSAndroid Build Coastguard Worker mod tests {
330*9e94795aSAndroid Build Coastguard Worker     use super::*;
331*9e94795aSAndroid Build Coastguard Worker 
332*9e94795aSAndroid Build Coastguard Worker     #[test]
test_filter_container()333*9e94795aSAndroid Build Coastguard Worker     fn test_filter_container() {
334*9e94795aSAndroid Build Coastguard Worker         let flags = vec![
335*9e94795aSAndroid Build Coastguard Worker             Flag {
336*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
337*9e94795aSAndroid Build Coastguard Worker                 name: "test1".to_string(),
338*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
339*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
340*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
341*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
342*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
343*9e94795aSAndroid Build Coastguard Worker                 container: "system".to_string(),
344*9e94795aSAndroid Build Coastguard Worker             },
345*9e94795aSAndroid Build Coastguard Worker             Flag {
346*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
347*9e94795aSAndroid Build Coastguard Worker                 name: "test2".to_string(),
348*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
349*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
350*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
351*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
352*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
353*9e94795aSAndroid Build Coastguard Worker                 container: "not_system".to_string(),
354*9e94795aSAndroid Build Coastguard Worker             },
355*9e94795aSAndroid Build Coastguard Worker             Flag {
356*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
357*9e94795aSAndroid Build Coastguard Worker                 name: "test3".to_string(),
358*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
359*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
360*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
361*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
362*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
363*9e94795aSAndroid Build Coastguard Worker                 container: "system".to_string(),
364*9e94795aSAndroid Build Coastguard Worker             },
365*9e94795aSAndroid Build Coastguard Worker         ];
366*9e94795aSAndroid Build Coastguard Worker 
367*9e94795aSAndroid Build Coastguard Worker         assert_eq!((Filter { container: Some("system".to_string()) }).apply(&flags).len(), 2);
368*9e94795aSAndroid Build Coastguard Worker     }
369*9e94795aSAndroid Build Coastguard Worker 
370*9e94795aSAndroid Build Coastguard Worker     #[test]
test_filter_no_container()371*9e94795aSAndroid Build Coastguard Worker     fn test_filter_no_container() {
372*9e94795aSAndroid Build Coastguard Worker         let flags = vec![
373*9e94795aSAndroid Build Coastguard Worker             Flag {
374*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
375*9e94795aSAndroid Build Coastguard Worker                 name: "test1".to_string(),
376*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
377*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
378*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
379*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
380*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
381*9e94795aSAndroid Build Coastguard Worker                 container: "system".to_string(),
382*9e94795aSAndroid Build Coastguard Worker             },
383*9e94795aSAndroid Build Coastguard Worker             Flag {
384*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
385*9e94795aSAndroid Build Coastguard Worker                 name: "test2".to_string(),
386*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
387*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
388*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
389*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
390*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
391*9e94795aSAndroid Build Coastguard Worker                 container: "not_system".to_string(),
392*9e94795aSAndroid Build Coastguard Worker             },
393*9e94795aSAndroid Build Coastguard Worker             Flag {
394*9e94795aSAndroid Build Coastguard Worker                 namespace: "namespace".to_string(),
395*9e94795aSAndroid Build Coastguard Worker                 name: "test3".to_string(),
396*9e94795aSAndroid Build Coastguard Worker                 package: "package".to_string(),
397*9e94795aSAndroid Build Coastguard Worker                 value: FlagValue::Disabled,
398*9e94795aSAndroid Build Coastguard Worker                 staged_value: None,
399*9e94795aSAndroid Build Coastguard Worker                 permission: FlagPermission::ReadWrite,
400*9e94795aSAndroid Build Coastguard Worker                 value_picked_from: ValuePickedFrom::Default,
401*9e94795aSAndroid Build Coastguard Worker                 container: "system".to_string(),
402*9e94795aSAndroid Build Coastguard Worker             },
403*9e94795aSAndroid Build Coastguard Worker         ];
404*9e94795aSAndroid Build Coastguard Worker 
405*9e94795aSAndroid Build Coastguard Worker         assert_eq!((Filter { container: None }).apply(&flags).len(), 3);
406*9e94795aSAndroid Build Coastguard Worker     }
407*9e94795aSAndroid Build Coastguard Worker }
408