cargo_feature_matrix/
lib.rs

1mod config;
2mod execution;
3pub mod features;
4
5pub use self::{config::Config, execution::TaskKind};
6use self::{execution::Task, features::FeatureMatrix};
7use cargo_metadata::{Metadata, MetadataCommand, Package};
8use derive_more::{
9  derive::{Display, Error},
10  From,
11};
12use figment::{
13  providers::{Format, Json},
14  Figment,
15};
16use std::path::PathBuf;
17
18pub fn run(
19  command: String,
20  args: Vec<String>,
21  task: TaskKind,
22  manifest_path: Option<PathBuf>,
23  figment: Figment,
24) -> Result<(), Error> {
25  let mut cmd = MetadataCommand::new();
26  if let Some(manifest_path) = &manifest_path {
27    cmd.manifest_path(manifest_path);
28  }
29  let metadata = cmd.exec()?;
30
31  let mut error = None;
32  for package in get_workspace_members(&metadata) {
33    let figment =
34      if let Some(package_config) = package.metadata.get("feature-matrix") {
35        figment
36          .clone()
37          .merge(Figment::from(Json::string(&package_config.to_string())))
38      } else {
39        figment.clone()
40      };
41
42    let config = Config::from(figment)?;
43
44    let matrix = FeatureMatrix::new(package, &config);
45    let task = Task::new(
46      task,
47      &command,
48      manifest_path.as_deref(),
49      &package.name,
50      &args,
51      matrix,
52    );
53
54    if let Err(err) = task.run() {
55      error = Some(err);
56    }
57  }
58
59  match error {
60    Some(err) => Err(err),
61    None => Ok(()),
62  }
63}
64
65/// Gets a list of packages that are members of the workspace
66fn get_workspace_members(
67  metadata: &Metadata,
68) -> impl Iterator<Item = &Package> + '_ {
69  metadata
70    .packages
71    .iter()
72    .filter(|package| metadata.workspace_members.contains(&package.id))
73}
74
75#[derive(Debug, Display, Error, From)]
76pub enum Error {
77  #[display("failed to get cargo metadata")]
78  Metadata(cargo_metadata::Error),
79  #[display("{message}")]
80  Io {
81    message: &'static str,
82    source: std::io::Error,
83  },
84  #[display("child process exited with {_0}")]
85  #[from(ignore)]
86  #[error(ignore)]
87  Fail(std::process::ExitStatus),
88  #[display("failed to get config from metadata")]
89  Config(figment::Error),
90}
91
92#[cfg(test)]
93mod tests {}