1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate_health_proc_macros::NameAndVersionMap;
16 
17 use std::{
18     collections::HashSet,
19     path::{Path, PathBuf},
20 };
21 
22 use anyhow::{anyhow, Result};
23 use semver::Version;
24 use walkdir::WalkDir;
25 
26 use crate::{
27     android_bp::generate_android_bps, Crate, CrateError, NameAndVersion, NameAndVersionMap,
28     NamedAndVersioned,
29 };
30 
31 use std::collections::BTreeMap;
32 
33 #[derive(NameAndVersionMap)]
34 pub struct CrateCollection {
35     crates: BTreeMap<NameAndVersion, Crate>,
36     repo_root: PathBuf,
37 }
38 
39 impl CrateCollection {
new<P: Into<PathBuf>>(repo_root: P) -> CrateCollection40     pub fn new<P: Into<PathBuf>>(repo_root: P) -> CrateCollection {
41         CrateCollection { crates: BTreeMap::new(), repo_root: repo_root.into() }
42     }
add_from(&mut self, path: &impl AsRef<Path>) -> Result<()>43     pub fn add_from(&mut self, path: &impl AsRef<Path>) -> Result<()> {
44         for entry_or_err in WalkDir::new(self.repo_root.join(path)) {
45             let entry = entry_or_err?;
46             if entry.file_name() == "Cargo.toml" {
47                 match Crate::from(&entry.path(), &self.repo_root.as_path()) {
48                     Ok(krate) => self.crates.insert_or_error(
49                         NameAndVersion::new(krate.name().to_string(), krate.version().clone()),
50                         krate,
51                     )?,
52                     Err(e) => match e.downcast_ref() {
53                         Some(CrateError::VirtualCrate(_)) => (),
54                         _ => return Err(e),
55                     },
56                 };
57             }
58         }
59         Ok(())
60     }
repo_root(&self) -> &Path61     pub fn repo_root(&self) -> &Path {
62         self.repo_root.as_path()
63     }
print(&self) -> Result<()>64     pub fn print(&self) -> Result<()> {
65         for krate in self.crates.values() {
66             krate.print()?
67         }
68         Ok(())
69     }
stage_crates(&self) -> Result<()>70     pub fn stage_crates(&self) -> Result<()> {
71         for krate in self.crates.values() {
72             krate.stage_crate()?
73         }
74         Ok(())
75     }
generate_android_bps(&mut self) -> Result<()>76     pub fn generate_android_bps(&mut self) -> Result<()> {
77         for (nv, output) in generate_android_bps(self.crates.values())?.into_iter() {
78             self.crates
79                 .get_mut(&nv)
80                 .ok_or(anyhow!("Failed to get crate {} {}", nv.name(), nv.version()))?
81                 .set_generate_android_bp_output(output);
82         }
83         Ok(())
84     }
diff_android_bps(&mut self) -> Result<()>85     pub fn diff_android_bps(&mut self) -> Result<()> {
86         for krate in self.crates.values_mut() {
87             krate.diff_android_bp()?;
88         }
89         Ok(())
90     }
91 }
92