mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 04:51:22 +00:00
feat: deno remove (#24952)
Co-authored-by: Satya Rohith <me@satyarohith.com>
This commit is contained in:
parent
b1036e4d9c
commit
085058cfff
@ -83,6 +83,11 @@ pub struct AddFlags {
|
|||||||
pub packages: Vec<String>,
|
pub packages: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
pub struct RemoveFlags {
|
||||||
|
pub packages: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct BenchFlags {
|
pub struct BenchFlags {
|
||||||
pub files: FileFlags,
|
pub files: FileFlags,
|
||||||
@ -428,6 +433,7 @@ pub struct HelpFlags {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum DenoSubcommand {
|
pub enum DenoSubcommand {
|
||||||
Add(AddFlags),
|
Add(AddFlags),
|
||||||
|
Remove(RemoveFlags),
|
||||||
Bench(BenchFlags),
|
Bench(BenchFlags),
|
||||||
Bundle(BundleFlags),
|
Bundle(BundleFlags),
|
||||||
Cache(CacheFlags),
|
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() {
|
if let Some((subcommand, mut m)) = matches.remove_subcommand() {
|
||||||
match subcommand.as_str() {
|
match subcommand.as_str() {
|
||||||
"add" => add_parse(&mut flags, &mut m),
|
"add" => add_parse(&mut flags, &mut m),
|
||||||
|
"remove" => remove_parse(&mut flags, &mut m),
|
||||||
"bench" => bench_parse(&mut flags, &mut m),
|
"bench" => bench_parse(&mut flags, &mut m),
|
||||||
"bundle" => bundle_parse(&mut flags, &mut m),
|
"bundle" => bundle_parse(&mut flags, &mut m),
|
||||||
"cache" => cache_parse(&mut flags, &mut m),
|
"cache" => cache_parse(&mut flags, &mut m),
|
||||||
@ -1442,6 +1449,7 @@ pub fn clap_root() -> Command {
|
|||||||
.defer(|cmd| {
|
.defer(|cmd| {
|
||||||
let cmd = cmd
|
let cmd = cmd
|
||||||
.subcommand(add_subcommand())
|
.subcommand(add_subcommand())
|
||||||
|
.subcommand(remove_subcommand())
|
||||||
.subcommand(bench_subcommand())
|
.subcommand(bench_subcommand())
|
||||||
.subcommand(bundle_subcommand())
|
.subcommand(bundle_subcommand())
|
||||||
.subcommand(cache_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 {
|
fn bench_subcommand() -> Command {
|
||||||
Command::new("bench")
|
Command::new("bench")
|
||||||
.about(
|
.about(
|
||||||
@ -3726,6 +3759,12 @@ fn add_parse_inner(
|
|||||||
AddFlags { packages }
|
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) {
|
fn bench_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
flags.type_check_mode = TypeCheckMode::Local;
|
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]
|
#[test]
|
||||||
fn run_with_frozen_lockfile() {
|
fn run_with_frozen_lockfile() {
|
||||||
let cases = [
|
let cases = [
|
||||||
|
@ -355,7 +355,7 @@ impl CliFactory {
|
|||||||
let fs = self.fs();
|
let fs = self.fs();
|
||||||
let cli_options = self.cli_options()?;
|
let cli_options = self.cli_options()?;
|
||||||
// For `deno install` we want to force the managed resolver so it can set up `node_modules/` directory.
|
// 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 {
|
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||||
fs: fs.clone(),
|
fs: fs.clone(),
|
||||||
root_node_modules_dir: Some(match cli_options.node_modules_dir_path() {
|
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 {
|
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
|
||||||
tools::registry::add(flags, add_flags, tools::registry::AddCommandName::Add).await
|
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 {
|
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
|
||||||
if bench_flags.watch.is_some() {
|
if bench_flags.watch.is_some() {
|
||||||
tools::bench::run_benchmarks_with_watch(flags, bench_flags).await
|
tools::bench::run_benchmarks_with_watch(flags, bench_flags).await
|
||||||
|
@ -64,6 +64,7 @@ mod unfurl;
|
|||||||
use auth::get_auth_method;
|
use auth::get_auth_method;
|
||||||
use auth::AuthMethod;
|
use auth::AuthMethod;
|
||||||
pub use pm::add;
|
pub use pm::add;
|
||||||
|
pub use pm::remove;
|
||||||
pub use pm::AddCommandName;
|
pub use pm::AddCommandName;
|
||||||
use publish_order::PublishOrderGraph;
|
use publish_order::PublishOrderGraph;
|
||||||
use unfurl::SpecifierUnfurler;
|
use unfurl::SpecifierUnfurler;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ use jsonc_parser::ast::Value;
|
|||||||
use crate::args::AddFlags;
|
use crate::args::AddFlags;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
|
use crate::args::RemoveFlags;
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
use crate::jsr::JsrFetchResolver;
|
use crate::jsr::JsrFetchResolver;
|
||||||
@ -337,9 +339,7 @@ pub async fn add(
|
|||||||
// make a new CliFactory to pick up the updated config file
|
// make a new CliFactory to pick up the updated config file
|
||||||
let cli_factory = CliFactory::from_flags(flags);
|
let cli_factory = CliFactory::from_flags(flags);
|
||||||
// cache deps
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -513,6 +513,85 @@ fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
|
|||||||
contents.join("\n")
|
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(
|
fn update_config_file_content(
|
||||||
obj: jsonc_parser::ast::Object,
|
obj: jsonc_parser::ast::Object,
|
||||||
config_file_contents: &str,
|
config_file_contents: &str,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"args": "add npm:ajv@latest",
|
"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 New Issue
Block a user