Skip to main content

cargo_rename/
lib.rs

1//! `cargo-rename` performs a coordinated, all-or-nothing rename of a Cargo
2//! package.
3//!
4//! It handles the necessary updates across Cargo.toml, source code, and the
5//! file system to ensure the project remains compilable. This includes:
6//!
7//! - **Manifests**: Updating `[package].name` and dependency entries in the workspace.
8//! - **Source Code**: Rewriting `use` statements and qualified paths.
9//! - **Filesystem**: Optionally moving the package directory to match the new name.
10//!
11//! **Safety**
12//!
13//! All changes execute inside a transaction. Every file write and directory move is
14//! tracked. If any step fails, the project is automatically restored to its exact
15//! previous state
16//!
17//!
18//! ## Installation
19//!
20//! ```bash
21//! cargo install cargo-rename
22//! ```
23//!
24//! ## Usage
25//!
26//! ```bash
27//! # Rename the package name only (directory stays the same)
28//! cargo rename old-crate new-crate
29//!
30//! # Move the package directory only (package name unchanged)
31//! cargo rename old-crate --move new-location
32//!
33//! # Rename both package name and move directory
34//! cargo rename old-crate new-crate --move new-location
35//!
36//! # Move to a different directory with the new package name
37//! cargo rename old-crate new-crate --move
38//!
39//! # Move to a nested path
40//! cargo rename old-crate --move libs/core/new-crate
41//!
42//! # Preview changes without writing anything
43//! cargo rename old-crate new-crate --dry-run
44//!
45//! # Skip confirmation prompt
46//! cargo rename old-crate new-crate --yes
47//!
48//! # Allow operation with uncommitted git changes
49//! cargo rename old-crate new-crate --allow-dirty
50//! ```
51//!
52//! ## CLI Reference
53//!
54//! ```bash
55//! Usage: cargo rename [OPTIONS] <OLD_NAME> [NEW_NAME]
56//!
57//! Arguments:
58//!   <OLD_NAME>  Current name of the package
59//!   [NEW_NAME]  New name for the package (optional if only moving)
60//!
61//! Options:
62//!       --move [<DIR>]          Move the package to a new directory
63//!       --manifest-path <PATH>  Path to workspace Cargo.toml
64//!   -n, --dry-run               Preview changes without applying them
65//!   -y, --yes                   Skip interactive confirmation
66//!       --allow-dirty           Allow operation with uncommitted git changes
67//!       --color <WHEN>          Control color output [default: auto] [possible values:
68//!                               auto, always, never]
69//!   -q, --quiet...              Decrease logging verbosity
70//!   -v, --verbose...            Increase logging verbosity (-v, -vv, -vvv)
71//!   -h, --help                  Print help (see more with '--help')
72//!   -V, --version               Print version
73//! ```
74//!
75//! ## Library Usage
76//!
77//! You can also use `cargo-rename` programmatically.
78//!
79//! ```no_run
80//! use cargo_rename::{execute, RenameArgs};
81//! use std::path::PathBuf;
82//!
83//! # fn main() -> cargo_rename::Result<()> {
84//! let args = RenameArgs {
85//!     old_name: "old-crate".into(),
86//!     new_name: Some("new-crate".into()),
87//!     outdir: Some(Some(PathBuf::from("libs/new-crate"))),
88//!     manifest_path: None,
89//!     dry_run: false,
90//!     skip_confirmation: true,
91//!     allow_dirty: false,
92//! };
93//!
94//! execute(args)?;
95//! # Ok(())
96//! # }
97//! ```
98//!
99//! ## Safety Checks
100//!
101//! By default, the tool enforces these checks before running:
102//! - `cargo metadata` must resolve successfully.
103//! - The new name must be a valid crate name.
104//! - The git working directory must be clean.
105//!
106//! ## Scope and Limitations
107//!
108//! - **Binaries**: `[[bin]]` targets are not renamed to preserve binary compatibility.
109//! - **Macros**: Identifiers generated dynamically inside macros may not be detected.
110
111pub mod cli;
112pub mod error;
113pub mod steps;
114
115// Internal modules
116pub mod cargo;
117pub mod fs;
118pub mod rewrite;
119pub mod verify;
120
121pub use error::{RenameError, Result};
122pub use steps::rename::{RenameArgs, execute};
123
124use clap::Parser;
125use log::LevelFilter;
126
127pub const VERSION: &str = env!("CARGO_PKG_VERSION");
128
129/// Main entry point.
130///
131/// Parses CLI args, sets up logging, and executes the rename.
132pub fn run() -> Result<()> {
133    let cargo_args = cli::CargoCli::parse();
134
135    setup_logging(cargo_args.verbose, cargo_args.quiet);
136    setup_colors(cargo_args.color);
137
138    match cargo_args.command {
139        cli::CargoCommand::Rename(args) => steps::rename::execute(args),
140    }
141}
142
143/// Configures logging verbosity.
144///
145/// Levels: `-v` (warn), `-vv` (info), `-vvv` (debug), `-vvvv` (trace), `-q` (off).
146fn setup_logging(verbose: u8, quiet: u8) {
147    let log_level = if quiet > 0 {
148        LevelFilter::Off
149    } else {
150        match verbose {
151            0 => LevelFilter::Error,
152            1 => LevelFilter::Warn,
153            2 => LevelFilter::Info,
154            3 => LevelFilter::Debug,
155            _ => LevelFilter::Trace,
156        }
157    };
158
159    env_logger::Builder::new()
160        .filter_level(log_level)
161        .format_timestamp(None)
162        .init();
163}
164
165/// Configures colored output.
166fn setup_colors(choice: clap::ColorChoice) {
167    use colored::control;
168
169    match choice {
170        clap::ColorChoice::Always => control::set_override(true),
171        clap::ColorChoice::Never => control::set_override(false),
172        clap::ColorChoice::Auto => {} // colored crate handles automatically
173    }
174}