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}