Skip to content

Commit 91ce3b7

Browse files
committed
Allow passing packages filter with env var
commit-id:c4ba78ac
1 parent bc29137 commit 91ce3b7

File tree

1 file changed

+58
-12
lines changed

1 file changed

+58
-12
lines changed

utils/scarb-ui/src/args/packages_filter.rs

+58-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::HashSet;
12
use std::fmt;
23

34
use anyhow::{bail, ensure, Result};
@@ -22,8 +23,15 @@ use scarb_metadata::{Metadata, PackageMetadata};
2223
pub struct PackagesFilter {
2324
/// Packages to run this command on, can be a concrete package name (`foobar`) or
2425
/// a prefix glob (`foo*`).
25-
#[arg(short, long, value_name = "SPEC", default_value = "*")]
26-
package: String,
26+
#[arg(
27+
short,
28+
long,
29+
default_value = "*",
30+
value_delimiter = ',',
31+
value_name = "SPEC",
32+
env = "SCARB_PACKAGES_FILTER"
33+
)]
34+
package: Vec<String>,
2735
/// Run for all packages in the workspace.
2836
#[arg(short, long, conflicts_with = "package")]
2937
workspace: bool,
@@ -34,31 +42,38 @@ impl PackagesFilter {
3442
///
3543
/// Returns an error if no or more than one packages were found.
3644
pub fn match_one<S: PackagesSource>(&self, source: &S) -> Result<S::Package> {
37-
let spec = Spec::parse(&self.package)?;
45+
let specs = self.package_specs()?;
3846

3947
// Check for current package.
4048
// If none (in case of virtual workspace), run for all members.
41-
if self.current_selected(&spec) {
49+
if self.current_selected(&specs) {
4250
if let Some(pkg) = self.current_package(source)? {
4351
return Ok(pkg);
4452
}
4553
}
4654

4755
let members = source.members();
4856

49-
if (self.workspace || matches!(spec, Spec::All)) && members.len() > 1 {
57+
if (self.workspace || specs.iter().any(|spec| matches!(spec, Spec::All)))
58+
&& members.len() > 1
59+
{
5060
bail!(indoc! {r#"
5161
could not determine which package to work on
5262
help: use the `--package` option to specify the package
5363
"#});
5464
}
5565

56-
let found = Self::do_match::<S>(&spec, self.workspace, members.into_iter())?;
66+
let specs_filter: String = specs
67+
.iter()
68+
.map(|s| s.to_string())
69+
.collect::<Vec<_>>()
70+
.join(",");
71+
let found = Self::do_match_all::<S>(specs, self.workspace, members)?;
5772

5873
ensure!(
5974
found.len() <= 1,
6075
formatdoc! {r#"
61-
workspace has multiple members matching `{spec}`
76+
workspace has multiple members matching `{specs_filter}`
6277
help: use the `--package` option to specify single package
6378
"#}
6479
);
@@ -70,18 +85,31 @@ impl PackagesFilter {
7085
///
7186
/// Returns an error if no packages were found.
7287
pub fn match_many<S: PackagesSource>(&self, source: &S) -> Result<Vec<S::Package>> {
73-
let spec = Spec::parse(&self.package)?;
88+
let specs = self.package_specs()?;
7489

7590
// Check for current package.
7691
// If none (in case of virtual workspace), run for all members.
77-
if self.current_selected(&spec) {
92+
if self.current_selected(&specs) {
7893
if let Some(pkg) = self.current_package(source)? {
7994
return Ok(vec![pkg]);
8095
}
8196
}
8297

8398
let members = source.members();
84-
Self::do_match::<S>(&spec, self.workspace, members.into_iter())
99+
Self::do_match_all::<S>(specs, self.workspace, members)
100+
}
101+
102+
fn package_specs(&self) -> Result<Vec<Spec>> {
103+
let specs = self
104+
.package
105+
.iter()
106+
.map(|s| Spec::parse(s))
107+
.collect::<Result<HashSet<Spec>>>()?;
108+
if specs.iter().any(|s| matches!(s, Spec::All)) {
109+
Ok(vec![Spec::All])
110+
} else {
111+
Ok(specs.into_iter().collect())
112+
}
85113
}
86114

87115
fn current_package<S: PackagesSource>(&self, source: &S) -> Result<Option<S::Package>> {
@@ -92,8 +120,25 @@ impl PackagesFilter {
92120
.cloned())
93121
}
94122

95-
fn current_selected(&self, spec: &Spec<'_>) -> bool {
96-
!self.workspace && matches!(spec, Spec::All)
123+
fn current_selected(&self, specs: &[Spec<'_>]) -> bool {
124+
!self.workspace && specs.iter().any(|spec| matches!(spec, Spec::All))
125+
}
126+
127+
fn do_match_all<S: PackagesSource>(
128+
specs: Vec<Spec>,
129+
workspace: bool,
130+
members: Vec<S::Package>,
131+
) -> Result<Vec<S::Package>> {
132+
let mut packages = Vec::new();
133+
for spec in specs {
134+
packages.extend(Self::do_match::<S>(
135+
&spec,
136+
workspace,
137+
members.clone().into_iter(),
138+
)?);
139+
}
140+
packages.dedup_by_key(|p| S::package_name_of(p).to_string());
141+
Ok(packages)
97142
}
98143

99144
fn do_match<S: PackagesSource>(
@@ -124,6 +169,7 @@ impl PackagesFilter {
124169
}
125170
}
126171

172+
#[derive(PartialEq, Eq, Hash)]
127173
enum Spec<'a> {
128174
All,
129175
One(&'a str),

0 commit comments

Comments
 (0)