melodium_repository/
utils.rs

1use crate::global::{Author, Package as PackageDetails, Tag, Type as TypeDetails};
2use crate::technical::{Package, Type};
3use cargo_metadata::{CargoOpt, DependencyKind, MetadataCommand};
4use core::fmt::Display;
5use melodium_common::descriptor::PackageRequirement;
6use std::path::PathBuf;
7
8#[derive(Debug)]
9pub enum Error {
10    Melodium(String),
11    Metadata(cargo_metadata::Error),
12}
13
14impl Display for Error {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        match self {
17            Error::Melodium(str) => write!(f, "{str}"),
18            Error::Metadata(err) => write!(f, "{err}"),
19        }
20    }
21}
22
23impl std::error::Error for Error {}
24
25impl From<cargo_metadata::Error> for Error {
26    fn from(value: cargo_metadata::Error) -> Self {
27        Error::Metadata(value)
28    }
29}
30
31pub fn cargo_toml(
32    package: &str,
33    path: impl Into<PathBuf>,
34) -> Result<(Package, PackageDetails), Error> {
35    let metadata = MetadataCommand::new()
36        .features(CargoOpt::SomeFeatures(vec!["real".into(), "plugin".into()]))
37        .manifest_path(path)
38        .exec()?;
39
40    let rust_name = format!("{package}-mel");
41
42    if let Some(rust_package) = metadata.packages.iter().find(|p| p.name == rust_name) {
43        Ok((rust_package.into(), rust_package.into()))
44    } else {
45        Err(Error::Melodium(format!(
46            "Package '{package}' not found (looking for '{rust_name}')"
47        )))
48    }
49}
50
51impl From<&cargo_metadata::Package> for Package {
52    fn from(value: &cargo_metadata::Package) -> Self {
53        Package {
54            name: value
55                .name
56                .strip_suffix("-mel")
57                .unwrap_or(&value.name)
58                .to_string(),
59            version: value.version.clone(),
60            requirements: value
61                .dependencies
62                .iter()
63                .filter_map(|dep| {
64                    dep.name
65                        .strip_suffix("-mel")
66                        .filter(|_| dep.kind == DependencyKind::Normal)
67                        .map(|name| PackageRequirement {
68                            package: name.to_string(),
69                            version_requirement: dep.req.clone(),
70                        })
71                })
72                .collect(),
73
74            r#type: Type::Compiled {
75                crate_name: value.name.clone(),
76                platforms: vec![],
77            },
78        }
79    }
80}
81
82impl From<&cargo_metadata::Package> for PackageDetails {
83    fn from(value: &cargo_metadata::Package) -> Self {
84        PackageDetails {
85            name: value
86                .name
87                .strip_suffix("-mel")
88                .unwrap_or(&value.name)
89                .to_string(),
90            authors: value.authors.iter().map(|a| Author::new(a)).collect(),
91            publication: chrono::Utc::now(),
92            description: vec![(
93                "en".to_string(),
94                value.description.clone().unwrap_or_default(),
95            )]
96            .into_iter()
97            .collect(),
98            version: value.version.clone(),
99            license: value.license.clone().unwrap_or_default(),
100            homepage: value.homepage.clone(),
101            repository: value.repository.clone(),
102            r#type: TypeDetails::Compiled,
103            tags: vec![Tag::Std],
104        }
105    }
106}