fn expand()

in src/rust/engine/fs/src/glob_matching.rs [115:202]


  fn expand(&self, path_globs: PathGlobs) -> BoxFuture<Vec<PathStat>, E> {
    let PathGlobs {
      include,
      exclude,
      strict_match_behavior,
      conjunction,
    } = path_globs;

    if include.is_empty() {
      return future::ok(vec![]).to_boxed();
    }

    let result = Arc::new(Mutex::new(Vec::new()));

    let mut sources = Vec::new();
    let mut roots = Vec::new();
    for pgie in include {
      let source = Arc::new(pgie.input);
      for path_glob in pgie.globs {
        sources.push(source.clone());
        roots.push(self.expand_single(result.clone(), exclude.clone(), path_glob));
      }
    }

    future::join_all(roots)
      .and_then(move |matched| {
        if strict_match_behavior.should_check_glob_matches() {
          // Get all the inputs which didn't transitively expand to any files.
          let matching_inputs = sources
            .iter()
            .zip(matched.into_iter())
            .filter_map(
              |(source, matched)| {
                if matched {
                  Some(source.clone())
                } else {
                  None
                }
              },
            )
            .collect::<HashSet<_>>();

          let non_matching_inputs = sources
            .into_iter()
            .filter(|s| !matching_inputs.contains(s))
            .collect::<HashSet<_>>();

          let match_failed = match conjunction {
            // All must match.
            GlobExpansionConjunction::AllMatch => !non_matching_inputs.is_empty(),
            // Only one needs to match.
            GlobExpansionConjunction::AnyMatch => matching_inputs.is_empty(),
          };

          if match_failed {
            // TODO(#5684): explain what global and/or target-specific option to set to
            // modify this behavior!
            let mut non_matching_inputs = non_matching_inputs
              .iter()
              .map(|parsed_source| parsed_source.0.clone())
              .collect::<Vec<_>>();
            non_matching_inputs.sort();
            let msg = format!(
              "Globs did not match. Excludes were: {:?}. Unmatched globs were: {:?}.",
              exclude.exclude_patterns(),
              non_matching_inputs,
            );
            if strict_match_behavior.should_throw_on_error() {
              return future::err(Self::mk_error(&msg));
            } else {
              // TODO(#5683): this doesn't have any useful context (the stack trace) without
              // being thrown -- this needs to be provided, otherwise this is far less useful.
              warn!("{}", msg);
            }
          }
        }

        let mut path_stats = Arc::try_unwrap(result)
          .unwrap_or_else(|_| panic!("expand violated its contract."))
          .into_inner()
          .into_iter()
          .collect::<Vec<_>>();
        path_stats.sort_by(|a, b| a.path().cmp(b.path()));
        path_stats.dedup_by(|a, b| a.path() == b.path());
        future::ok(path_stats)
      })
      .to_boxed()
  }