feat(core): implement list, uninstall and update package commands
This commit is contained in:
parent
64350de3a9
commit
393f431bc3
|
@ -27,7 +27,7 @@ use crate::info_println;
|
|||
pub fn install_package(paths: &Paths, matches: &ArgMatches) -> Result<()> {
|
||||
let package_name = matches
|
||||
.value_of("package_name")
|
||||
.ok_or(anyhow!("missing package name"))?;
|
||||
.ok_or_else(|| anyhow!("missing package name"))?;
|
||||
let version = matches.value_of("version");
|
||||
let force = matches.is_present("force");
|
||||
|
||||
|
|
53
espanso/src/cli/package/list.rs
Normal file
53
espanso/src/cli/package/list.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of espanso.
|
||||
*
|
||||
* Copyright (C) 2019-2021 Federico Terzi
|
||||
*
|
||||
* espanso is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* espanso is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use clap::ArgMatches;
|
||||
use espanso_package::StoredPackage;
|
||||
use espanso_path::Paths;
|
||||
|
||||
use crate::info_println;
|
||||
|
||||
pub fn list_packages(paths: &Paths, _: &ArgMatches) -> Result<()> {
|
||||
let archiver =
|
||||
espanso_package::get_archiver(&paths.packages).context("unable to get package archiver")?;
|
||||
|
||||
let packages = archiver.list().context("unable to list packages")?;
|
||||
|
||||
if packages.is_empty() {
|
||||
info_println!("No packages found!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
info_println!("Installed packages:");
|
||||
info_println!("");
|
||||
|
||||
for package in packages {
|
||||
match package {
|
||||
StoredPackage::Legacy(legacy) => {
|
||||
info_println!("- {} (legacy)", legacy.name);
|
||||
},
|
||||
StoredPackage::Modern(package) => {
|
||||
info_println!("- {} - version: {} ({})", package.manifest.name, package.manifest.version, package.source);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -19,12 +19,18 @@
|
|||
|
||||
use crate::{
|
||||
error_eprintln,
|
||||
exit_code::{configure_custom_panic_hook, PACKAGE_INSTALL_FAILED, PACKAGE_SUCCESS},
|
||||
exit_code::{
|
||||
configure_custom_panic_hook, PACKAGE_INSTALL_FAILED, PACKAGE_LIST_FAILED, PACKAGE_SUCCESS,
|
||||
PACKAGE_UNINSTALL_FAILED, PACKAGE_UPDATE_FAILED, PACKAGE_UPDATE_PARTIAL_FAILURE,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{CliModule, CliModuleArgs};
|
||||
|
||||
mod install;
|
||||
mod list;
|
||||
mod uninstall;
|
||||
mod update;
|
||||
|
||||
pub fn new() -> CliModule {
|
||||
CliModule {
|
||||
|
@ -49,9 +55,29 @@ fn package_main(args: CliModuleArgs) -> i32 {
|
|||
error_eprintln!("unable to install package: {:?}", err);
|
||||
return PACKAGE_INSTALL_FAILED;
|
||||
}
|
||||
} else if let Some(sub_matches) = cli_args.subcommand_matches("uninstall") {
|
||||
if let Err(err) = uninstall::uninstall_package(&paths, sub_matches) {
|
||||
error_eprintln!("unable to uninstall package: {:?}", err);
|
||||
return PACKAGE_UNINSTALL_FAILED;
|
||||
}
|
||||
} else if let Some(sub_matches) = cli_args.subcommand_matches("list") {
|
||||
if let Err(err) = list::list_packages(&paths, sub_matches) {
|
||||
error_eprintln!("unable to list packages: {:?}", err);
|
||||
return PACKAGE_LIST_FAILED;
|
||||
}
|
||||
} else if let Some(sub_matches) = cli_args.subcommand_matches("update") {
|
||||
match update::update_package(&paths, sub_matches) {
|
||||
Ok(update::UpdateResults::PartialFailure) => {
|
||||
error_eprintln!("some packages were updated, but not all of them. Check the previous log for more information");
|
||||
return PACKAGE_UPDATE_PARTIAL_FAILURE;
|
||||
}
|
||||
Err(err) => {
|
||||
error_eprintln!("unable to update package: {:?}", err);
|
||||
return PACKAGE_UPDATE_FAILED;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: uninstall, list, update
|
||||
|
||||
PACKAGE_SUCCESS
|
||||
}
|
||||
|
|
39
espanso/src/cli/package/uninstall.rs
Normal file
39
espanso/src/cli/package/uninstall.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of espanso.
|
||||
*
|
||||
* Copyright (C) 2019-2021 Federico Terzi
|
||||
*
|
||||
* espanso is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* espanso is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::ArgMatches;
|
||||
use espanso_path::Paths;
|
||||
|
||||
use crate::info_println;
|
||||
|
||||
pub fn uninstall_package(paths: &Paths, matches: &ArgMatches) -> Result<()> {
|
||||
let package_name = matches
|
||||
.value_of("package_name")
|
||||
.ok_or_else(|| anyhow!("missing package name"))?;
|
||||
|
||||
let archiver =
|
||||
espanso_package::get_archiver(&paths.packages).context("unable to get package archiver")?;
|
||||
|
||||
archiver.delete(package_name).context("unable to delete package")?;
|
||||
|
||||
info_println!("package '{}' uninstalled!", package_name);
|
||||
|
||||
Ok(())
|
||||
}
|
124
espanso/src/cli/package/update.rs
Normal file
124
espanso/src/cli/package/update.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* This file is part of espanso.
|
||||
*
|
||||
* Copyright (C) 2019-2021 Federico Terzi
|
||||
*
|
||||
* espanso is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* espanso is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::ArgMatches;
|
||||
use espanso_package::{Archiver, PackageSpecifier, SaveOptions, StoredPackage};
|
||||
use espanso_path::Paths;
|
||||
|
||||
use crate::{error_eprintln, info_println, warn_eprintln};
|
||||
|
||||
pub enum UpdateResults {
|
||||
Success,
|
||||
PartialFailure,
|
||||
}
|
||||
|
||||
pub fn update_package(paths: &Paths, matches: &ArgMatches) -> Result<UpdateResults> {
|
||||
let package_name = matches
|
||||
.value_of("package_name")
|
||||
.ok_or_else(|| anyhow!("missing package name"))?;
|
||||
|
||||
let archiver =
|
||||
espanso_package::get_archiver(&paths.packages).context("unable to get package archiver")?;
|
||||
|
||||
let packages_to_update = if package_name == "all" {
|
||||
let packages = archiver.list()?;
|
||||
info_println!("updating {} packages", packages.len());
|
||||
|
||||
packages
|
||||
.into_iter()
|
||||
.map(|package| match package {
|
||||
StoredPackage::Legacy(legacy) => legacy.name,
|
||||
StoredPackage::Modern(modern) => modern.manifest.name,
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![package_name.to_owned()]
|
||||
};
|
||||
|
||||
let mut update_errors = Vec::new();
|
||||
|
||||
for package_name in &packages_to_update {
|
||||
if let Err(err) = perform_package_update(&*archiver, &package_name) {
|
||||
error_eprintln!("error updating package '{}': {:?}", package_name, err);
|
||||
update_errors.push(err);
|
||||
}
|
||||
}
|
||||
|
||||
if update_errors.is_empty() {
|
||||
Ok(UpdateResults::Success)
|
||||
} else if packages_to_update.len() == update_errors.len() {
|
||||
Err(update_errors.pop().expect("unable to extract error"))
|
||||
} else {
|
||||
Ok(UpdateResults::PartialFailure)
|
||||
}
|
||||
}
|
||||
|
||||
fn perform_package_update(archiver: &dyn Archiver, package_name: &str) -> Result<()> {
|
||||
info_println!("updating package: {}", package_name);
|
||||
|
||||
let package = archiver.get(package_name)?;
|
||||
|
||||
let (package_specifier, old_version) = match package {
|
||||
StoredPackage::Legacy(legacy) => {
|
||||
warn_eprintln!(
|
||||
"detected legacy package '{}' without source information, pulling from espanso hub.",
|
||||
legacy.name
|
||||
);
|
||||
(
|
||||
PackageSpecifier {
|
||||
name: legacy.name,
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
)
|
||||
}
|
||||
StoredPackage::Modern(modern) => ((&modern).into(), Some(modern.manifest.version)),
|
||||
};
|
||||
|
||||
let package_provider = espanso_package::get_provider(&package_specifier)
|
||||
.context("unable to obtain compatible package provider")?;
|
||||
|
||||
info_println!("using package provider: {}", package_provider.name());
|
||||
|
||||
let new_package = package_provider.download(&package_specifier)?;
|
||||
|
||||
if new_package.version() == old_version.unwrap_or_default() {
|
||||
info_println!("already up to date!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
archiver
|
||||
.save(
|
||||
&*new_package,
|
||||
&package_specifier,
|
||||
&SaveOptions {
|
||||
overwrite_existing: true,
|
||||
},
|
||||
)
|
||||
.context("unable to save package")?;
|
||||
|
||||
info_println!(
|
||||
"updated package '{}' to version: {}",
|
||||
new_package.name(),
|
||||
new_package.version()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -58,6 +58,10 @@ pub const WORKAROUND_NOT_AVAILABLE: i32 = 2;
|
|||
pub const PACKAGE_SUCCESS: i32 = 0;
|
||||
pub const PACKAGE_UNEXPECTED_FAILURE: i32 = 1;
|
||||
pub const PACKAGE_INSTALL_FAILED: i32 = 2;
|
||||
pub const PACKAGE_UNINSTALL_FAILED: i32 = 3;
|
||||
pub const PACKAGE_LIST_FAILED: i32 = 4;
|
||||
pub const PACKAGE_UPDATE_FAILED: i32 = 5;
|
||||
pub const PACKAGE_UPDATE_PARTIAL_FAILURE: i32 = 6;
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
|
|
@ -368,18 +368,21 @@ fn main() {
|
|||
.about("package-management commands")
|
||||
.subcommand(install_subcommand.clone())
|
||||
.subcommand(uninstall_subcommand.clone())
|
||||
.subcommand(SubCommand::with_name("update").about(
|
||||
"Update a package. If 'all' is passed as package name, attempts to update all packages.",
|
||||
).arg(Arg::with_name("package_name").help("Package name")))
|
||||
.subcommand(
|
||||
SubCommand::with_name("list").about("List all installed packages"), // TODO: update <Package> and update all
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("workaround")
|
||||
.subcommand(
|
||||
SubCommand::with_name("secure-input")
|
||||
.about("Attempt to disable secure input by automating the common steps."),
|
||||
)
|
||||
.about("A collection of workarounds to solve some common problems."),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("workaround")
|
||||
.subcommand(
|
||||
SubCommand::with_name("secure-input")
|
||||
.about("Attempt to disable secure input by automating the common steps."),
|
||||
)
|
||||
.about("A collection of workarounds to solve some common problems."),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("worker")
|
||||
.setting(AppSettings::Hidden)
|
||||
|
|
Loading…
Reference in New Issue
Block a user