|
1 | 1 | use std::collections::HashMap; |
| 2 | +use std::convert::Infallible; |
2 | 3 | use std::env; |
3 | 4 | use std::env::consts::ARCH; |
4 | 5 | use std::ffi::OsString; |
| 6 | +use std::fmt::Debug; |
5 | 7 | use std::path::PathBuf; |
6 | 8 |
|
7 | 9 | use anyhow::{Context, Result}; |
8 | 10 | use clap::{Parser, Subcommand}; |
9 | 11 | use const_format::formatcp; |
10 | 12 |
|
11 | 13 | use crate::cargo_cmd::{CargoCmd as _, cargo_cmd}; |
| 14 | +use crate::toolchain; |
12 | 15 |
|
13 | 16 | pub struct Args { |
14 | 17 | pub manifest_path: Option<PathBuf>, |
15 | 18 | pub target_dir: PathBuf, |
16 | 19 | pub target: String, |
17 | 20 | pub env: HashMap<OsString, OsString>, |
18 | 21 | pub current_dir: PathBuf, |
| 22 | + pub clang: Option<PathBuf>, |
| 23 | + pub ar: Option<PathBuf>, |
| 24 | +} |
| 25 | + |
| 26 | +pub trait WarningLevel { |
| 27 | + type Error; |
| 28 | + fn warning<T: Debug>( |
| 29 | + &self, |
| 30 | + msg: &str, |
| 31 | + err: impl Into<anyhow::Error>, |
| 32 | + default: T, |
| 33 | + ) -> Result<T, Self::Error>; |
| 34 | +} |
| 35 | + |
| 36 | +pub struct Warning; |
| 37 | + |
| 38 | +#[doc(hidden)] |
| 39 | +pub mod warning { |
| 40 | + pub struct WarningIgnore; |
| 41 | + pub struct WarningWarn; |
| 42 | + #[allow(dead_code)] |
| 43 | + pub struct WarningError; |
| 44 | +} |
| 45 | + |
| 46 | +impl Warning { |
| 47 | + pub const IGNORE: warning::WarningIgnore = warning::WarningIgnore; |
| 48 | + pub const WARN: warning::WarningWarn = warning::WarningWarn; |
| 49 | + #[allow(dead_code)] |
| 50 | + pub const ERROR: warning::WarningError = warning::WarningError; |
| 51 | +} |
| 52 | + |
| 53 | +impl WarningLevel for warning::WarningIgnore { |
| 54 | + type Error = Infallible; |
| 55 | + fn warning<T: Debug>( |
| 56 | + &self, |
| 57 | + _msg: &str, |
| 58 | + _err: impl Into<anyhow::Error>, |
| 59 | + default: T, |
| 60 | + ) -> Result<T, Self::Error> { |
| 61 | + Ok(default) |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +impl WarningLevel for warning::WarningWarn { |
| 66 | + type Error = Infallible; |
| 67 | + fn warning<T: Debug>( |
| 68 | + &self, |
| 69 | + msg: &str, |
| 70 | + err: impl Into<anyhow::Error>, |
| 71 | + default: T, |
| 72 | + ) -> Result<T, Self::Error> { |
| 73 | + warning(msg); |
| 74 | + warning(format!("using {default:?}")); |
| 75 | + println!("{:?}", err.into()); |
| 76 | + Ok(default) |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +impl WarningLevel for warning::WarningError { |
| 81 | + type Error = anyhow::Error; |
| 82 | + fn warning<T: Debug>( |
| 83 | + &self, |
| 84 | + msg: &str, |
| 85 | + err: impl Into<anyhow::Error>, |
| 86 | + _default: T, |
| 87 | + ) -> Result<T, Self::Error> { |
| 88 | + Err(err.into()).context(msg.to_string()) |
| 89 | + } |
19 | 90 | } |
20 | 91 |
|
21 | 92 | impl Args { |
22 | | - pub fn parse_from( |
| 93 | + pub fn parse<W: WarningLevel>( |
23 | 94 | args: impl IntoIterator<Item = impl Into<OsString> + Clone>, |
24 | 95 | env: impl IntoIterator<Item = (impl Into<OsString>, impl Into<OsString>)>, |
25 | 96 | cwd: Option<impl Into<PathBuf>>, |
26 | | - ) -> Result<Args> { |
| 97 | + warn: W, |
| 98 | + ) -> Result<Args, W::Error> { |
27 | 99 | let mut args = ArgsImpl::parse_from(args); |
28 | 100 | args.env = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); |
29 | | - args.current_dir = match cwd { |
| 101 | + let cwd = match cwd { |
30 | 102 | Some(cwd) => cwd.into(), |
31 | | - None => env::current_dir().context("Failed to get current directory")?, |
| 103 | + None => match env::current_dir() { |
| 104 | + Ok(cwd) => cwd, |
| 105 | + Err(err) => { |
| 106 | + warn.warning("Could not get current directory", err, PathBuf::from("."))? |
| 107 | + } |
| 108 | + }, |
32 | 109 | }; |
33 | | - args.try_into() |
| 110 | + args.current_dir = cwd.clone(); |
| 111 | + Args::try_from_with_defaults(warn, args) |
34 | 112 | } |
35 | 113 | } |
36 | 114 |
|
| 115 | +fn warning(msg: impl AsRef<str>) { |
| 116 | + eprintln!( |
| 117 | + "{}{}{}", |
| 118 | + console::style("warning").yellow().bold(), |
| 119 | + console::style(": ").bold(), |
| 120 | + console::style(msg.as_ref()).bold(), |
| 121 | + ); |
| 122 | +} |
| 123 | + |
37 | 124 | impl TryFrom<ArgsImpl> for Args { |
38 | 125 | type Error = anyhow::Error; |
39 | 126 |
|
40 | 127 | fn try_from(value: ArgsImpl) -> Result<Self> { |
| 128 | + Args::try_from_with_defaults(Warning::ERROR, value) |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +impl Args { |
| 133 | + fn try_from_with_defaults<W: WarningLevel>(warn: W, value: ArgsImpl) -> Result<Self, W::Error> { |
41 | 134 | let manifest_path = value.manifest_path; |
42 | 135 |
|
43 | 136 | let target_dir = match value.target_dir { |
44 | 137 | Some(dir) => dir, |
45 | | - None => resolve_target_dir(&manifest_path, &value.env, &value.current_dir)?, |
| 138 | + None => match resolve_target_dir(&manifest_path, &value.env, &value.current_dir) { |
| 139 | + Ok(dir) => dir, |
| 140 | + Err(err) => warn.warning( |
| 141 | + "could not resolve target directory", |
| 142 | + err, |
| 143 | + value.current_dir.join("target"), |
| 144 | + )?, |
| 145 | + }, |
46 | 146 | }; |
47 | 147 |
|
48 | 148 | let target = match value.target { |
49 | 149 | Some(triplet) => triplet, |
50 | | - None => resolve_target(&value.env, &value.current_dir)?, |
| 150 | + None => match resolve_target(&value.env, &value.current_dir) { |
| 151 | + Ok(triplet) => triplet, |
| 152 | + Err(err) => warn.warning( |
| 153 | + "could not resolve target triple", |
| 154 | + err, |
| 155 | + DEFAULT_TARGET.to_string(), |
| 156 | + )?, |
| 157 | + }, |
| 158 | + }; |
| 159 | + |
| 160 | + let target = if target.ends_with("-hyperlight-none") { |
| 161 | + target |
| 162 | + } else { |
| 163 | + let (arch, _) = target.split_once('-').unwrap_or((&target, "")); |
| 164 | + warn.warning( |
| 165 | + "requested target is not a hyperlight target", |
| 166 | + anyhow::anyhow!("invalid hyperlight target: {target}"), |
| 167 | + format!("{arch}-hyperlight-none"), |
| 168 | + )? |
51 | 169 | }; |
52 | 170 |
|
53 | | - let cwd = env::current_dir().context("Failed to get current directory")?; |
54 | | - let target_dir = cwd.join(target_dir); |
| 171 | + let target_dir = value.current_dir.join(target_dir); |
55 | 172 |
|
56 | 173 | Ok(Args { |
57 | 174 | manifest_path, |
58 | 175 | target_dir, |
59 | 176 | target, |
60 | 177 | env: value.env, |
61 | 178 | current_dir: value.current_dir, |
| 179 | + clang: toolchain::find_cc().ok(), |
| 180 | + ar: toolchain::find_ar().ok(), |
62 | 181 | }) |
63 | 182 | } |
64 | 183 | } |
|
0 commit comments