Skip to content

Commit

Permalink
feat(rm): add oro rm command
Browse files Browse the repository at this point in the history
Fixes: #238
  • Loading branch information
zkat committed Apr 13, 2023
1 parent 7ed9f77 commit ec301bb
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 1 deletion.
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Expand Up @@ -17,6 +17,7 @@
- [apply](./commands/apply.md)
- [ping](./commands/ping.md)
- [reapply](./commands/reapply.md)
- [remove](./commands/remove.md)
- [view](./commands/view.md)

---
Expand Down
1 change: 1 addition & 0 deletions book/src/commands/remove.md
@@ -0,0 +1 @@
{{#include ../../../tests/snapshots/help__remove.snap:8:}}
2 changes: 1 addition & 1 deletion book/src/guide/node_modules.md
@@ -1,4 +1,4 @@
# Applying `node_modules/`
# Managing `node_modules/`

The whole point of Orogene is to manage `node_modules/` directories for
consumption by various tooling, such as Node.js, transpilers, bundlers,
Expand Down
1 change: 1 addition & 0 deletions src/commands/mod.rs
Expand Up @@ -5,6 +5,7 @@ pub mod add;
pub mod apply;
pub mod ping;
pub mod reapply;
pub mod remove;
pub mod view;

#[async_trait]
Expand Down
81 changes: 81 additions & 0 deletions src/commands/remove.rs
@@ -0,0 +1,81 @@
use async_trait::async_trait;
use clap::Args;
use miette::{IntoDiagnostic, Result};
use oro_pretty_json::Formatted;

use crate::apply_args::ApplyArgs;
use crate::commands::OroCommand;

/// Removes one or more dependencies to the target package.
#[derive(Debug, Args)]
#[clap(visible_aliases(["rm"]))]
pub struct RemoveCmd {
/// Package names of dependencies to remove. These will be removed from
/// all dependency types.
#[arg(required = true)]
names: Vec<String>,

#[command(flatten)]
apply: ApplyArgs,
}

#[async_trait]
impl OroCommand for RemoveCmd {
async fn execute(self) -> Result<()> {
let mut manifest = oro_pretty_json::from_str(
&async_std::fs::read_to_string(self.apply.root.join("package.json"))
.await
.into_diagnostic()?,
)
.into_diagnostic()?;
let mut count = 0;
for name in &self.names {
count += self.remove_from_manifest(&mut manifest, name);
}

async_std::fs::write(
self.apply.root.join("package.json"),
oro_pretty_json::to_string_pretty(&manifest).into_diagnostic()?,
)
.await
.into_diagnostic()?;

tracing::info!(
"{}Removed {count} dependencies from package.json.",
if self.apply.emoji { "📝 " } else { "" },
);

// TODO: Force locked = false here, once --locked is supported.
// Using `oro remove` with `--locked` doesn't make sense.
// self.apply.locked = false;

// Then, we apply the change.
self.apply.execute().await
}
}

impl RemoveCmd {
fn remove_from_manifest(&self, mani: &mut Formatted, name: &str) -> usize {
let mut count = 0;
for ty in [
"dependencies",
"devDependencies",
"optionalDependencies",
"peerDependencies",
] {
if mani.value[ty].is_object() {
if let Some(obj) = mani.value[ty].as_object_mut() {
if obj.contains_key(name) {
tracing::debug!(
"Removing {name}@{} from {ty}.",
obj[name].as_str().unwrap_or("")
);
obj.remove(name);
count += 1;
}
}
}
}
count
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Expand Up @@ -444,6 +444,8 @@ pub enum OroCmd {

Reapply(commands::reapply::ReapplyCmd),

Remove(commands::remove::RemoveCmd),

View(commands::view::ViewCmd),

#[clap(hide = true)]
Expand All @@ -459,6 +461,7 @@ impl OroCommand for Orogene {
OroCmd::Apply(cmd) => cmd.execute().await,
OroCmd::Ping(cmd) => cmd.execute().await,
OroCmd::Reapply(cmd) => cmd.execute().await,
OroCmd::Remove(cmd) => cmd.execute().await,
OroCmd::View(cmd) => cmd.execute().await,
OroCmd::HelpMarkdown(cmd) => cmd.execute().await,
}
Expand Down
5 changes: 5 additions & 0 deletions tests/help.rs
Expand Up @@ -22,6 +22,11 @@ fn reapply_markdown() {
insta::assert_snapshot!("reapply", sub_md("reapply"));
}

#[test]
fn remove_markdown() {
insta::assert_snapshot!("remove", sub_md("remove"));
}

#[test]
fn view_markdown() {
insta::assert_snapshot!("view", sub_md("view"));
Expand Down
8 changes: 8 additions & 0 deletions tests/snapshots/help__add.snap
Expand Up @@ -23,6 +23,14 @@ Specifiers for packages to add
### Options
#### `--prefix <PREFIX>`
Prefix to prepend to package versions for resolved NPM dependencies.
For example, if you do `oro add foo@1.2.3 --prefix ~`, this will write `"foo": "~1.2.3"` to your `package.json`.
\[default: ^]
#### `-D, --dev`
Add packages as devDependencies
Expand Down
158 changes: 158 additions & 0 deletions tests/snapshots/help__remove.snap
@@ -0,0 +1,158 @@
---
source: tests/help.rs
expression: "sub_md(\"remove\")"
---
stderr:

stdout:
# oro remove

Removes one or more dependencies to the target package

### Usage:

```
oro remove [OPTIONS] <NAMES>...
```
[alias: rm]
### Arguments
#### `<NAMES>...`
Package names of dependencies to remove. These will be removed from all dependency types
### Options
#### `-h, --help`
Print help (see a summary with '-h')
#### `-V, --version`
Print version
### Apply Options
#### `--no-apply`
Prevent all apply operations from executing
#### `--prefer-copy`
When extracting packages, prefer to copy files files instead of linking them.
This option has no effect if hard linking fails (for example, if the cache is on a different drive), or if the project is on a filesystem that supports Copy-on-Write (zfs, btrfs, APFS (macOS), etc).
#### `--validate`
Validate the integrity of installed files.
When this is true, orogene will verify all files extracted from the cache, as well as verify that any files in the existing `node_modules` are unmodified. If verification fails, the packages will be reinstalled.
#### `--lockfile-only`
Whether to skip restoring packages into `node_modules` and just resolve the tree and write the lockfile
#### `--no-scripts`
Skip running install scripts
#### `--default-tag <DEFAULT_TAG>`
Default dist-tag to use when resolving package versions
\[default: latest]
#### `--concurrency <CONCURRENCY>`
Controls number of concurrent operations during various apply steps (resolution fetches, extractions, etc).
Tuning this might help reduce memory usage (if lowered), or improve performance (if increased).
\[default: 50]
#### `--script-concurrency <SCRIPT_CONCURRENCY>`
Controls number of concurrent script executions while running `run_script`.
This option is separate from `concurrency` because executing concurrent scripts is a much heavier operation.
\[default: 6]
#### `--no-lockfile`
Disable writing the lockfile after operations complete.
Note that lockfiles are only written after all operations complete successfully.
#### `--hoisted`
Use the hoisted installation mode, where all dependencies and their transitive dependencies are installed as high up in the `node_modules` tree as possible.
This can potentially mean that packages have access to dependencies they did not specify in their package.json, but it might be useful for compatibility.
By default, dependencies are installed in "isolated" mode, using a symlink/junction structure to simulate a dependency tree.
### Global Options
#### `--root <ROOT>`
Path to the project to operate on.
By default, Orogene will look up from the current working directory until it finds a directory with a `package.json` file or a `node_modules/` directory.
\[default: .]
#### `--registry <REGISTRY>`
Registry used for unscoped packages
\[default: https://registry.npmjs.org]
#### `--scoped-registry <SCOPED_REGISTRIES>`
Registry to use for a specific `@scope`, using `--scoped-registry @scope=https://foo.com` format.
Can be provided multiple times to specify multiple scoped registries.
#### `--cache <CACHE>`
Location of disk cache.
Default location varies by platform.
#### `--config <CONFIG>`
File to read configuration values from.
When specified, global configuration loading is disabled and configuration values will only be read from this location.
#### `--loglevel <LOGLEVEL>`
Log output level/directive.
Supports plain loglevels (off, error, warn, info, debug, trace) as well as more advanced directives in the format `target[span{field=value}]=level`.
\[default: info]
#### `-q, --quiet`
Disable all output
#### `--json`
Format output as JSON
#### `--no-progress`
Disable the progress bars
#### `--no-emoji`
Disable printing emoji.
By default, this will show emoji when outputting to a TTY that supports unicode.

0 comments on commit ec301bb

Please sign in to comment.