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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
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, } pub struct CookArgs { pub profile: OptimisationProfile, pub default_features: DefaultFeatures, pub features: Option<HashSet<String>>, pub target: Option<String>, pub target_dir: Option<PathBuf>, pub target_args: TargetArgs, pub manifest_path: Option<PathBuf>, pub package: Option<String>, pub workspace: 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, args: CookArgs) -> Result<(), anyhow::Error> { let current_directory = std::env::current_dir()?; self.skeleton.build_minimum_project(¤t_directory)?; build_dependencies(&args); self.skeleton .remove_compiled_dummies( current_directory, args.profile, args.target, args.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(args: &CookArgs) { let CookArgs { profile, default_features, features, target, target_dir, target_args, manifest_path, package, workspace, } = args; 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.iter().cloned().collect::<Vec<String>>().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"); } if let Some(manifest_path) = manifest_path { command_with_args.arg("--manifest-path").arg(manifest_path); } if let Some(package) = package { command_with_args.arg("--package").arg(package); } if *workspace { command_with_args.arg("--workspace"); } 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"), } } }