mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
feat(cli/uninstall): add uninstall command (#12209)
This commit is contained in:
parent
f602d63f48
commit
ee2e25fba7
3 changed files with 145 additions and 0 deletions
52
cli/flags.rs
52
cli/flags.rs
|
@ -110,6 +110,12 @@ pub struct InstallFlags {
|
||||||
pub force: bool,
|
pub force: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct UninstallFlags {
|
||||||
|
pub name: String,
|
||||||
|
pub root: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct LintFlags {
|
pub struct LintFlags {
|
||||||
pub files: Vec<PathBuf>,
|
pub files: Vec<PathBuf>,
|
||||||
|
@ -166,6 +172,7 @@ pub enum DenoSubcommand {
|
||||||
Fmt(FmtFlags),
|
Fmt(FmtFlags),
|
||||||
Info(InfoFlags),
|
Info(InfoFlags),
|
||||||
Install(InstallFlags),
|
Install(InstallFlags),
|
||||||
|
Uninstall(UninstallFlags),
|
||||||
Lsp,
|
Lsp,
|
||||||
Lint(LintFlags),
|
Lint(LintFlags),
|
||||||
Repl(ReplFlags),
|
Repl(ReplFlags),
|
||||||
|
@ -428,6 +435,8 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
|
||||||
bundle_parse(&mut flags, m);
|
bundle_parse(&mut flags, m);
|
||||||
} else if let Some(m) = matches.subcommand_matches("install") {
|
} else if let Some(m) = matches.subcommand_matches("install") {
|
||||||
install_parse(&mut flags, m);
|
install_parse(&mut flags, m);
|
||||||
|
} else if let Some(m) = matches.subcommand_matches("uninstall") {
|
||||||
|
uninstall_parse(&mut flags, m);
|
||||||
} else if let Some(m) = matches.subcommand_matches("completions") {
|
} else if let Some(m) = matches.subcommand_matches("completions") {
|
||||||
completions_parse(&mut flags, m);
|
completions_parse(&mut flags, m);
|
||||||
} else if let Some(m) = matches.subcommand_matches("test") {
|
} else if let Some(m) = matches.subcommand_matches("test") {
|
||||||
|
@ -499,6 +508,7 @@ If the flag is set, restrict these messages to errors.",
|
||||||
.subcommand(fmt_subcommand())
|
.subcommand(fmt_subcommand())
|
||||||
.subcommand(info_subcommand())
|
.subcommand(info_subcommand())
|
||||||
.subcommand(install_subcommand())
|
.subcommand(install_subcommand())
|
||||||
|
.subcommand(uninstall_subcommand())
|
||||||
.subcommand(lsp_subcommand())
|
.subcommand(lsp_subcommand())
|
||||||
.subcommand(lint_subcommand())
|
.subcommand(lint_subcommand())
|
||||||
.subcommand(repl_subcommand())
|
.subcommand(repl_subcommand())
|
||||||
|
@ -995,6 +1005,36 @@ The installation root is determined, in order of precedence:
|
||||||
These must be added to the path manually if required.")
|
These must be added to the path manually if required.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uninstall_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
SubCommand::with_name("uninstall")
|
||||||
|
.setting(AppSettings::TrailingVarArg)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("name")
|
||||||
|
.required(true)
|
||||||
|
.multiple(false)
|
||||||
|
.allow_hyphen_values(true))
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("root")
|
||||||
|
.long("root")
|
||||||
|
.help("Installation root")
|
||||||
|
.takes_value(true)
|
||||||
|
.multiple(false))
|
||||||
|
.about("Uninstall a script previously installed with deno install")
|
||||||
|
.long_about(
|
||||||
|
"Uninstalls an executable script in the installation root's bin directory.
|
||||||
|
|
||||||
|
deno uninstall serve
|
||||||
|
|
||||||
|
To change the installation root, use --root:
|
||||||
|
|
||||||
|
deno uninstall --root /usr/local serve
|
||||||
|
|
||||||
|
The installation root is determined, in order of precedence:
|
||||||
|
- --root option
|
||||||
|
- DENO_INSTALL_ROOT environment variable
|
||||||
|
- $HOME/.deno")
|
||||||
|
}
|
||||||
|
|
||||||
fn lsp_subcommand<'a, 'b>() -> App<'a, 'b> {
|
fn lsp_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
SubCommand::with_name("lsp")
|
SubCommand::with_name("lsp")
|
||||||
.about("Start the language server")
|
.about("Start the language server")
|
||||||
|
@ -1896,6 +1936,18 @@ fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uninstall_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
|
let root = if matches.is_present("root") {
|
||||||
|
let install_root = matches.value_of("root").unwrap();
|
||||||
|
Some(PathBuf::from(install_root))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = matches.value_of("name").unwrap().to_string();
|
||||||
|
flags.subcommand = DenoSubcommand::Uninstall(UninstallFlags { name, root });
|
||||||
|
}
|
||||||
|
|
||||||
fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) {
|
fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) {
|
||||||
flags.subcommand = DenoSubcommand::Lsp;
|
flags.subcommand = DenoSubcommand::Lsp;
|
||||||
}
|
}
|
||||||
|
|
10
cli/main.rs
10
cli/main.rs
|
@ -53,6 +53,7 @@ use crate::flags::LintFlags;
|
||||||
use crate::flags::ReplFlags;
|
use crate::flags::ReplFlags;
|
||||||
use crate::flags::RunFlags;
|
use crate::flags::RunFlags;
|
||||||
use crate::flags::TestFlags;
|
use crate::flags::TestFlags;
|
||||||
|
use crate::flags::UninstallFlags;
|
||||||
use crate::flags::UpgradeFlags;
|
use crate::flags::UpgradeFlags;
|
||||||
use crate::fmt_errors::PrettyJsError;
|
use crate::fmt_errors::PrettyJsError;
|
||||||
use crate::module_loader::CliModuleLoader;
|
use crate::module_loader::CliModuleLoader;
|
||||||
|
@ -487,6 +488,12 @@ async fn install_command(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn uninstall_command(
|
||||||
|
uninstall_flags: UninstallFlags,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
tools::installer::uninstall(uninstall_flags.name, uninstall_flags.root)
|
||||||
|
}
|
||||||
|
|
||||||
async fn lsp_command() -> Result<(), AnyError> {
|
async fn lsp_command() -> Result<(), AnyError> {
|
||||||
lsp::start().await
|
lsp::start().await
|
||||||
}
|
}
|
||||||
|
@ -1149,6 +1156,9 @@ fn get_subcommand(
|
||||||
DenoSubcommand::Install(install_flags) => {
|
DenoSubcommand::Install(install_flags) => {
|
||||||
install_command(flags, install_flags).boxed_local()
|
install_command(flags, install_flags).boxed_local()
|
||||||
}
|
}
|
||||||
|
DenoSubcommand::Uninstall(uninstall_flags) => {
|
||||||
|
uninstall_command(uninstall_flags).boxed_local()
|
||||||
|
}
|
||||||
DenoSubcommand::Lsp => lsp_command().boxed_local(),
|
DenoSubcommand::Lsp => lsp_command().boxed_local(),
|
||||||
DenoSubcommand::Lint(lint_flags) => {
|
DenoSubcommand::Lint(lint_flags) => {
|
||||||
lint_command(flags, lint_flags).boxed_local()
|
lint_command(flags, lint_flags).boxed_local()
|
||||||
|
|
|
@ -139,6 +139,57 @@ pub fn infer_name_from_url(url: &Url) -> Option<String> {
|
||||||
Some(stem)
|
Some(stem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn uninstall(name: String, root: Option<PathBuf>) -> Result<(), AnyError> {
|
||||||
|
let root = if let Some(root) = root {
|
||||||
|
canonicalize_path(&root)?
|
||||||
|
} else {
|
||||||
|
get_installer_root()?
|
||||||
|
};
|
||||||
|
let installation_dir = root.join("bin");
|
||||||
|
|
||||||
|
// ensure directory exists
|
||||||
|
if let Ok(metadata) = fs::metadata(&installation_dir) {
|
||||||
|
if !metadata.is_dir() {
|
||||||
|
return Err(generic_error("Installation path is not a directory"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file_path = installation_dir.join(&name);
|
||||||
|
|
||||||
|
let mut removed = false;
|
||||||
|
|
||||||
|
if file_path.exists() {
|
||||||
|
fs::remove_file(&file_path)?;
|
||||||
|
println!("deleted {}", file_path.to_string_lossy());
|
||||||
|
removed = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if cfg!(windows) {
|
||||||
|
file_path = file_path.with_extension("cmd");
|
||||||
|
if file_path.exists() {
|
||||||
|
fs::remove_file(&file_path)?;
|
||||||
|
println!("deleted {}", file_path.to_string_lossy());
|
||||||
|
removed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !removed {
|
||||||
|
return Err(generic_error(format!("No installation found for {}", name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There might be some extra files to delete
|
||||||
|
for ext in ["tsconfig.json", "lock.json"] {
|
||||||
|
file_path = file_path.with_extension(ext);
|
||||||
|
if file_path.exists() {
|
||||||
|
fs::remove_file(&file_path)?;
|
||||||
|
println!("deleted {}", file_path.to_string_lossy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("✅ Successfully uninstalled {}", name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn install(
|
pub fn install(
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
module_url: &str,
|
module_url: &str,
|
||||||
|
@ -926,4 +977,36 @@ mod tests {
|
||||||
let content = fs::read_to_string(file_path).unwrap();
|
let content = fs::read_to_string(file_path).unwrap();
|
||||||
assert!(content.contains(&expected_string));
|
assert!(content.contains(&expected_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uninstall_basic() {
|
||||||
|
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||||
|
let bin_dir = temp_dir.path().join("bin");
|
||||||
|
std::fs::create_dir(&bin_dir).unwrap();
|
||||||
|
|
||||||
|
let mut file_path = bin_dir.join("echo_test");
|
||||||
|
File::create(&file_path).unwrap();
|
||||||
|
if cfg!(windows) {
|
||||||
|
file_path = file_path.with_extension("cmd");
|
||||||
|
File::create(&file_path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create extra files
|
||||||
|
file_path = file_path.with_extension("tsconfig.json");
|
||||||
|
File::create(&file_path).unwrap();
|
||||||
|
file_path = file_path.with_extension("lock.json");
|
||||||
|
File::create(&file_path).unwrap();
|
||||||
|
|
||||||
|
uninstall("echo_test".to_string(), Some(temp_dir.path().to_path_buf()))
|
||||||
|
.expect("Uninstall failed");
|
||||||
|
|
||||||
|
assert!(!file_path.exists());
|
||||||
|
assert!(!file_path.with_extension("tsconfig.json").exists());
|
||||||
|
assert!(!file_path.with_extension("lock.json").exists());
|
||||||
|
|
||||||
|
if cfg!(windows) {
|
||||||
|
file_path = file_path.with_extension("cmd");
|
||||||
|
assert!(!file_path.exists());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue