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<()> {
|
pub fn install_package(paths: &Paths, matches: &ArgMatches) -> Result<()> {
|
||||||
let package_name = matches
|
let package_name = matches
|
||||||
.value_of("package_name")
|
.value_of("package_name")
|
||||||
.ok_or(anyhow!("missing package name"))?;
|
.ok_or_else(|| anyhow!("missing package name"))?;
|
||||||
let version = matches.value_of("version");
|
let version = matches.value_of("version");
|
||||||
let force = matches.is_present("force");
|
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::{
|
use crate::{
|
||||||
error_eprintln,
|
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};
|
use super::{CliModule, CliModuleArgs};
|
||||||
|
|
||||||
mod install;
|
mod install;
|
||||||
|
mod list;
|
||||||
|
mod uninstall;
|
||||||
|
mod update;
|
||||||
|
|
||||||
pub fn new() -> CliModule {
|
pub fn new() -> CliModule {
|
||||||
CliModule {
|
CliModule {
|
||||||
|
@ -49,9 +55,29 @@ fn package_main(args: CliModuleArgs) -> i32 {
|
||||||
error_eprintln!("unable to install package: {:?}", err);
|
error_eprintln!("unable to install package: {:?}", err);
|
||||||
return PACKAGE_INSTALL_FAILED;
|
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
|
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_SUCCESS: i32 = 0;
|
||||||
pub const PACKAGE_UNEXPECTED_FAILURE: i32 = 1;
|
pub const PACKAGE_UNEXPECTED_FAILURE: i32 = 1;
|
||||||
pub const PACKAGE_INSTALL_FAILED: i32 = 2;
|
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;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
|
|
@ -368,8 +368,12 @@ fn main() {
|
||||||
.about("package-management commands")
|
.about("package-management commands")
|
||||||
.subcommand(install_subcommand.clone())
|
.subcommand(install_subcommand.clone())
|
||||||
.subcommand(uninstall_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(
|
||||||
SubCommand::with_name("list").about("List all installed packages"), // TODO: update <Package> and update all
|
SubCommand::with_name("list").about("List all installed packages"), // TODO: update <Package> and update all
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("workaround")
|
SubCommand::with_name("workaround")
|
||||||
|
@ -378,7 +382,6 @@ fn main() {
|
||||||
.about("Attempt to disable secure input by automating the common steps."),
|
.about("Attempt to disable secure input by automating the common steps."),
|
||||||
)
|
)
|
||||||
.about("A collection of workarounds to solve some common problems."),
|
.about("A collection of workarounds to solve some common problems."),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("worker")
|
SubCommand::with_name("worker")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user