Skip to content

Commit

Permalink
Ports cargo-no-dev-deps's --no-private flag
Browse files Browse the repository at this point in the history
Closes #185
Closes #187
  • Loading branch information
taiki-e committed Aug 28, 2023
1 parent 0e73a9c commit 90dc055
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 93 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com

## [Unreleased]

- Add `--no-private` flag to exclude `publish = false` crates.

This flag is more powerful than [`--ignore-private` flag](https://github.com/taiki-e/cargo-hack#--ignore-private), which also prevents private crate from affecting dependency resolution.

- Restore `Cargo.lock` after run to match behavior with [cargo-minimal-versions](https://github.com/taiki-e/cargo-minimal-versions) and [cargo-no-dev-deps](https://github.com/taiki-e/cargo-no-dev-deps), when `--no-dev-deps`, `--remove-dev-deps`, or `--no-private` is used.

## [0.5.29] - 2023-08-06

- Documentation improvements.
Expand Down
5 changes: 5 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub(crate) struct Args {
pub(crate) no_dev_deps: bool,
/// --remove-dev-deps
pub(crate) remove_dev_deps: bool,
/// --no-private
pub(crate) no_private: bool,
/// --ignore-private
pub(crate) ignore_private: bool,
/// --ignore-unknown-features
Expand Down Expand Up @@ -136,6 +138,7 @@ impl Args {
let mut remove_dev_deps = false;
let mut each_feature = false;
let mut feature_powerset = false;
let mut no_private = false;
let mut ignore_private = false;
let mut ignore_unknown_features = false;
let mut clean_per_run = false;
Expand Down Expand Up @@ -274,6 +277,7 @@ impl Args {
Long("remove-dev-deps") => parse_flag!(remove_dev_deps),
Long("each-feature") => parse_flag!(each_feature),
Long("feature-powerset") => parse_flag!(feature_powerset),
Long("no-private") => parse_flag!(no_private),
Long("ignore-private") => parse_flag!(ignore_private),
Long("exclude-no-default-features") => parse_flag!(exclude_no_default_features),
Long("exclude-all-features") => parse_flag!(exclude_all_features),
Expand Down Expand Up @@ -553,6 +557,7 @@ impl Args {
feature_powerset,
no_dev_deps,
remove_dev_deps,
no_private,
ignore_private,
ignore_unknown_features,
optional_deps,
Expand Down
155 changes: 72 additions & 83 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,98 +48,87 @@ fn main() {
fn try_main() -> Result<()> {
let cx = &Context::new()?;

exec_on_workspace(cx)
}

fn exec_on_workspace(cx: &Context) -> Result<()> {
let restore_handles = if cx.no_dev_deps || cx.remove_dev_deps {
let mut restore_handles = Vec::with_capacity(cx.metadata.workspace_members.len());
for id in &cx.metadata.workspace_members {
let manifest_path = &cx.packages(id).manifest_path;
let manifest = cx.manifests(id);
let doc = manifest.remove_dev_deps();
restore_handles.push(cx.restore.register(&manifest.raw, manifest_path));
if term::verbose() {
info!("removing dev-dependencies from {}", manifest_path.display());
}
fs::write(manifest_path, doc)?;
manifest::with(cx, || {
if cx.subcommand.is_none() {
return Ok(());
}
restore_handles
} else {
vec![]
};

if cx.subcommand.is_none() {
// Restore original Cargo.toml and Cargo.lock.
drop(restore_handles);
return Ok(());
}

let mut progress = Progress::default();
let packages = determine_package_list(cx, &mut progress)?;
let mut keep_going = KeepGoing::default();
if let Some(range) = &cx.version_range {
let total = progress.total;
progress.total = 0;
for (cargo_version, _) in range {
if cx.target.is_empty() || *cargo_version >= 64 {
progress.total += total;
} else {
progress.total += total * cx.target.len();
}
}
let line = cmd!("cargo");
{
// First, generate the lockfile using the oldest cargo specified.
// https://github.com/taiki-e/cargo-hack/issues/105
let toolchain = &range[0].1;
rustup::install_toolchain(toolchain, &cx.target, true)?;
let mut line = line.clone();
line.leading_arg(toolchain);
line.arg("generate-lockfile");
if let Some(pid) = cx.current_package() {
let package = cx.packages(pid);
if !cx.no_manifest_path {
line.arg("--manifest-path");
line.arg(
package
.manifest_path
.strip_prefix(&cx.current_dir)
.unwrap_or(&package.manifest_path),
);
let mut progress = Progress::default();
let packages = determine_package_list(cx, &mut progress)?;
let mut keep_going = KeepGoing::default();
if let Some(range) = &cx.version_range {
let total = progress.total;
progress.total = 0;
for (cargo_version, _) in range {
if cx.target.is_empty() || *cargo_version >= 64 {
progress.total += total;
} else {
progress.total += total * cx.target.len();
}
}
line.run_with_output()?;
}

range.iter().enumerate().try_for_each(|(i, (cargo_version, toolchain))| {
if i != 0 {
let line = cmd!("cargo");
{
// First, generate the lockfile using the oldest cargo specified.
// https://github.com/taiki-e/cargo-hack/issues/105
let toolchain = &range[0].1;
rustup::install_toolchain(toolchain, &cx.target, true)?;
let mut line = line.clone();
line.leading_arg(toolchain);
line.arg("generate-lockfile");
if let Some(pid) = cx.current_package() {
let package = cx.packages(pid);
if !cx.no_manifest_path {
line.arg("--manifest-path");
line.arg(
package
.manifest_path
.strip_prefix(&cx.current_dir)
.unwrap_or(&package.manifest_path),
);
}
}
line.run_with_output()?;
}

if cx.clean_per_version {
cargo_clean(cx, None)?;
}

let mut line = line.clone();
line.leading_arg(toolchain);
line.apply_context(cx);
exec_on_packages(cx, &packages, line, &mut progress, &mut keep_going, *cargo_version)
})?;
} else {
let mut line = cx.cargo();
line.apply_context(cx);
exec_on_packages(cx, &packages, line, &mut progress, &mut keep_going, cx.cargo_version)?;
}
if keep_going.count > 0 {
eprintln!();
error!("{keep_going}");
}
range.iter().enumerate().try_for_each(|(i, (cargo_version, toolchain))| {
if i != 0 {
rustup::install_toolchain(toolchain, &cx.target, true)?;
}

// Restore original Cargo.toml and Cargo.lock.
drop(restore_handles);
if cx.clean_per_version {
cargo_clean(cx, None)?;
}

Ok(())
let mut line = line.clone();
line.leading_arg(toolchain);
line.apply_context(cx);
exec_on_packages(
cx,
&packages,
line,
&mut progress,
&mut keep_going,
*cargo_version,
)
})?;
} else {
let mut line = cx.cargo();
line.apply_context(cx);
exec_on_packages(
cx,
&packages,
line,
&mut progress,
&mut keep_going,
cx.cargo_version,
)?;
}
if keep_going.count > 0 {
eprintln!();
error!("{keep_going}");
}
Ok(())
})
}

#[derive(Default)]
Expand Down
126 changes: 117 additions & 9 deletions src/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
use std::{collections::BTreeMap, path::Path};
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
};

use anyhow::{format_err, Context as _, Result};
use anyhow::{bail, format_err, Context as _, Result};

use crate::{fs, metadata::Metadata};
use crate::{
context::Context,
fs,
metadata::{self, Metadata},
term,
};

type ParseResult<T> = Result<T, &'static str>;

Expand All @@ -29,12 +37,6 @@ impl Manifest {
})?;
Ok(Self { raw, doc, package, features })
}

pub(crate) fn remove_dev_deps(&self) -> String {
let mut doc = self.doc.clone();
remove_dev_deps(&mut doc);
doc.to_string()
}
}

pub(crate) struct Package {
Expand Down Expand Up @@ -100,6 +102,85 @@ impl Features {
}
}

pub(crate) fn with(cx: &Context, f: impl FnOnce() -> Result<()>) -> Result<()> {
// TODO: provide option to keep updated Cargo.lock
let restore_lockfile = true;
let no_dev_deps = cx.no_dev_deps | cx.remove_dev_deps;
let no_private = cx.no_private;
let restore_handles = if no_dev_deps || no_private {
let mut restore_handles = Vec::with_capacity(cx.metadata.workspace_members.len());
let workspace_root = &cx.metadata.workspace_root;
let root_manifest = &workspace_root.join("Cargo.toml");
let mut has_root_crate = false;
let mut root_id = None;
let mut private_crates = vec![];
for id in &cx.metadata.workspace_members {
let package = cx.packages(id);
let manifest_path = &package.manifest_path;
let is_root = manifest_path == root_manifest;
if is_root {
root_id = Some(id);
}
has_root_crate |= is_root;
let is_private = cx.is_private(id);
if is_private && no_private {
if is_root {
bail!(
"--no-private is not supported yet with workspace with private root crate"
);
}
private_crates.push(manifest_path);
} else if is_root && no_private {
//
} else if no_dev_deps {
let manifest = cx.manifests(id);
let mut doc = manifest.doc.clone();
if term::verbose() {
info!("removing dev-dependencies from {}", manifest_path.display());
}
remove_dev_deps(&mut doc);
restore_handles.push(cx.restore.register(&manifest.raw, manifest_path));
fs::write(manifest_path, doc.to_string())?;
}
}
if no_private && (no_dev_deps && has_root_crate || !private_crates.is_empty()) {
let manifest_path = root_manifest;
let manifest = cx.manifests(root_id.unwrap());
let mut doc = manifest.doc.clone();
if no_dev_deps && has_root_crate {
if term::verbose() {
info!("removing dev-dependencies from {}", manifest_path.display());
}
remove_dev_deps(&mut doc);
}
if !private_crates.is_empty() {
if term::verbose() {
info!("removing private crates from {}", manifest_path.display());
}
remove_private_crates(&mut doc, &cx.metadata, &private_crates)?;
}
restore_handles.push(cx.restore.register(&manifest.raw, manifest_path));
fs::write(manifest_path, doc.to_string())?;
}
if restore_lockfile {
let lockfile = &cx.metadata.workspace_root.join("Cargo.lock");
if lockfile.exists() {
restore_handles.push(cx.restore.register(fs::read_to_string(lockfile)?, lockfile));
}
}
restore_handles
} else {
vec![]
};

f()?;

// Restore original Cargo.toml and Cargo.lock.
drop(restore_handles);

Ok(())
}

fn remove_dev_deps(doc: &mut toml_edit::Document) {
const KEY: &str = "dev-dependencies";
let table = doc.as_table_mut();
Expand All @@ -113,6 +194,33 @@ fn remove_dev_deps(doc: &mut toml_edit::Document) {
}
}

fn remove_private_crates(
doc: &mut toml_edit::Document,
metadata: &metadata::Metadata,
private_crates: &[&PathBuf],
) -> Result<()> {
let table = doc.as_table_mut();
if let Some(workspace) = table.get_mut("workspace").and_then(toml_edit::Item::as_table_like_mut)
{
if let Some(members) = workspace.get_mut("members").and_then(toml_edit::Item::as_array_mut)
{
let mut i = 0;
while i < members.len() {
if let Some(member) = members.get(i).and_then(toml_edit::Value::as_str) {
let manifest_path =
metadata.workspace_root.join(member).join("Cargo.toml").canonicalize()?;
if private_crates.iter().any(|p| **p == manifest_path) {
members.remove(i);
continue;
}
}
i += 1;
}
}
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::remove_dev_deps;
Expand Down
2 changes: 1 addition & 1 deletion src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{term, Context, PackageId};

macro_rules! cmd {
($program:expr $(, $arg:expr)* $(,)?) => {{
let mut _cmd = crate::process::ProcessBuilder::new($program);
let mut _cmd = $crate::process::ProcessBuilder::new($program);
$(
_cmd.arg($arg);
)*
Expand Down

0 comments on commit 90dc055

Please sign in to comment.