xref: /aosp_15_r20/tools/asuite/adevice/src/cli.rs (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1 use clap::{Args, Parser, Subcommand};
2 
3 #[derive(Parser)]
4 #[command(
5     about = "Tool to push your rebuilt modules to your device.\nSet ANDROID_SERIAL to choose your device if there is more than one."
6 )]
7 #[command(version = "0.4")]
8 pub struct Cli {
9     #[command(subcommand)]
10     pub command: Commands,
11     #[clap(flatten)]
12     pub global_options: GlobalOptions,
13 }
14 
15 #[derive(Subcommand)]
16 pub enum Commands {
17     /// Shows the file differences between build tree and host.
18     /// Show the actions that would be run.
19     Status,
20     /// Updates the device (via adb push) with files from $ANDROID_PRODUCT_OUT.
21     /// Only pushes files listed on --partitions.
22     /// This does not work well when $ANDROID_PRODUCT_OUT and the device image
23     /// are vastly different.  You should reimage the device in that case.
24     Update,
25     /// Adds module name to the list of tracked modules.
26     /// If an installed file under $ANDROID_PRODUCT_OUT is not
27     /// part of a tracked module or the base image, then it will
28     /// not be pushed to the device.
29     Track(ModuleNames),
30     /// Change the base module we are tracking from `droid` to something else.
31     TrackBase(BaseModule),
32     /// Removes module name from list of tracked modules.
33     /// See `track` for more details.
34     Untrack(ModuleNames),
35     /// Removes untracked files from the device.
36     Clean {
37         #[clap(long, short)]
38         force: bool,
39     },
40 }
41 
42 #[derive(Debug, Args)]
43 pub struct ModuleNames {
44     /// List one or modules, space separated.
45     /// Use the module name in Android.bp
46     pub modules: Vec<String>,
47 }
48 
49 #[derive(Debug, Args)]
50 pub struct BaseModule {
51     /// The module name the system image is built from like 'droid' or 'sync'.
52     /// It can also be an unbundled mainline module name.
53     pub base: String,
54 }
55 
56 #[derive(Args, Debug)]
57 pub struct GlobalOptions {
58     // TODO(rbraunstein): Revisit all the command name descriptions.
59     // TODO(rbraunstein): Add system_other to the default list, but deal gracefully
60     // with it not being on the device.
61     /// Partitions in the product tree to sync. Repeat arg or comma-separate.
62     ///
63     /// By default this includes: "system", "system_ext", "odm", "product"
64     ///
65     /// If a partition is explicitly passed in but that does not exist in the
66     /// tracked files then adevice will error.
67     #[clap(long, short, global = true, value_delimiter = ',')]
68     pub partitions: Option<Vec<String>>,
69     // TODO(rbraunstein): Validate relative, not absolute paths.
70     /// If unset defaults to ANDROID_PRODUCT_OUT env variable.
71     #[clap(long = "product_out", global = true)]
72     pub product_out: Option<String>,
73     /// Do not make any modification if more than this many are needed
74     #[clap(long, short, default_value_t = 400, global = true)]
75     pub max_allowed_changes: usize,
76     /// If passed, use the device, otherwise use the only connected device or ANDROID_SERIAL env value.
77     #[clap(long, short, global = true)]
78     pub serial: Option<String>,
79     /// Override the type of restart that happens after an update.
80     #[clap(long = "restart", short, global = true, value_enum, default_value_t=RestartChoice::Auto)]
81     pub restart_choice: RestartChoice,
82     /// Path to config file.  Uses $HOME/.config/asuite/adevice-tracking.json if unset.
83     #[clap(long = "config", global = true)]
84     pub config_path: Option<String>,
85     #[clap(long = "force", global = true, alias = "force", alias = "force")]
86     // Force device update even if unbuilt modules are detected.
87     pub force: bool,
88     // Don't wait for device to become available after restarting it.
89     #[clap(long = "nowait", global = true, alias = "no_wait", alias = "no-wait")]
90     pub nowait: bool,
91 }
92 
93 #[derive(clap::ValueEnum, Clone, Debug)]
94 pub enum Verbosity {
95     /// Only show minimal information.
96     None,
97     /// Show all adb operations.
98     Details,
99     /// For debugging internals of tool and timings.
100     Debug,
101 }
102 
103 /// Allows you to choose how to reboot or to not reboot.
104 #[derive(clap::ValueEnum, Clone, Debug)]
105 pub enum RestartChoice {
106     /// Let the system choose the restart based on the files changed.
107     Auto,
108     /// Don't restart.
109     None,
110     /// Always do a full system reboot after updates.
111     Reboot,
112     /// Always do a framework restart restart after updates.
113     Restart,
114 }
115 
116 #[derive(Clone, Debug, PartialEq)]
117 pub enum Wait {
118     Yes,
119     No,
120 }
121 
122 impl From<Wait> for bool {
from(w: Wait) -> bool123     fn from(w: Wait) -> bool {
124         match w {
125             Wait::Yes => true,
126             Wait::No => false,
127         }
128     }
129 }
130 
131 impl Cli {
132     /// Decide if the options indicate that we should wait for the device.
133     /// Exists in case the cli options get more complicated like --wait=false
should_wait(&self) -> Wait134     pub fn should_wait(&self) -> Wait {
135         match self.global_options.nowait {
136             true => Wait::No,
137             false => Wait::Yes,
138         }
139     }
140 }
141 
142 #[cfg(test)]
143 mod tests {
144     use crate::cli::Wait;
145 
146     use super::Cli;
147     use clap::Parser;
148 
149     #[test]
force_default_false()150     fn force_default_false() {
151         let cli = Cli::parse_from(["fake_prog", "update"]);
152         assert!(!cli.global_options.force);
153     }
154 
155     #[test]
force_works()156     fn force_works() {
157         let cli = Cli::parse_from(["fake_prog", "update", "--force"]);
158         assert!(cli.global_options.force);
159     }
160 
161     #[test]
nowait_works()162     fn nowait_works() {
163         let cli = Cli::parse_from(["fake_prog", "update", "--nowait"]);
164         assert!(cli.global_options.nowait);
165     }
166 
167     #[test]
no_wait_alias_works()168     fn no_wait_alias_works() {
169         let cli = Cli::parse_from(["fake_prog", "update", "--no_wait"]);
170         assert!(cli.global_options.nowait);
171     }
172 
173     #[test]
unset_nowait_is_none()174     fn unset_nowait_is_none() {
175         let cli = Cli::parse_from(["fake_prog", "update"]);
176         assert!(!cli.global_options.nowait);
177     }
178 
179     #[test]
it_should_wait()180     fn it_should_wait() {
181         let cli = Cli::parse_from(["fake_prog", "update"]);
182         assert_eq!(Wait::Yes, cli.should_wait());
183         let should_wait: bool = cli.should_wait().into();
184         assert!(should_wait);
185     }
186 
187     #[test]
it_should_not_wait()188     fn it_should_not_wait() {
189         let cli = Cli::parse_from(["fake_prog", "update", "--nowait"]);
190         assert_eq!(Wait::No, cli.should_wait());
191         let should_wait: bool = cli.should_wait().into();
192         assert!(!should_wait);
193     }
194 }
195