mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: deno remove (#24952)
Co-authored-by: Satya Rohith <me@satyarohith.com>
This commit is contained in:
parent
b1036e4d9c
commit
085058cfff
12 changed files with 229 additions and 5 deletions
|
@ -83,6 +83,11 @@ pub struct AddFlags {
|
|||
pub packages: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct RemoveFlags {
|
||||
pub packages: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct BenchFlags {
|
||||
pub files: FileFlags,
|
||||
|
@ -428,6 +433,7 @@ pub struct HelpFlags {
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DenoSubcommand {
|
||||
Add(AddFlags),
|
||||
Remove(RemoveFlags),
|
||||
Bench(BenchFlags),
|
||||
Bundle(BundleFlags),
|
||||
Cache(CacheFlags),
|
||||
|
@ -1216,6 +1222,7 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
|
|||
if let Some((subcommand, mut m)) = matches.remove_subcommand() {
|
||||
match subcommand.as_str() {
|
||||
"add" => add_parse(&mut flags, &mut m),
|
||||
"remove" => remove_parse(&mut flags, &mut m),
|
||||
"bench" => bench_parse(&mut flags, &mut m),
|
||||
"bundle" => bundle_parse(&mut flags, &mut m),
|
||||
"cache" => cache_parse(&mut flags, &mut m),
|
||||
|
@ -1442,6 +1449,7 @@ pub fn clap_root() -> Command {
|
|||
.defer(|cmd| {
|
||||
let cmd = cmd
|
||||
.subcommand(add_subcommand())
|
||||
.subcommand(remove_subcommand())
|
||||
.subcommand(bench_subcommand())
|
||||
.subcommand(bundle_subcommand())
|
||||
.subcommand(cache_subcommand())
|
||||
|
@ -1515,6 +1523,31 @@ You can add multiple dependencies at once:
|
|||
})
|
||||
}
|
||||
|
||||
fn remove_subcommand() -> Command {
|
||||
Command::new("remove")
|
||||
.alias("rm")
|
||||
.about("Remove dependencies")
|
||||
.long_about(
|
||||
"Remove dependencies from the configuration file.
|
||||
|
||||
deno remove @std/path
|
||||
|
||||
You can remove multiple dependencies at once:
|
||||
|
||||
deno remove @std/path @std/assert
|
||||
",
|
||||
)
|
||||
.defer(|cmd| {
|
||||
cmd.arg(
|
||||
Arg::new("packages")
|
||||
.help("List of packages to remove")
|
||||
.required(true)
|
||||
.num_args(1..)
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn bench_subcommand() -> Command {
|
||||
Command::new("bench")
|
||||
.about(
|
||||
|
@ -3726,6 +3759,12 @@ fn add_parse_inner(
|
|||
AddFlags { packages }
|
||||
}
|
||||
|
||||
fn remove_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||
flags.subcommand = DenoSubcommand::Remove(RemoveFlags {
|
||||
packages: matches.remove_many::<String>("packages").unwrap().collect(),
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||
flags.type_check_mode = TypeCheckMode::Local;
|
||||
|
||||
|
@ -10247,6 +10286,35 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_subcommand() {
|
||||
let r = flags_from_vec(svec!["deno", "remove"]);
|
||||
r.unwrap_err();
|
||||
|
||||
let r = flags_from_vec(svec!["deno", "remove", "@david/which"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Remove(RemoveFlags {
|
||||
packages: svec!["@david/which"],
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r =
|
||||
flags_from_vec(svec!["deno", "remove", "@david/which", "@luca/hello"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Remove(RemoveFlags {
|
||||
packages: svec!["@david/which", "@luca/hello"],
|
||||
}),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_with_frozen_lockfile() {
|
||||
let cases = [
|
||||
|
|
|
@ -355,7 +355,7 @@ impl CliFactory {
|
|||
let fs = self.fs();
|
||||
let cli_options = self.cli_options()?;
|
||||
// For `deno install` we want to force the managed resolver so it can set up `node_modules/` directory.
|
||||
create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_)) {
|
||||
create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_) | DenoSubcommand::Remove(_)) {
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: fs.clone(),
|
||||
root_node_modules_dir: Some(match cli_options.node_modules_dir_path() {
|
||||
|
|
|
@ -100,6 +100,9 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
|
||||
tools::registry::add(flags, add_flags, tools::registry::AddCommandName::Add).await
|
||||
}),
|
||||
DenoSubcommand::Remove(remove_flags) => spawn_subcommand(async {
|
||||
tools::registry::remove(flags, remove_flags).await
|
||||
}),
|
||||
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
|
||||
if bench_flags.watch.is_some() {
|
||||
tools::bench::run_benchmarks_with_watch(flags, bench_flags).await
|
||||
|
|
|
@ -64,6 +64,7 @@ mod unfurl;
|
|||
use auth::get_auth_method;
|
||||
use auth::AuthMethod;
|
||||
pub use pm::add;
|
||||
pub use pm::remove;
|
||||
pub use pm::AddCommandName;
|
||||
use publish_order::PublishOrderGraph;
|
||||
use unfurl::SpecifierUnfurler;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -23,6 +24,7 @@ use jsonc_parser::ast::Value;
|
|||
use crate::args::AddFlags;
|
||||
use crate::args::CacheSetting;
|
||||
use crate::args::Flags;
|
||||
use crate::args::RemoveFlags;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::jsr::JsrFetchResolver;
|
||||
|
@ -337,9 +339,7 @@ pub async fn add(
|
|||
// make a new CliFactory to pick up the updated config file
|
||||
let cli_factory = CliFactory::from_flags(flags);
|
||||
// cache deps
|
||||
if cli_factory.cli_options()?.enable_future_features() {
|
||||
crate::module_loader::load_top_level_deps(&cli_factory).await?;
|
||||
}
|
||||
crate::module_loader::load_top_level_deps(&cli_factory).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -513,6 +513,85 @@ fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
|
|||
contents.join("\n")
|
||||
}
|
||||
|
||||
fn remove_from_config(
|
||||
config_path: &Path,
|
||||
keys: &[&'static str],
|
||||
packages_to_remove: &[String],
|
||||
removed_packages: &mut Vec<String>,
|
||||
fmt_options: &FmtOptionsConfig,
|
||||
) -> Result<(), AnyError> {
|
||||
let mut json: serde_json::Value =
|
||||
serde_json::from_slice(&std::fs::read(config_path)?)?;
|
||||
for key in keys {
|
||||
let Some(obj) = json.get_mut(*key).and_then(|v| v.as_object_mut()) else {
|
||||
continue;
|
||||
};
|
||||
for package in packages_to_remove {
|
||||
if obj.shift_remove(package).is_some() {
|
||||
removed_packages.push(package.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let config = serde_json::to_string_pretty(&json)?;
|
||||
let config =
|
||||
crate::tools::fmt::format_json(config_path, &config, fmt_options)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(config);
|
||||
|
||||
std::fs::write(config_path, config)
|
||||
.context("Failed to update configuration file")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
flags: Arc<Flags>,
|
||||
remove_flags: RemoveFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
let (config_file, factory) = DenoOrPackageJson::from_flags(flags.clone())?;
|
||||
let options = factory.cli_options()?;
|
||||
let start_dir = &options.start_dir;
|
||||
let fmt_config_options = config_file.fmt_options();
|
||||
|
||||
let mut removed_packages = Vec::new();
|
||||
|
||||
if let Some(deno_json) = start_dir.maybe_deno_json() {
|
||||
remove_from_config(
|
||||
&deno_json.specifier.to_file_path().unwrap(),
|
||||
&["imports"],
|
||||
&remove_flags.packages,
|
||||
&mut removed_packages,
|
||||
&fmt_config_options,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
|
||||
remove_from_config(
|
||||
&pkg_json.path,
|
||||
&["dependencies", "devDependencies"],
|
||||
&remove_flags.packages,
|
||||
&mut removed_packages,
|
||||
&fmt_config_options,
|
||||
)?;
|
||||
}
|
||||
|
||||
if removed_packages.is_empty() {
|
||||
log::info!("No packages were removed");
|
||||
} else {
|
||||
for package in &removed_packages {
|
||||
log::info!("Removed {}", crate::colors::green(package));
|
||||
}
|
||||
// Update deno.lock
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
let cli_factory = CliFactory::from_flags(flags);
|
||||
crate::module_loader::load_top_level_deps(&cli_factory).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_config_file_content(
|
||||
obj: jsonc_parser::ast::Object,
|
||||
config_file_contents: &str,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"steps": [
|
||||
{
|
||||
"args": "add npm:ajv@latest",
|
||||
"output": "Add npm:ajv@8.11.0\n"
|
||||
"output": "add.out"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
15
tests/specs/add/dist_tag/add.out
Normal file
15
tests/specs/add/dist_tag/add.out
Normal file
|
@ -0,0 +1,15 @@
|
|||
Add npm:ajv@8.11.0
|
||||
[UNORDERED_START]
|
||||
Download http://localhost:4260/ajv
|
||||
Download http://localhost:4260/fast-deep-equal
|
||||
Download http://localhost:4260/json-schema-traverse
|
||||
Download http://localhost:4260/require-from-string
|
||||
Download http://localhost:4260/uri-js
|
||||
Download http://localhost:4260/punycode
|
||||
Download http://localhost:4260/ajv/ajv-8.11.0.tgz
|
||||
Download http://localhost:4260/require-from-string/require-from-string-2.0.2.tgz
|
||||
Download http://localhost:4260/uri-js/uri-js-4.4.1.tgz
|
||||
Download http://localhost:4260/fast-deep-equal/fast-deep-equal-3.1.3.tgz
|
||||
Download http://localhost:4260/json-schema-traverse/json-schema-traverse-1.0.0.tgz
|
||||
Download http://localhost:4260/punycode/punycode-2.1.1.tgz
|
||||
[UNORDERED_END]
|
16
tests/specs/remove/basic/__test__.jsonc
Normal file
16
tests/specs/remove/basic/__test__.jsonc
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"tempDir": true,
|
||||
"steps": [{
|
||||
"args": ["add", "@std/assert", "@std/http"],
|
||||
"output": "add.out"
|
||||
}, {
|
||||
"args": ["eval", "console.log(Deno.readTextFileSync('deno.lock').trim())"],
|
||||
"output": "add_lock.out"
|
||||
}, {
|
||||
"args": ["remove", "@std/assert", "@std/http"],
|
||||
"output": "rm.out"
|
||||
}, {
|
||||
"args": ["eval", "console.log(Deno.readTextFileSync('deno.lock').trim())"],
|
||||
"output": "remove_lock.out"
|
||||
}]
|
||||
}
|
12
tests/specs/remove/basic/add.out
Normal file
12
tests/specs/remove/basic/add.out
Normal file
|
@ -0,0 +1,12 @@
|
|||
Created deno.json configuration file.
|
||||
Add jsr:@std/assert@1.0.0
|
||||
Add jsr:@std/http@1.0.0
|
||||
[UNORDERED_START]
|
||||
Download http://127.0.0.1:4250/@std/http/1.0.0_meta.json
|
||||
Download http://127.0.0.1:4250/@std/assert/1.0.0_meta.json
|
||||
Download http://127.0.0.1:4250/@std/http/1.0.0/mod.ts
|
||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/mod.ts
|
||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/assert_equals.ts
|
||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/assert.ts
|
||||
Download http://127.0.0.1:4250/@std/assert/1.0.0/fail.ts
|
||||
[UNORDERED_END]
|
24
tests/specs/remove/basic/add_lock.out
Normal file
24
tests/specs/remove/basic/add_lock.out
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "3",
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"jsr:@std/assert@^1.0.0": "jsr:@std/assert@1.0.0",
|
||||
"jsr:@std/http@^1.0.0": "jsr:@std/http@1.0.0"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/assert@1.0.0": {
|
||||
"integrity": "7ae268c58de9693b4997fd93d9b303a47df336664e2008378ccb93c3458d092a"
|
||||
},
|
||||
"@std/http@1.0.0": {
|
||||
"integrity": "d75bd303c21123a9b58f7249e38b4c0aa3a09f7d76b13f9d7e7842d89052091a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"remote": {},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
"jsr:@std/assert@^1.0.0",
|
||||
"jsr:@std/http@^1.0.0"
|
||||
]
|
||||
}
|
||||
}
|
4
tests/specs/remove/basic/remove_lock.out
Normal file
4
tests/specs/remove/basic/remove_lock.out
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": "3",
|
||||
"remote": {}
|
||||
}
|
2
tests/specs/remove/basic/rm.out
Normal file
2
tests/specs/remove/basic/rm.out
Normal file
|
@ -0,0 +1,2 @@
|
|||
Removed @std/assert
|
||||
Removed @std/http
|
Loading…
Reference in a new issue