1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
use crate::Skeleton; use anyhow::Context; use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::path::PathBuf; use std::process::Command; #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub struct Recipe { pub skeleton: Skeleton, } pub struct TargetArgs { pub benches: bool, pub tests: bool, pub examples: bool, pub all_targets: bool, } impl Recipe { pub fn prepare(base_path: PathBuf) -> Result<Self, anyhow::Error> { let skeleton = Skeleton::derive(&base_path)?; Ok(Recipe { skeleton }) } pub fn cook( &self, profile: OptimisationProfile, default_features: DefaultFeatures, features: Option<HashSet<String>>, target: Option<String>, target_dir: Option<PathBuf>, target_args: TargetArgs, ) -> Result<(), anyhow::Error> { let current_directory = std::env::current_dir()?; self.skeleton.build_minimum_project(¤t_directory)?; build_dependencies( profile, default_features, features, &target, &target_dir, target_args, ); self.skeleton .remove_compiled_dummy_libraries(current_directory, profile, target, target_dir) .context("Failed to clean up dummy compilation artifacts.")?; Ok(()) } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum OptimisationProfile { Release, Debug, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum DefaultFeatures { Enabled, Disabled, } fn build_dependencies( profile: OptimisationProfile, default_features: DefaultFeatures, features: Option<HashSet<String>>, target: &Option<String>, target_dir: &Option<PathBuf>, target_args: TargetArgs, ) { let mut command = Command::new("cargo"); let command_with_args = command.arg("build"); if profile == OptimisationProfile::Release { command_with_args.arg("--release"); } if default_features == DefaultFeatures::Disabled { command_with_args.arg("--no-default-features"); } if let Some(features) = features { let feature_flag = features.into_iter().collect::<Vec<_>>().join(","); command_with_args.arg("--features").arg(feature_flag); } if let Some(target) = target { command_with_args.arg("--target").arg(target); } if let Some(target_dir) = target_dir { command_with_args.arg("--target-dir").arg(target_dir); } if target_args.benches { command_with_args.arg("--benches"); } if target_args.tests { command_with_args.arg("--tests"); } if target_args.examples { command_with_args.arg("--examples"); } if target_args.all_targets { command_with_args.arg("--all-targets"); } execute_command(command_with_args); } fn execute_command(command: &mut Command) { let mut child = command .envs(std::env::vars()) .spawn() .expect("Failed to execute process"); let exit_status = child.wait().expect("Failed to run command"); if !exit_status.success() { match exit_status.code() { Some(code) => panic!("Exited with status code: {}", code), None => panic!("Process terminated by signal"), } } }