cargo_geiger/
mapping.rs

1mod geiger;
2mod krates_mapping;
3mod metadata;
4
5use metadata::package_id::ToCargoMetadataPackage;
6
7use ::krates::Krates;
8use cargo::core::dependency::DepKind;
9use krates::cm::Metadata;
10use std::collections::HashSet;
11use std::fmt::Display;
12use std::path::PathBuf;
13
14use krates::cm::Dependency as CargoMetadataDependency;
15use krates::cm::PackageId as CargoMetadataPackageId;
16use krates::semver::Version as CargoMetadataVersion;
17
18use crate::mapping::krates_mapping::GetPackage;
19use crate::mapping::metadata::dependency::GetDependencyInformation;
20use crate::mapping::metadata::package::GetPackageInformation;
21use crate::mapping::metadata::GetMetadataPackages;
22
23use cargo_geiger_serde::DependencyKind as CargoGeigerSerdeDependencyKind;
24use cargo_geiger_serde::PackageId as CargoGeigerSerdePackageId;
25use cargo_geiger_serde::Source as CargoGeigerSerdeSource;
26
27/// Holds a pointer to both a `Krates` graph, and the `Metadata` struct
28/// which are often required together
29pub struct CargoMetadataParameters<'a> {
30    pub krates: &'a Krates,
31    pub metadata: &'a Metadata,
32}
33
34pub trait DepsNotReplaced {
35    fn deps_not_replaced<T: ToCargoMetadataPackage + Display>(
36        &self,
37        package_id: &T,
38        is_root_package: bool,
39    ) -> Option<Vec<(CargoMetadataPackageId, HashSet<CargoMetadataDependency>)>>;
40}
41
42pub trait GetPackageIdInformation {
43    fn get_package_id_licence<T: GetPackage>(
44        &self,
45        krates: &T,
46    ) -> Option<String>;
47
48    fn get_package_id_name_and_version<T: GetPackage>(
49        &self,
50        krates: &T,
51    ) -> Option<(String, CargoMetadataVersion)>;
52
53    fn get_package_id_repository<T: GetPackage>(
54        &self,
55        krates: &T,
56    ) -> Option<String>;
57}
58
59pub trait GetPackageRoot: GetPackageInformation {
60    fn get_root(&self) -> Option<PathBuf> {
61        match self.get_package_parent() {
62            Some(path) => Some(path.to_path_buf()),
63            None => {
64                eprintln!(
65                    "Failed to get root for: {} {:?}",
66                    self.get_package_name(),
67                    self.get_package_version()
68                );
69                None
70            }
71        }
72    }
73}
74
75pub trait MatchesIgnoringSource {
76    fn matches_ignoring_source<
77        T: GetPackage,
78        U: GetPackageIdInformation + Display,
79    >(
80        &self,
81        krates: &T,
82        package_id: &U,
83    ) -> Option<bool>;
84}
85
86pub trait QueryResolve {
87    fn query_resolve(&self, query: &str) -> Option<CargoMetadataPackageId>;
88}
89
90pub trait ToCargoCoreDepKind {
91    fn to_cargo_core_dep_kind(&self) -> DepKind;
92}
93
94pub trait ToCargoGeigerDependencyKind {
95    fn to_cargo_geiger_dependency_kind(
96        &self,
97    ) -> Option<CargoGeigerSerdeDependencyKind>;
98}
99
100pub trait ToCargoGeigerPackageId {
101    fn to_cargo_geiger_package_id(
102        &self,
103        metadata: &Metadata,
104    ) -> Option<CargoGeigerSerdePackageId>;
105}
106
107pub trait ToCargoGeigerSource {
108    fn to_cargo_geiger_source(
109        &self,
110        metadata: &Metadata,
111    ) -> CargoGeigerSerdeSource;
112}
113
114pub trait ToCargoMetadataPackageId: GetDependencyInformation {
115    fn to_cargo_metadata_package_id<T: GetMetadataPackages>(
116        &self,
117        metadata: &T,
118    ) -> Option<CargoMetadataPackageId> {
119        metadata
120            .get_metadata_packages()
121            .filter(|p| {
122                p.name == self.get_dependency_name()
123                    && self.get_dependency_version_req().matches(&p.version)
124            })
125            .map(|p| p.id.clone())
126            .collect::<Vec<CargoMetadataPackageId>>()
127            .pop()
128    }
129}
130
131#[cfg(test)]
132mod mapping_tests {
133    use super::*;
134
135    use rstest::*;
136    use std::path::Path;
137
138    struct MockPackage<'a> {
139        mock_package_name: String,
140        mock_package_parent: Option<&'a Path>,
141        mock_package_version: CargoMetadataVersion,
142    }
143
144    impl GetPackageInformation for MockPackage<'_> {
145        fn get_package_name(&self) -> String {
146            self.mock_package_name.clone()
147        }
148
149        fn get_package_parent(&self) -> Option<&Path> {
150            self.mock_package_parent
151        }
152
153        fn get_package_version(&self) -> CargoMetadataVersion {
154            self.mock_package_version.clone()
155        }
156    }
157
158    impl GetPackageRoot for MockPackage<'_> {}
159
160    #[rstest(
161        input_package_path_option,
162        expected_package_path_buf_option,
163        case(
164            Some(Path::new("/path/to/file")),
165            Some(PathBuf::from("/path/to/file"))
166        ),
167        case(None, None)
168    )]
169    fn get_package_root_test(
170        input_package_path_option: Option<&Path>,
171        expected_package_path_buf_option: Option<PathBuf>,
172    ) {
173        let _mock_package_parent = input_package_path_option;
174
175        let mock_package = MockPackage {
176            mock_package_name: String::from("package_name"),
177            mock_package_parent: input_package_path_option,
178            mock_package_version: CargoMetadataVersion::new(1, 1, 1),
179        };
180
181        assert_eq!(mock_package.get_root(), expected_package_path_buf_option)
182    }
183}