Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.

Commit fe0de61

Browse files
committed
cleaner way of ensuring package manager events are ran in succession
1 parent 4498aa3 commit fe0de61

20 files changed

Lines changed: 245 additions & 211 deletions

File tree

app/src/commands/apply.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl ComtryaCommand for Apply {
8686
let contexts = runtime.contexts.clone();
8787
let manifest_path = self
8888
.manifest_path(runtime)
89-
.inspect(|path| debug!("Load manifests from path: {path:#?}"))?;
89+
.inspect(|path| debug!("Load manifests from path: {:#?}", path))?;
9090
let manifests = load(manifest_path, &contexts);
9191
let manifest_manager = {
9292
let graph = DependencyGraph::new(manifests, &contexts, runtime).await?;
@@ -96,41 +96,42 @@ impl ComtryaCommand for Apply {
9696
let dry_run = self.dry_run;
9797
let password_manager = &runtime.password_manager;
9898

99-
println!("Total: {}", manifest_manager.get_ordered_manifests().len());
10099
for manifest in manifest_manager.get_ordered_manifests() {
101100
// Need to clone all these because they'll be in their own threads
102101
let label = self.label.clone();
103102
let contexts = contexts.clone();
104-
let password_manager = password_manager.clone();
103+
let pm = password_manager.clone();
105104
let manifest_manager = Arc::clone(&manifest_manager);
105+
let name = manifest.get_name();
106106

107107
workers.spawn(async move {
108-
for successor in manifest_manager.get_successors(&manifest).await {
109-
// May need to remove this unwrap and handle the option instead
110-
if !successor.barrier.as_ref().unwrap().wait(true).await {
111-
return Err(anyhow!(
112-
"Debug unable to run manifest {manifest:?} due dependency failure."
113-
));
114-
}
115-
}
116-
117-
let exec_result = manifest
118-
.execute(
119-
dry_run,
120-
label.clone(),
121-
&contexts.clone(),
122-
password_manager.clone(),
123-
)
124-
.await;
125-
108+
// Wait on own barrier, if a dependency fails this is how it find's out
126109
manifest
127110
.barrier
128111
.as_ref()
129-
.unwrap()
130-
.wait(exec_result.is_ok())
131-
.await;
112+
.with_context(|| format!("Cannot lock manifest '{}' for execution", name))?
113+
.wait(true)
114+
.await
115+
.then_some(())
116+
.context(format!("Skipping manifest '{}' Dependancy(s) failed", name))?;
117+
118+
let result = manifest.execute(dry_run, label, &contexts, pm).await;
119+
120+
// Inform successors (dependants) of pass or fail
121+
for successor in manifest_manager
122+
.get_successors(&manifest)
123+
.await
124+
.context(format!("Cannot resolve dependants for manifest '{}'", name))?
125+
{
126+
successor
127+
.barrier
128+
.as_ref()
129+
.context(format!("Cannot mark manifest '{}' completed", name))?
130+
.wait(result.is_ok())
131+
.await;
132+
}
132133

133-
exec_result.context("Manifest {manifest:?} failed. {e}")
134+
Ok(())
134135
});
135136
}
136137

app/src/config/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ where
8181
}
8282

8383
pub(crate) fn load_config(args: &GlobalArgs) -> Result<Config> {
84-
match lib_config(&args) {
84+
match lib_config(args) {
8585
Ok(config) => match args.manifest_directory.clone() {
8686
Some(manifest_path) => Ok(Config {
8787
manifest_paths: vec![manifest_path],

app/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use comtrya_lib::manifests;
1010
use clap::Parser;
1111
use tracing::{error, Level};
1212

13-
#[allow(unused_imports)]
1413
use tracing_subscriber::{fmt::writer::MakeWriterExt, layer::SubscriberExt, FmtSubscriber};
1514

1615
mod commands;

app/src/utils/dependency_graph.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use tracing::{error, trace};
1414

1515
use crate::Runtime;
1616
use comtrya_lib::{
17-
actions::Actions,
1817
contexts::Contexts,
1918
manifests::{DependencyBarrier, Manifest},
2019
utilities::{get_privilege_provider, password_manager::PasswordManager},
@@ -41,7 +40,7 @@ impl DependencyGraph {
4140
let mut should_ask_for_pass = false;
4241
let mut dependency_map = Vec::new();
4342

44-
for (_, manifest) in manifests.iter_mut() {
43+
for manifest in manifests.values_mut() {
4544
manifest.barrier = Some(DependencyBarrier::new(manifest.depends.len() + 1));
4645
let node = this.add_manifest(manifest.clone()).await;
4746
this.name_to_idx.insert(manifest.get_name(), node);
@@ -54,7 +53,7 @@ impl DependencyGraph {
5453
let dep_prefix = name.rsplit_once('.').map(|(n, _)| n).unwrap_or(&name);
5554
let dependency_name = dependency_name.replace("./", &format!("{dep_prefix}."));
5655

57-
let Some(dependency_manifest) = manifests.get(&dependency_name) else {
56+
let Some(dependency) = manifests.get(&dependency_name) else {
5857
return error!(
5958
message = "Unresolved dependency",
6059
dependency = dependency_name
@@ -64,28 +63,20 @@ impl DependencyGraph {
6463
trace!(
6564
message = "Dependency Registered",
6665
from = name,
67-
to = dependency_manifest.get_name()
66+
to = dependency.get_name()
6867
);
6968

70-
dependency_map.push((node, this.name_to_idx[&dependency_manifest.get_name()]));
69+
dependency_map.push((node, this.name_to_idx[&dependency.get_name()]));
7170
});
7271

73-
if !should_ask_for_pass {
74-
should_ask_for_pass = manifest.actions.iter().any(|action| match action {
75-
Actions::CommandRun(cva) => cva.action.privileged,
76-
Actions::PackageInstall(_) | Actions::PackageRepository(_) => true,
77-
_ => false,
78-
});
79-
}
72+
should_ask_for_pass |= manifest.actions.iter().any(|action| action.is_privileged());
8073
}
8174

82-
for (from, to) in dependency_map {
83-
this.graph.add_edge(from, to, ());
75+
for (from, to) in &dependency_map {
76+
this.graph.add_edge(*from, *to, ());
8477
}
8578

8679
if should_ask_for_pass {
87-
debug!("Should be prompting for password. Asking now");
88-
8980
let mut password_manager =
9081
PasswordManager::new(get_privilege_provider(contexts).as_deref())?;
9182
password_manager.prompt("Please enter password:")?;
@@ -117,15 +108,17 @@ impl DependencyGraph {
117108
*idx
118109
}
119110

120-
pub async fn get_successors(&self, manifest: &LockedManifest) -> Vec<LockedManifest> {
121-
self.graph
122-
.neighbors_directed(self.get_node_from_manifest(manifest).await, Incoming)
111+
pub async fn get_successors(&self, manifest: &LockedManifest) -> Option<Vec<LockedManifest>> {
112+
let manifests = self
113+
.graph
114+
.neighbors_directed(self.get_node_from_manifest(manifest).await?, Incoming)
123115
.map(|node| Arc::clone(&self.graph[node].clone()))
124-
.collect()
116+
.collect();
117+
118+
Some(manifests)
125119
}
126120

127-
pub async fn get_node_from_manifest(&self, manifest: &LockedManifest) -> NodeIndex {
128-
// let join_set = JoinSet::new();
129-
*self.name_to_idx.get(&manifest.get_name()).unwrap()
121+
pub async fn get_node_from_manifest(&self, manifest: &LockedManifest) -> Option<NodeIndex> {
122+
self.name_to_idx.get(&manifest.get_name()).copied()
130123
}
131124
}

app/src/utils/mod.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
11
mod dependency_graph;
2-
pub use dependency_graph::DependencyGraph;
3-
use std::iter::from_fn;
4-
5-
pub trait ZipLongest<T>: Iterator<Item = T> {
6-
fn zip_longest<U, I>(self, other: I) -> impl Iterator<Item = (Option<T>, Option<U>)>
7-
where
8-
Self: Sized,
9-
I: IntoIterator<Item = U>;
10-
}
112

12-
impl<T, I: Iterator<Item = T>> ZipLongest<T> for I {
13-
fn zip_longest<U, J>(self, other: J) -> impl Iterator<Item = (Option<T>, Option<U>)>
14-
where
15-
J: IntoIterator<Item = U>,
16-
{
17-
let mut a = self.fuse();
18-
let mut b = other.into_iter().fuse();
19-
20-
from_fn(move || match (a.next(), b.next()) {
21-
(None, None) => None,
22-
(a, b) => Some((a, b)),
23-
})
24-
}
25-
}
3+
pub use dependency_graph::DependencyGraph;

lib/src/actions/command/run.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ impl Action for RunCommand {
6262
))],
6363
}])
6464
}
65+
66+
fn is_privileged(&self) -> bool {
67+
self.privileged
68+
}
6569
}
6670

6771
#[cfg(test)]

lib/src/actions/file/link.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,19 @@ impl FileLink {
9292
}];
9393

9494
if let Ok(paths) = std::fs::read_dir(from) {
95-
paths.for_each(|path| {
96-
if let Ok(path) = path {
97-
let p = path.path();
98-
99-
if let Some(file_name) = p.file_name() {
100-
steps.push(Step {
101-
atom: Box::new(Link {
102-
source: p.clone(),
103-
target: to.join(file_name),
104-
}),
105-
initializers: vec![Ensure(Box::new(FileExists(p.clone())))],
106-
finalizers: vec![],
107-
})
108-
}
109-
}
110-
})
95+
steps.extend(paths.filter_map(|path| {
96+
let p = path.ok()?.path();
97+
let file_name = p.file_name()?;
98+
99+
Some(Step {
100+
atom: Box::new(Link {
101+
source: p.clone(),
102+
target: to.join(file_name),
103+
}),
104+
initializers: vec![Ensure(Box::new(FileExists(p.clone())))],
105+
finalizers: vec![],
106+
})
107+
}))
111108
}
112109

113110
steps
@@ -209,7 +206,6 @@ mod tests {
209206
actions: vec![],
210207
depends: vec![],
211208
name: None,
212-
dag_index: None,
213209
..Default::default()
214210
};
215211

@@ -265,7 +261,6 @@ mod tests {
265261
actions: vec![],
266262
depends: vec![],
267263
name: None,
268-
dag_index: None,
269264
..Default::default()
270265
};
271266

lib/src/actions/file/mod.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub mod unarchive;
77

88
use crate::actions::Action;
99
use crate::manifests::Manifest;
10-
use anyhow::{anyhow, Result};
10+
use anyhow::{anyhow, Context, Result};
1111
use normpath::PathExt;
1212
use serde::{de::Error, Deserialize, Deserializer};
1313
use std::path::PathBuf;
@@ -16,20 +16,16 @@ pub trait FileAction: Action {
1616
fn resolve(&self, manifest: &Manifest, path: &str) -> anyhow::Result<PathBuf> {
1717
Ok(manifest
1818
.root_dir
19-
.clone()
20-
.ok_or_else(|| anyhow!("Failed because manifest has no root_dir"))?
19+
.as_ref()
20+
.context("Failed because manifest has no root_dir")?
2121
.join("files")
2222
.join(path)
2323
.normalize()
24-
.map_err(|e| {
25-
anyhow!(
26-
"Resolution of {} failed in manifest {} because {}",
27-
path.to_string(),
28-
manifest
29-
.name
30-
.as_ref()
31-
.unwrap_or(&"cannot extract manifest name".to_string()),
32-
e.to_string()
24+
.with_context(|| {
25+
format!(
26+
"Resolution of {} failed in manifest {}",
27+
path,
28+
manifest.get_name()
3329
)
3430
})?
3531
.as_path()
@@ -45,7 +41,7 @@ pub trait FileAction: Action {
4541
.join("files")
4642
.join(path);
4743

48-
std::fs::read(file_path.clone()).map_err(|e| match e.kind() {
44+
std::fs::read(&*file_path).map_err(|e| match e.kind() {
4945
ErrorKind::NotFound => anyhow!(
5046
"Failed because {} was not found",
5147
file_path.to_string_lossy()

lib/src/actions/group/add.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ impl Action for GroupAdd {
2020

2121
let mut atoms: Vec<Step> = vec![];
2222

23-
atoms.append(&mut provider.add_group(&variant, &contexts));
23+
atoms.append(&mut provider.add_group(&variant, contexts));
2424

2525
Ok(atoms)
2626
}
27+
28+
fn is_privileged(&self) -> bool {
29+
true
30+
}
2731
}

0 commit comments

Comments
 (0)