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
mod config;
mod execution;
pub mod features;
pub use self::{config::Config, execution::TaskKind};
use self::{execution::Task, features::FeatureMatrix};
use cargo_metadata::{Metadata, MetadataCommand, Package};
use figment::{
providers::{Format, Json},
Figment,
};
use std::path::PathBuf;
use thiserror::Error;
pub fn run(
command: String,
args: Vec<String>,
task: TaskKind,
manifest_path: Option<PathBuf>,
figment: Figment,
) -> Result<(), Error> {
let mut cmd = MetadataCommand::new();
if let Some(manifest_path) = &manifest_path {
cmd.manifest_path(manifest_path);
}
let metadata = cmd.exec()?;
let mut error = None;
for package in get_workspace_members(&metadata) {
let figment = if let Some(package_config) =
package.metadata.get("feature-matrix")
{
figment
.clone()
.merge(Figment::from(Json::string(&package_config.to_string())))
} else {
figment.clone()
};
let config = Config::from(figment)?;
let matrix = FeatureMatrix::new(package, &config);
let task = Task::new(
task,
&command,
manifest_path.as_deref(),
&package.name,
&args,
matrix,
);
if let Err(err) = task.run() {
error = Some(err);
}
}
match error {
Some(err) => Err(err),
None => Ok(()),
}
}
fn get_workspace_members(
metadata: &Metadata,
) -> impl Iterator<Item = &Package> + '_ {
metadata
.packages
.iter()
.filter(|package| metadata.workspace_members.contains(&package.id))
}
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to get cargo metadata")]
Metadata(#[from] cargo_metadata::Error),
#[error("{}", message)]
Io {
message: &'static str,
#[source]
source: std::io::Error,
},
#[error("child process exited with {}", _0)]
Fail(std::process::ExitStatus),
#[error("failed to get config from metadata")]
Config(#[from] figment::Error),
}
#[cfg(test)]
mod tests {}