Skip to content

Commit a17b9fc

Browse files
committed
calculating the graph
1 parent 5c18fd1 commit a17b9fc

File tree

3 files changed

+128
-45
lines changed

3 files changed

+128
-45
lines changed

src/cli.rs

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use structopt::StructOpt;
1515
use toml_edit::Value;
1616

1717
use crate::commands;
18+
use crate::util;
1819

1920
fn parse_identifiers(src: &str) -> Identifier {
2021
Identifier::AlphaNumeric(src.to_owned())
@@ -350,7 +351,7 @@ pub struct Opt {
350351
pub cmd: Command,
351352
}
352353

353-
fn make_pkg_predicate(args: PackageSelectOptions) -> Result<Box<dyn Fn(&Package) -> bool>, String> {
354+
fn make_pkg_predicate(ws: &Workspace<'_>, args: PackageSelectOptions) -> Result<Box<dyn Fn(&Package) -> bool>, String> {
354355
let PackageSelectOptions {
355356
packages,
356357
skip,
@@ -374,16 +375,6 @@ fn make_pkg_predicate(args: PackageSelectOptions) -> Result<Box<dyn Fn(&Package)
374375
}
375376
}
376377

377-
if changed_since.len() != 0 {
378-
if !skip.is_empty() || !ignore_pre_version.is_empty() {
379-
return Err(
380-
"-c/--changed-since is mutually exlusive to using -s/--skip and -i/--ignore-version-pre"
381-
.into(),
382-
);
383-
}
384-
}
385-
386-
387378
let publish = move |p: &Package| {
388379
let publ = if ignore_publish {
389380
true
@@ -396,6 +387,35 @@ fn make_pkg_predicate(args: PackageSelectOptions) -> Result<Box<dyn Fn(&Package)
396387
publ
397388
};
398389

390+
if changed_since.len() != 0 {
391+
if !skip.is_empty() || !ignore_pre_version.is_empty() {
392+
return Err(
393+
"-c/--changed-since is mutually exlusive to using -s/--skip and -i/--ignore-version-pre"
394+
.into(),
395+
);
396+
}
397+
398+
}
399+
400+
let changed = util::changed_packages(ws, &changed_since);
401+
if changed.len() == 0 {
402+
return Err("No changes detected".into())
403+
};
404+
405+
ws.config()
406+
.shell()
407+
.status("Calculating", "Dependents of changed crates")
408+
.expect("Writing to Shell doesn't fail");
409+
410+
// FIXME: run through the changed once, mark which ones have major-changes
411+
// update the set of changed to reflect that and calculate the
412+
// remaining graph from that, probably useful to upgrade after
413+
// every cycle
414+
let (dependents_graph, dependents_map) = util::changed_dependents(
415+
util::members_deep(ws).into_iter().filter(|p| publish(&p)).collect(),
416+
&changed,
417+
publish
418+
);
399419

400420

401421
if !packages.is_empty() {
@@ -474,19 +494,20 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
474494
pkg_opts,
475495
check_only,
476496
} => {
477-
let predicate = make_pkg_predicate(pkg_opts)?;
478497
let ws = Workspace::new(&root_manifest, &c)
479498
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
499+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
480500
commands::clean_up_unused_dependencies(&ws, predicate, check_only)
481501
}
482502
Command::AddOwner {
483503
owner,
484504
token,
485505
pkg_opts,
486506
} => {
487-
let predicate = make_pkg_predicate(pkg_opts)?;
488507
let ws = Workspace::new(&root_manifest, &c)
489508
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
509+
510+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
490511
for pkg in ws.members().filter(|p| predicate(p)) {
491512
commands::add_owner(ws.config(), &pkg, owner.clone(), token.clone())?;
492513
}
@@ -501,7 +522,11 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
501522
if name == "name" {
502523
return Err("To change the name please use the rename command!".into());
503524
}
504-
let predicate = make_pkg_predicate(pkg_opts)?;
525+
526+
let ws = Workspace::new(&root_manifest, &c)
527+
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
528+
529+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
505530
let type_value = {
506531
if let Ok(v) = bool::from_str(&value) {
507532
Value::from(v)
@@ -512,8 +537,6 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
512537
}
513538
};
514539

515-
let ws = Workspace::new(&root_manifest, &c)
516-
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
517540
commands::set_field(
518541
ws.members()
519542
.filter(|p| predicate(p) && c.shell().status("Setting on", p.name()).is_ok()),
@@ -539,7 +562,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
539562
force_update,
540563
version,
541564
} => {
542-
let predicate = make_pkg_predicate(pkg_opts)?;
565+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
543566
commands::set_version(
544567
&ws,
545568
|p| predicate(p),
@@ -551,7 +574,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
551574
pkg_opts,
552575
force_update,
553576
} => {
554-
let predicate = make_pkg_predicate(pkg_opts)?;
577+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
555578
commands::set_version(
556579
&ws,
557580
|p| predicate(p),
@@ -580,7 +603,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
580603
pkg_opts,
581604
force_update,
582605
} => {
583-
let predicate = make_pkg_predicate(pkg_opts)?;
606+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
584607
commands::set_version(
585608
&ws,
586609
|p| predicate(p),
@@ -597,7 +620,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
597620
pkg_opts,
598621
force_update,
599622
} => {
600-
let predicate = make_pkg_predicate(pkg_opts)?;
623+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
601624
commands::set_version(
602625
&ws,
603626
|p| predicate(p),
@@ -614,7 +637,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
614637
pkg_opts,
615638
force_update,
616639
} => {
617-
let predicate = make_pkg_predicate(pkg_opts)?;
640+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
618641
commands::set_version(
619642
&ws,
620643
|p| predicate(p),
@@ -632,7 +655,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
632655
pkg_opts,
633656
force_update,
634657
} => {
635-
let predicate = make_pkg_predicate(pkg_opts)?;
658+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
636659
commands::set_version(
637660
&ws,
638661
|p| predicate(p),
@@ -649,7 +672,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
649672
pkg_opts,
650673
force_update,
651674
} => {
652-
let predicate = make_pkg_predicate(pkg_opts)?;
675+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
653676
commands::set_version(
654677
&ws,
655678
|p| predicate(p),
@@ -665,7 +688,7 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
665688
pkg_opts,
666689
force_update,
667690
} => {
668-
let predicate = make_pkg_predicate(pkg_opts)?;
691+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
669692
commands::set_version(
670693
&ws,
671694
|p| predicate(p),
@@ -680,16 +703,20 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
680703
}
681704
}
682705
}
683-
Command::DeDevDeps { pkg_opts } => maybe_patch(false, &make_pkg_predicate(pkg_opts)?),
706+
Command::DeDevDeps { pkg_opts } => {
707+
let ws = Workspace::new(&root_manifest, &c)
708+
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
709+
maybe_patch(false, &make_pkg_predicate(&ws, pkg_opts)?)
710+
},
684711
Command::ToRelease {
685712
include_dev,
686713
pkg_opts,
687714
} => {
688-
let predicate = make_pkg_predicate(pkg_opts)?;
689-
maybe_patch(include_dev, &predicate)?;
690-
691715
let ws = Workspace::new(&root_manifest, &c)
692716
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
717+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
718+
maybe_patch(include_dev, &predicate)?;
719+
693720
let packages = commands::packages_to_release(&ws, predicate)?;
694721
println!(
695722
"{:}",
@@ -712,11 +739,12 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
712739
verify_readme_feature()?;
713740
}
714741

715-
let predicate = make_pkg_predicate(pkg_opts)?;
716-
maybe_patch(include_dev, &predicate)?;
717-
718742
let ws = Workspace::new(&root_manifest, &c)
719743
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
744+
745+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
746+
maybe_patch(include_dev, &predicate)?;
747+
720748
let packages = commands::packages_to_release(&ws, predicate)?;
721749

722750
commands::check(&packages, &ws, build, check_readme)
@@ -726,11 +754,12 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
726754
pkg_opts,
727755
readme_mode,
728756
} => {
729-
let predicate = make_pkg_predicate(pkg_opts)?;
730-
maybe_patch(false, &predicate)?;
731-
732757
let ws = Workspace::new(&root_manifest, &c)
733758
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
759+
760+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
761+
maybe_patch(false, &predicate)?;
762+
734763
let packages = commands::packages_to_release(&ws, predicate)?;
735764

736765
commands::gen_all_readme(packages, &ws, readme_mode)
@@ -745,11 +774,10 @@ pub fn run(args: Opt) -> Result<(), Box<dyn Error>> {
745774
pkg_opts,
746775
check_readme,
747776
} => {
748-
let predicate = make_pkg_predicate(pkg_opts)?;
749-
maybe_patch(include_dev, &predicate)?;
750-
751777
let ws = Workspace::new(&root_manifest, &c)
752778
.map_err(|e| format!("Reading workspace {:?} failed: {:}", root_manifest, e))?;
779+
let predicate = make_pkg_predicate(&ws, pkg_opts)?;
780+
maybe_patch(include_dev, &predicate)?;
753781

754782
let packages = commands::packages_to_release(&ws, predicate)?;
755783

src/commands/to_release.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,16 @@ where
5959
drop(lock);
6060

6161
let map = members
62-
.into_iter()
62+
.iter()
6363
.filter_map(|member| {
6464
if ignored.contains(&member.name()) || already_published.contains(&member.name()) {
6565
return None;
6666
}
67-
Some((member.name(), graph.add_node(member.clone())))
67+
Some((member.name(), graph.add_node((*member).clone())))
6868
})
6969
.collect::<HashMap<_, _>>();
7070

71-
for member in members_deep(ws).iter() {
71+
for member in members.iter() {
7272
let current_index = match map.get(&member.name()) {
7373
Some(i) => i,
7474
_ => continue, // ignore entries we are not expected to publish

src/util.rs

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,68 @@
11
use cargo::{
22
core::{package::Package, Workspace},
3+
util::interning::InternedString,
34
sources::PathSource,
45
};
56
use log::warn;
6-
use std::{error::Error, fs};
7+
use std::{
8+
collections::{HashSet, HashMap},
9+
error::Error, fs,
10+
};
711
use toml_edit::{Document, InlineTable, Item, Table, Value};
8-
use petgraph::Graph;
12+
use petgraph::{Directed, Graph, graph::NodeIndex};
913
use git2::{Repository};
1014

11-
pub fn changed_packages<'a>(ws: &'a Workspace, reference: &str) -> Vec<Package> {
15+
/// Calculate the dependents graph
16+
pub fn changed_dependents<'a, F>(all_members: Vec<Package>, changed: &HashSet<Package>, predicate: F)
17+
-> (Graph::<Package, u8, Directed, u32>, HashMap<InternedString, NodeIndex<u32>>)
18+
where
19+
F: Fn(&Package) -> bool,
20+
{
21+
let mut graph = Graph::<Package, u8, Directed>::new();
22+
23+
let mut map = all_members
24+
.iter()
25+
.filter_map(|member| {
26+
if !predicate(&member) && !changed.contains(member) {
27+
return None;
28+
}
29+
Some((member.name(), graph.add_node(member.clone())))
30+
})
31+
.collect::<HashMap<_, _>>();
32+
33+
for member in all_members.iter() {
34+
let current_index = match map.get(&member.name()) {
35+
Some(i) => i,
36+
_ => continue, // ignore entries we are not expected to publish
37+
};
38+
39+
for dep in member.dependencies() {
40+
if let Some(dep_index) = map.get(&dep.package_name()) {
41+
graph.add_edge(*current_index, *dep_index, 0);
42+
}
43+
}
44+
}
45+
46+
'members: for member in all_members.iter() {
47+
let member_index = if let Some(i) = map.get(&member.name()) { i } else { continue };
48+
for pkg in changed.iter() {
49+
if let Some(pkg_idx) = map.get(&pkg.name()) {
50+
if petgraph::algo::has_path_connecting(&graph, *pkg_idx, *member_index, None) {
51+
continue 'members;
52+
}
53+
}
54+
}
55+
// we didn't continue, so no match was found. remove
56+
graph.remove_node(*member_index);
57+
map.remove(&member.name());
58+
}
59+
60+
(graph, map)
61+
}
62+
63+
pub fn changed_packages<'a>(ws: &'a Workspace, reference: &str) -> HashSet<Package> {
1264
let path = ws.root();
65+
println!("{:?}", path);
1366
let repo = Repository::open(&path).expect("Workspace isn't a git repo");
1467
let current_head = repo.head()
1568
.and_then(|b| b.peel_to_commit())
@@ -32,17 +85,19 @@ pub fn changed_packages<'a>(ws: &'a Workspace, reference: &str) -> Vec<Package>
3285
.map(|l| path.join(l))
3386
.collect::<Vec<_>>();
3487

35-
let cfg = git2::Config::default().unwrap();
88+
let mut packages = HashSet::new();
3689

3790
for m in members_deep(ws) {
3891
let root = m.root();
3992
for f in files.iter() {
4093
if f.starts_with(root) {
41-
println!("{:?}: {:}", f, m.name());
94+
packages.insert(m);
4295
break;
4396
}
4497
}
4598
}
99+
100+
packages
46101
}
47102

48103
// Find all members of the workspace, into the total depth

0 commit comments

Comments
 (0)