xref: /aosp_15_r20/development/tools/external_crates/crate_tool/src/crate_type.rs (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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 anyhow::{anyhow, Result};
16 use cargo::{
17     core::{Manifest, SourceId},
18     util::toml::read_manifest,
19     Config,
20 };
21 use name_and_version::{NameAndVersionRef, NamedAndVersioned};
22 use rooted_path::RootedPath;
23 use semver::Version;
24 
25 use crate::CrateError;
26 
27 #[derive(Debug, Clone)]
28 pub struct Crate {
29     manifest: Manifest,
30     path: RootedPath,
31 }
32 
33 impl NamedAndVersioned for Crate {
name(&self) -> &str34     fn name(&self) -> &str {
35         self.manifest.name().as_str()
36     }
version(&self) -> &Version37     fn version(&self) -> &Version {
38         self.manifest.version()
39     }
key(&self) -> NameAndVersionRef40     fn key(&self) -> NameAndVersionRef {
41         NameAndVersionRef::new(self.name(), self.version())
42     }
43 }
44 
45 impl Crate {
new(manifest: Manifest, path: RootedPath) -> Crate46     pub fn new(manifest: Manifest, path: RootedPath) -> Crate {
47         Crate { manifest, path }
48     }
from(manifest_dir: RootedPath) -> Result<Crate>49     pub fn from(manifest_dir: RootedPath) -> Result<Crate> {
50         let source_id = SourceId::for_path(manifest_dir.abs())?;
51         let (manifest, _nested) = read_manifest(
52             manifest_dir.join("Cargo.toml").unwrap().as_ref(),
53             source_id,
54             &Config::default()?,
55         )?;
56         match manifest {
57             cargo::core::EitherManifest::Real(r) => Ok(Crate::new(r, manifest_dir)),
58             cargo::core::EitherManifest::Virtual(_) => {
59                 Err(anyhow!(CrateError::VirtualCrate(manifest_dir.as_ref().to_path_buf())))
60             }
61         }
62     }
63 
description(&self) -> &str64     pub fn description(&self) -> &str {
65         self.manifest.metadata().description.as_deref().unwrap_or("")
66     }
license(&self) -> Option<&str>67     pub fn license(&self) -> Option<&str> {
68         self.manifest.metadata().license.as_deref()
69     }
repository(&self) -> Option<&str>70     pub fn repository(&self) -> Option<&str> {
71         self.manifest.metadata().repository.as_deref()
72     }
path(&self) -> &RootedPath73     pub fn path(&self) -> &RootedPath {
74         &self.path
75     }
76 
is_migration_denied(&self) -> bool77     pub fn is_migration_denied(&self) -> bool {
78         const MIGRATION_DENYLIST: &[&str] = &[
79             "external/rust/crates/openssl/", // It's complicated.
80             "external/rust/cxx/",            // It's REALLY complicated.
81         ];
82         MIGRATION_DENYLIST.iter().any(|prefix| self.path().rel().starts_with(prefix))
83     }
84 }
85 
86 #[cfg(test)]
87 mod tests {
88     use std::{
89         fs::{create_dir, write},
90         path::Path,
91     };
92 
93     use super::*;
94     use anyhow::anyhow;
95     use tempfile::tempdir;
96 
write_test_manifest(temp_crate_dir: &Path, name: &str, version: &str) -> Result<RootedPath>97     fn write_test_manifest(temp_crate_dir: &Path, name: &str, version: &str) -> Result<RootedPath> {
98         let temp_crate_dir = RootedPath::new("/", temp_crate_dir.strip_prefix("/")?)?;
99         write(
100             temp_crate_dir.join("Cargo.toml")?,
101             format!("[package]\nname = \"{}\"\nversion = \"{}\"\n", name, version),
102         )?;
103         let lib_rs = temp_crate_dir.join("src/lib.rs")?;
104         create_dir(lib_rs.abs().parent().ok_or(anyhow!("Failed to get parent"))?)?;
105         write(lib_rs, "// foo")?;
106         Ok(temp_crate_dir)
107     }
108 
109     #[test]
test_from_and_properties() -> Result<()>110     fn test_from_and_properties() -> Result<()> {
111         let temp_crate_dir = tempdir()?;
112         let manifest_dir = write_test_manifest(temp_crate_dir.path(), "foo", "1.2.0")?;
113         let krate = Crate::from(manifest_dir)?;
114         assert_eq!(krate.name(), "foo");
115         assert_eq!(krate.version().to_string(), "1.2.0");
116         Ok(())
117     }
118 
119     #[test]
test_from_error() -> Result<()>120     fn test_from_error() -> Result<()> {
121         let temp_crate_dir = tempdir()?;
122         let manifest_dir = write_test_manifest(temp_crate_dir.path(), "foo", "1.2.0")?;
123         assert!(Crate::from(manifest_dir.join("blah")?).is_err());
124         Ok(())
125     }
126 }
127