Skip to content

Commit 91c0c94

Browse files
committed
feat: uninstall apps
Signed-off-by: Adrian Lungu <lunguadrian30@gmail.com>
1 parent 156db21 commit 91c0c94

7 files changed

Lines changed: 176 additions & 3 deletions

File tree

tockloader-cli/src/cli.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ fn get_subcommands() -> Vec<Command> {
5858
.args(get_app_args())
5959
.args(get_channel_args())
6060
.arg_required_else_help(false),
61+
Command::new("uninstall")
62+
.about("Uninstall apps")
63+
.arg(arg!(--"name" <APPNAME>).required(false))
64+
.args(get_app_args())
65+
.args(get_channel_args())
66+
.arg_required_else_help(false),
6167
]
6268
}
6369

tockloader-cli/src/main.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use anyhow::{Context, Result};
1010
use clap::ArgMatches;
1111
use cli::make_cli;
1212
use known_boards::KnownBoardNames;
13+
use tockloader_lib::attributes::app_attributes::AppOption;
1314
use tockloader_lib::board_settings::BoardSettings;
1415
use tockloader_lib::connection::{
1516
Connection, ProbeRSConnection, ProbeTargetInfo, SerialConnection, SerialTargetInfo,
@@ -19,7 +20,7 @@ use tockloader_lib::known_boards::KnownBoard;
1920
use tockloader_lib::tabs::tab::Tab;
2021
use tockloader_lib::{
2122
list_debug_probes, list_serial_ports, CommandEraseApps, CommandInfo, CommandInstall,
22-
CommandList,
23+
CommandList, CommandUninstall,
2324
};
2425

2526
fn get_serial_target_info(user_options: &ArgMatches) -> SerialTargetInfo {
@@ -240,6 +241,65 @@ async fn main() -> Result<()> {
240241

241242
conn.erase_apps().await.context("Failed to erase apps.")?;
242243
}
244+
Some(("uninstall", sub_matches)) => {
245+
cli::validate(&mut cmd, sub_matches);
246+
let mut conn = open_connection(sub_matches).await?;
247+
let installed_apps = conn.list().await.context("Failed to list apps.")?;
248+
let app_name = sub_matches.get_one::<String>("name").map(String::as_str);
249+
250+
if installed_apps.is_empty() {
251+
panic!("No apps installed");
252+
}
253+
match app_name {
254+
Some(app_name) => {
255+
match installed_apps
256+
.iter()
257+
.find(|iter| iter.tbf_header.get_package_name().unwrap_or("") == app_name)
258+
{
259+
Some(_) => conn
260+
.uninstall_app(Some(app_name.to_string()), None)
261+
.await
262+
.context("Failed to uninstall app.")?,
263+
None => panic!("Specified app is not installed!"),
264+
}
265+
}
266+
None => loop {
267+
let mut options: Vec<AppOption> = installed_apps
268+
.iter()
269+
.enumerate()
270+
.map(|(i, app)| AppOption { index: i + 1, app })
271+
.collect();
272+
273+
// Delete all option
274+
options.insert(
275+
0,
276+
AppOption {
277+
index: 0,
278+
app: &installed_apps[0],
279+
},
280+
);
281+
let selected =
282+
inquire::Select::new("Which app do you want to uninstall?", options)
283+
.prompt()
284+
.context("No apps installed")
285+
.unwrap();
286+
287+
if inquire::Select::new(
288+
format!("You chose {selected}",).as_str(),
289+
["Cancel", "Confirm"].to_vec(),
290+
)
291+
.prompt()
292+
.unwrap()
293+
== "Confirm"
294+
{
295+
conn.uninstall_app(None, Some(selected.index))
296+
.await
297+
.context("Failed to uninstall app")?;
298+
break;
299+
}
300+
},
301+
}
302+
}
243303
_ => {
244304
println!("Could not run the provided subcommand.");
245305
_ = make_cli().print_help();

tockloader-lib/src/attributes/app_attributes.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,34 @@ pub struct AppAttributes {
2121
pub tbf_footers: Vec<TbfFooter>,
2222
}
2323

24+
#[derive(Debug)]
25+
pub struct AppOption<'a> {
26+
pub index: usize,
27+
pub app: &'a AppAttributes,
28+
}
29+
30+
impl<'a> std::fmt::Display for AppOption<'a> {
31+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32+
if self.index == 0 {
33+
write!(f, "Delete all")
34+
} else {
35+
write!(
36+
f,
37+
"{}. {} - start: {:#x}, size: {}, type: {}",
38+
self.index,
39+
self.app.tbf_header.get_package_name().unwrap_or(""),
40+
self.app.address,
41+
self.app.tbf_header.total_size(),
42+
if self.app.tbf_header.get_fixed_address_flash().is_none() {
43+
"C (flexible)"
44+
} else {
45+
"Rust (fixed)"
46+
}
47+
)
48+
}
49+
}
50+
}
51+
2452
/// This structure represents a footer of a Tock application. Currently, footers
2553
/// only contain credentials, which are used to verify the integrity of the
2654
/// application.

tockloader-lib/src/command_impl/install.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ impl CommandInstall for TockloaderConnection {
2121
// obtain the binaries in a vector
2222
let mut app_binaries: Vec<Vec<u8>> = Vec::new();
2323

24-
let mut address = settings.start_address;
2524
for app in app_attributes_list.iter() {
25+
let address = app.address;
2626
app_binaries.push(
2727
self.read(address, app.tbf_header.total_size() as usize)
2828
.await
2929
.unwrap(),
3030
);
31-
address += app.tbf_header.total_size() as u64;
3231
}
3332

3433
let app = TockApp::from_tab(&tab, &settings).unwrap();

tockloader-lib/src/command_impl/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub mod list;
66
pub mod probers;
77
pub mod reshuffle_apps;
88
pub mod serial;
9+
pub mod uninstall;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use async_trait::async_trait;
2+
3+
use crate::{
4+
attributes::app_attributes::AppAttributes,
5+
command_impl::reshuffle_apps::{create_pkt, reshuffle_apps, TockApp},
6+
connection::{Connection, TockloaderConnection},
7+
errors::{InternalError, TockloaderError},
8+
CommandEraseApps, CommandList, CommandUninstall, IO,
9+
};
10+
11+
#[async_trait]
12+
impl CommandUninstall for TockloaderConnection {
13+
async fn uninstall_app(
14+
&mut self,
15+
app_name: Option<String>,
16+
app_index: Option<usize>,
17+
) -> Result<(), TockloaderError> {
18+
let settings = self.get_settings();
19+
20+
let mut app_attributes_list: Vec<AppAttributes> = self.list().await?;
21+
22+
// Remove all apps with given name
23+
if let Some(name) = app_name {
24+
let _ = app_attributes_list
25+
.retain(|app| app.tbf_header.get_package_name().unwrap_or("") != name);
26+
} else if let Some(index) = app_index {
27+
// Delete all apps, call erase
28+
if index == 0 {
29+
self.erase_apps().await?;
30+
return Ok(());
31+
}
32+
// Remove the selected index
33+
app_attributes_list.remove(index - 1);
34+
} else {
35+
panic!("Called uninstall with wrong parameters!");
36+
}
37+
38+
let tock_app_list = app_attributes_list
39+
.iter()
40+
.map(TockApp::from_app_attributes)
41+
.collect::<Vec<TockApp>>();
42+
43+
// obtain the binaries in a vector
44+
let mut app_binaries: Vec<Vec<u8>> = Vec::new();
45+
46+
for app in app_attributes_list.iter() {
47+
let address = app.address;
48+
app_binaries.push(
49+
self.read(address, app.tbf_header.total_size() as usize)
50+
.await
51+
.unwrap(),
52+
);
53+
}
54+
55+
let configuration =
56+
reshuffle_apps(&settings, tock_app_list).ok_or(TockloaderError::Internal(
57+
InternalError::MisconfiguredBoardSettings("Can't fit new app".to_string()),
58+
))?;
59+
60+
// create the pkt, this contains all the binaries in a vec
61+
let mut pkt = create_pkt(configuration, app_binaries, None, &settings);
62+
63+
pkt.append(&mut [0u8; 512].to_vec());
64+
65+
log::debug!("pkt len {}", pkt.len());
66+
// write the pkt
67+
let _ = self.write(settings.start_address, &pkt).await?;
68+
Ok(())
69+
}
70+
}

tockloader-lib/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ pub trait CommandInstall {
5050
async fn install_app(&mut self, tab_file: Tab) -> Result<(), TockloaderError>;
5151
}
5252

53+
#[async_trait]
54+
pub trait CommandUninstall {
55+
async fn uninstall_app(
56+
&mut self,
57+
app_name: Option<String>,
58+
app_index: Option<usize>,
59+
) -> Result<(), TockloaderError>;
60+
}
61+
5362
#[async_trait]
5463
pub trait CommandEraseApps {
5564
async fn erase_apps(&mut self) -> Result<(), TockloaderError>;

0 commit comments

Comments
 (0)