// SPDX-FileCopyrightText: 2024 Simon Bruder // // SPDX-License-Identifier: MPL-2.0 use std::cell::RefCell; use std::fs::{create_dir_all, File}; use std::io::Write; use std::path::PathBuf; use std::process::Command; use std::rc::Rc; use cargo_platform::Platform; use tempfile::{tempdir, TempDir}; use toml_edit::{value, DocumentMut}; pub(crate) type Result = std::result::Result>; #[derive(Debug)] pub(crate) struct SimpleManifest { pub(crate) name: String, pub(crate) version: String, pub(crate) license: Option, pub(crate) license_file: Option<(PathBuf, String)>, pub(crate) authors: Vec, pub(crate) repository: Option, pub(crate) dependencies: RefCell, Rc)>>, pub(crate) dev_dependencies: RefCell, Rc)>>, pub(crate) build_dependencies: RefCell, Rc)>>, } #[derive(Debug)] pub(crate) struct TestPackage { pub(crate) dir: TempDir, pub(crate) manifest: SimpleManifest, } fn set_dependency( doc: &mut DocumentMut, kind: &str, dependency: &(Option, Rc), ) { let (platform, dependency) = dependency; let val = value(dependency.dir.path().to_str().unwrap()); if let Some(platform) = platform { let target_spec = match platform { Platform::Name(name) => name.as_str(), Platform::Cfg(cfg) => &format!("cfg({cfg})"), }; doc["target"][target_spec][kind][&dependency.manifest.name]["path"] = val; } else { doc[kind][&dependency.manifest.name]["path"] = val; } } impl TestPackage { pub(crate) fn new(manifest: SimpleManifest) -> Result { let pkg = Self { dir: tempdir()?, manifest, }; pkg.update_files()?; Ok(pkg) } pub(crate) fn update_files(&self) -> Result<()> { let mut doc = DocumentMut::new(); doc["package"]["name"] = value(&self.manifest.name); doc["package"]["version"] = value(&self.manifest.version); if let Some(license) = &self.manifest.license { doc["package"]["license"] = value(license.to_string()); } if let Some((path, contents)) = &self.manifest.license_file { let mut license_file = File::create(self.dir.path().join(path))?; write!(license_file, "{}", contents)?; doc["package"]["license-file"] = value(path.to_str().unwrap()); } doc["package"]["authors"] = value(toml_edit::Array::from_iter(self.manifest.authors.iter())); if let Some(repository) = &self.manifest.repository { doc["package"]["repository"] = value(repository); } for dependency in self.manifest.dependencies.borrow().iter() { set_dependency(&mut doc, "dependencies", dependency); } for dev_dependency in self.manifest.dev_dependencies.borrow().iter() { set_dependency(&mut doc, "dev-dependencies", dev_dependency); } for build_dependency in self.manifest.build_dependencies.borrow().iter() { set_dependency(&mut doc, "build-dependencies", build_dependency); } write!(File::create(self.dir.path().join("Cargo.toml"))?, "{}", doc)?; create_dir_all(self.dir.path().join("src"))?; File::create(self.dir.path().join("src").join("lib.rs"))?; Command::new("cargo") .args(["generate-lockfile", "--quiet"]) .current_dir(self.dir.path()) .spawn()?; Ok(()) } pub(crate) fn manifest_path(&self) -> PathBuf { self.dir.path().join("Cargo.toml") } }