1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use serde_json;
use std::collections::BTreeSet;
use super::{LalResult, Manifest, Lockfile};
#[derive(Serialize)]
struct SingleUpdate {
pub repo: String,
pub dependencies: Vec<String>,
}
#[derive(Serialize, Default)]
struct UpdateStage {
pub updates: Vec<SingleUpdate>,
}
#[derive(Serialize, Default)]
struct UpdateSequence {
pub stages: Vec<UpdateStage>,
}
fn compute_update_stages(lf: &Lockfile, component: &str) -> LalResult<UpdateSequence> {
let all_required = lf.get_reverse_deps_transitively_for(component.into());
let dependencies = lf.find_all_dependency_names();
debug!("Needs updating: {:?}", all_required);
debug!("Dependency table: {:?}", dependencies);
let mut result = UpdateSequence::default();
let mut remaining = all_required.clone();
let mut handled = vec![component.to_string()].into_iter().collect();
while !remaining.is_empty() {
let mut stage = UpdateStage::default();
debug!("Remaining set: {:?}", remaining);
for dep in remaining.clone() {
debug!("Processing {}", dep);
let deps_for_name = dependencies[&dep].clone();
debug!("Deps for {} is {:?}", dep, deps_for_name);
let intersection = deps_for_name.intersection(&remaining).collect::<BTreeSet<_>>();
debug!("Intersection: {:?}", intersection);
if intersection.is_empty() {
stage.updates.push(SingleUpdate {
repo: dep,
dependencies: deps_for_name
.intersection(&handled)
.cloned()
.collect(),
});
}
}
for dep in &stage.updates {
remaining.remove(&dep.repo);
handled.insert(dep.repo.clone());
}
result.stages.push(stage);
}
Ok(result)
}
pub fn propagate(manifest: &Manifest, component: &str, json_output: bool) -> LalResult<()> {
debug!("Calculating update path for {}", component);
let lf = Lockfile::default().set_name(&manifest.name).populate_from_input()?;
let result = compute_update_stages(&lf, component)?;
if json_output {
let encoded = serde_json::to_string_pretty(&result)?;
println!("{}", encoded);
} else {
println!("Assuming {} has been updated:", component);
let mut i = 1;
for stage in result.stages {
println!("Stage {}:", i);
for update in stage.updates {
println!("- update [{}] in {}",
update.dependencies.join(", "),
update.repo);
}
i += 1;
}
}
Ok(())
}