foundry_cli/opts/build/
paths.rs
1use clap::{Parser, ValueHint};
2use eyre::Result;
3use foundry_compilers::artifacts::remappings::Remapping;
4use foundry_config::{
5 figment,
6 figment::{
7 error::Kind::InvalidType,
8 value::{Dict, Map, Value},
9 Metadata, Profile, Provider,
10 },
11 find_project_root, remappings_from_env_var, Config,
12};
13use serde::Serialize;
14use std::path::PathBuf;
15
16#[derive(Clone, Debug, Default, Serialize, Parser)]
18#[command(next_help_heading = "Project options")]
19pub struct ProjectPathOpts {
20 #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH")]
25 #[serde(skip)]
26 pub root: Option<PathBuf>,
27
28 #[arg(long, short = 'C', value_hint = ValueHint::DirPath, value_name = "PATH")]
30 #[serde(rename = "src", skip_serializing_if = "Option::is_none")]
31 pub contracts: Option<PathBuf>,
32
33 #[arg(long, short = 'R')]
35 #[serde(skip)]
36 pub remappings: Vec<Remapping>,
37
38 #[arg(long, value_name = "ENV")]
40 #[serde(skip)]
41 pub remappings_env: Option<String>,
42
43 #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH")]
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub cache_path: Option<PathBuf>,
47
48 #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH")]
50 #[serde(rename = "libs", skip_serializing_if = "Vec::is_empty")]
51 pub lib_paths: Vec<PathBuf>,
52
53 #[arg(long, conflicts_with = "contracts", visible_alias = "hh")]
57 #[serde(skip)]
58 pub hardhat: bool,
59
60 #[arg(long, value_hint = ValueHint::FilePath, value_name = "FILE")]
62 #[serde(skip)]
63 pub config_path: Option<PathBuf>,
64}
65
66impl ProjectPathOpts {
67 #[track_caller]
75 pub fn project_root(&self) -> PathBuf {
76 self.root
77 .clone()
78 .unwrap_or_else(|| find_project_root(None).expect("could not determine project root"))
79 }
80
81 pub fn get_remappings(&self) -> Vec<Remapping> {
83 let mut remappings = self.remappings.clone();
84 if let Some(env_remappings) =
85 self.remappings_env.as_ref().and_then(|env| remappings_from_env_var(env))
86 {
87 remappings.extend(env_remappings.expect("Failed to parse env var remappings"));
88 }
89 remappings
90 }
91}
92
93foundry_config::impl_figment_convert!(ProjectPathOpts);
94
95impl Provider for ProjectPathOpts {
97 fn metadata(&self) -> Metadata {
98 Metadata::named("Project Paths Args Provider")
99 }
100
101 fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {
102 let value = Value::serialize(self)?;
103 let error = InvalidType(value.to_actual(), "map".into());
104 let mut dict = value.into_dict().ok_or(error)?;
105
106 let mut libs =
107 self.lib_paths.iter().map(|p| format!("{}", p.display())).collect::<Vec<_>>();
108
109 if self.hardhat {
110 dict.insert("src".to_string(), "contracts".to_string().into());
111 libs.push("node_modules".to_string());
112 }
113
114 if !libs.is_empty() {
115 dict.insert("libs".to_string(), libs.into());
116 }
117
118 Ok(Map::from([(Config::selected_profile(), dict)]))
119 }
120}