Skip to content

Commit

Permalink
Update lift-to-workspace
Browse files Browse the repository at this point in the history
Signed-off-by: Oliver Tale-Yazdi <[email protected]>
  • Loading branch information
ggwpez committed Oct 24, 2023
1 parent 4a86988 commit 4eeaa3d
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 34 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ env_logger = { version = "0.10.0", features = [ "auto-color", "humantime" ], opt
log = { version = "0.4.20", optional = true }
serde = "1.0.189"
serde_json = "1.0.107"
semver = "1"
serde_yaml = "0.9.25"
tempfile = { version = "3.8.0", optional = true }
toml_edit = "0.20.2"
tracing = { version = "0.1.40", optional = true }
histo = "1.0.0"
itertools = "0.11.0"

[dev-dependencies]
anyhow = "1.0.75"
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ enum SubCommand {
Format(fmt::FormatCmd),
Run(run::RunCmd),
//#[clap(alias = "t")]
//Transpose(transpose::TransposeCmd),
Transpose(transpose::TransposeCmd),
Debug(debug::DebugCmd),
}

Expand All @@ -75,6 +75,7 @@ impl Command {
Some(SubCommand::Lint(cmd)) => cmd.run(&self.global),
Some(SubCommand::Format(cmd)) => cmd.run(&self.global),
Some(SubCommand::Run(cmd)) => cmd.run(&self.global),
Some(SubCommand::Transpose(cmd)) => cmd.run(&self.global),
Some(SubCommand::Debug(cmd)) => cmd.run(&self.global),
None => run::RunCmd::default().run(&self.global),
}
Expand Down
82 changes: 49 additions & 33 deletions src/cmd/transpose.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-FileCopyrightText: Oliver Tale-Yazdi <[email protected]>

use crate::{autofix::*, log};
use cargo_metadata::DependencyKind as DepKind;
use super::GlobalArgs;
use crate::{autofix::*, grammar::*, log};

use cargo_metadata::{Dependency as Dep, Package};
use itertools::Itertools;
use std::{
collections::{BTreeMap as Map, HashMap},
fs::canonicalize,
};

use super::GlobalArgs;

/// Transpose dependencies in the workspace.
#[derive(Debug, clap::Parser)]
pub struct TransposeCmd {
Expand Down Expand Up @@ -72,58 +73,73 @@ pub enum DefaultFeatureMode {
}

impl LiftToWorkspaceCmd {
pub fn run(&self, global: &GlobalArgs) {
pub fn run(&self, g: &GlobalArgs) {
let mut args = self.cargo_args.clone();
args.workspace = true;
let meta = args.load_metadata().expect("Loads metadata");
log::debug!("Scanning workspace for '{}'", self.dependency);
// crate -> dependency
let mut found = Vec::new();
let mut by_kind = HashMap::<DepKind, u32>::new();
let mut found_version: Option<cargo_metadata::semver::VersionReq> = None;
// version -> crate
let mut by_version = HashMap::<semver::VersionReq, Vec<(Package, Dep)>>::new();

for pkg in meta.packages.iter() {
for dep in pkg.dependencies.iter() {
if dep.name != self.dependency {
continue
}

found.push((pkg.clone(), dep.clone()));
by_version.entry(dep.req.clone()).or_default().push((pkg.clone(), dep.clone()));
}
}

if found_version.as_ref().map_or(false, |f| f.ne(&dep.req)) {
panic!(
"Found different versions of '{}' in the workspace: {} vs {}. Please use 'cargo upgrade -p {}' first.",
global.bold(&self.dependency), global.red(&format!("{}", found_version.unwrap())), global.red(&format!("{}", dep.req)), &self.dependency
);
}
found_version = Some(dep.req.clone());
log::debug!(
"Found '{}' in package '{}' with version '{}'",
self.dependency,
pkg.name,
dep.req
);
*by_kind.entry(dep.kind).or_default() += 1;
let versions = by_version.keys().collect::<Vec<_>>();
if versions.len() > 1 {
let longest = versions.iter().map(|v| v.to_string().len()).max().unwrap();
let mut err = String::new();
// iter by descending frequence
for (version, pkgs) in by_version.iter().sorted_by_key(|(_, pkgs)| pkgs.len()).rev() {
let ddd = if pkgs.len() > 3 { ", …" } else { "" };
let s = plural_or(pkgs.len(), " ");
// TODO plural s
err.push_str(&format!(
" {: <width$}: {: >3} time{s} ({}{ddd})\n",
version.to_string(),
pkgs.len(),
pkgs.iter()
.map(|(c, _)| c.name.as_str())
.take(3)
.collect::<Vec<_>>()
.join(", "),
width = longest
));
}

let _hint = format!("cargo upgrade -p {}@version", &self.dependency);
panic!(
"\nFound {} different versions of '{}' in the workspace:\n{err}",
versions.len(),
&self.dependency,
);
}
let Some(version) = found_version else {
panic!("Could not find any dependency named '{}'", global.red(&self.dependency));

let Some(version) = by_version.keys().next() else {
panic!("Could not find any dependency named '{}'", g.red(&self.dependency));
};
let _ = version;
let found = by_version.values().map(Vec::len).sum();

log::info!(
"Selected '{} {}' for lift up ({} occurrence{}: N={}, D={}, B={})",
"Selected '{} {}' for lift up ({} occurrence{})", //: N={}, D={}, B={})",
&self.dependency,
&version,
found.len(),
crate::grammar::plural(found.len()),
by_kind.get(&DepKind::Normal).unwrap_or(&0),
by_kind.get(&DepKind::Development).unwrap_or(&0),
by_kind.get(&DepKind::Build).unwrap_or(&0)
found,
crate::grammar::plural(found),
//by_kind.get(&DepKind::Normal).unwrap_or(&0),
//by_kind.get(&DepKind::Development).unwrap_or(&0),
//by_kind.get(&DepKind::Build).unwrap_or(&0)
);

let mut fixers = Map::new();
for (pkg, dep) in found {
for (pkg, dep) in by_version.values().flatten() {
let krate_path = canonicalize(pkg.manifest_path.clone().into_std_path_buf()).unwrap();
fixers
.entry(pkg.name.clone())
Expand Down
8 changes: 8 additions & 0 deletions src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ pub(crate) fn plural(n: usize) -> &'static str {
"s"
}
}

pub(crate) fn plural_or(n: usize, or: &str) -> String {
if n == 1 {
or.to_string()
} else {
"s".to_string()
}
}

0 comments on commit 4eeaa3d

Please sign in to comment.