diff --git a/scarb/src/bin/scarb/commands/external.rs b/scarb/src/bin/scarb/commands/external.rs index 3584bcdc0..4d6a97059 100644 --- a/scarb/src/bin/scarb/commands/external.rs +++ b/scarb/src/bin/scarb/commands/external.rs @@ -3,10 +3,13 @@ use std::ffi::OsString; use anyhow::{anyhow, Result}; use scarb::core::Config; +use scarb::ops; use scarb::ops::execute_external_subcommand; #[tracing::instrument(skip_all, level = "info")] pub fn run(args: Vec, config: &Config) -> Result<()> { + let ws = ops::read_workspace(config.manifest_path(), config)?; + let Some((cmd, args)) = args.split_first() else { panic!("`args` should never be empty.") }; @@ -15,5 +18,5 @@ pub fn run(args: Vec, config: &Config) -> Result<()> { .to_str() .ok_or_else(|| anyhow!("command name must be valid UTF-8"))?; - execute_external_subcommand(cmd, args, config, None) + execute_external_subcommand(cmd, args, None, &ws) } diff --git a/scarb/src/compiler/compilation_unit.rs b/scarb/src/compiler/compilation_unit.rs index a61de56eb..e9e66b414 100644 --- a/scarb/src/compiler/compilation_unit.rs +++ b/scarb/src/compiler/compilation_unit.rs @@ -5,7 +5,7 @@ use cairo_lang_filesystem::cfg::CfgSet; use smol_str::SmolStr; use crate::compiler::Profile; -use crate::core::{Config, ManifestCompilerConfig, Package, PackageId, Target}; +use crate::core::{ManifestCompilerConfig, Package, PackageId, Target, Workspace}; use crate::flock::Filesystem; use crate::internal::stable_hash::StableHasher; @@ -77,8 +77,8 @@ impl CompilationUnit { &self.main_component().target } - pub fn target_dir<'c>(&self, config: &'c Config) -> Filesystem<'c> { - config.target_dir().child(self.profile.as_str()) + pub fn target_dir<'c>(&self, ws: &'c Workspace<'_>) -> Filesystem<'c> { + ws.target_dir().child(self.profile.as_str()) } pub fn is_sole_for_package(&self) -> bool { diff --git a/scarb/src/compiler/compilers/lib.rs b/scarb/src/compiler/compilers/lib.rs index ffaf4a41a..cc8377a1c 100644 --- a/scarb/src/compiler/compilers/lib.rs +++ b/scarb/src/compiler/compilers/lib.rs @@ -50,7 +50,7 @@ impl Compiler for LibCompiler { ); } - let target_dir = unit.target_dir(ws.config()); + let target_dir = unit.target_dir(ws); let compiler_config = build_compiler_config(&unit, ws); diff --git a/scarb/src/compiler/compilers/starknet_contract.rs b/scarb/src/compiler/compilers/starknet_contract.rs index f59846cc9..c4ccfc5e8 100644 --- a/scarb/src/compiler/compilers/starknet_contract.rs +++ b/scarb/src/compiler/compilers/starknet_contract.rs @@ -204,7 +204,7 @@ impl Compiler for StarknetContractCompiler { ); } - let target_dir = unit.target_dir(ws.config()); + let target_dir = unit.target_dir(ws); let compiler_config = build_compiler_config(&unit, ws); diff --git a/scarb/src/core/config.rs b/scarb/src/core/config.rs index 8668d2e09..b73ce9c42 100644 --- a/scarb/src/core/config.rs +++ b/scarb/src/core/config.rs @@ -18,15 +18,14 @@ use crate::compiler::{CompilerRepository, Profile}; use crate::core::AppDirs; #[cfg(doc)] use crate::core::Workspace; -use crate::flock::{AdvisoryLock, RootFilesystem}; +use crate::flock::AdvisoryLock; use crate::internal::fsx; -use crate::DEFAULT_TARGET_DIR_NAME; use crate::SCARB_ENV; pub struct Config { manifest_path: Utf8PathBuf, dirs: Arc, - target_dir: RootFilesystem, + target_dir_override: Option, app_exe: OnceCell, ui: Ui, creation_time: Instant, @@ -64,14 +63,6 @@ impl Config { } } - let target_dir = - RootFilesystem::new_output_dir(b.target_dir_override.unwrap_or_else(|| { - b.manifest_path - .parent() - .expect("parent of manifest path must always exist") - .join(DEFAULT_TARGET_DIR_NAME) - })); - let compilers = b.compilers.unwrap_or_else(CompilerRepository::std); let compiler_plugins = b.cairo_plugins.unwrap_or_else(CairoPluginRepository::std); let profile: Profile = b.profile.unwrap_or_default(); @@ -83,7 +74,7 @@ impl Config { Ok(Self { manifest_path: b.manifest_path, dirs, - target_dir, + target_dir_override: b.target_dir_override, app_exe: OnceCell::new(), ui, creation_time, @@ -116,8 +107,8 @@ impl Config { &self.dirs } - pub fn target_dir(&self) -> &RootFilesystem { - &self.target_dir + pub fn target_dir_override(&self) -> Option<&Utf8PathBuf> { + self.target_dir_override.as_ref() } pub fn app_exe(&self) -> Result<&Path> { diff --git a/scarb/src/core/workspace.rs b/scarb/src/core/workspace.rs index 8e8b9ac4b..842e68f41 100644 --- a/scarb/src/core/workspace.rs +++ b/scarb/src/core/workspace.rs @@ -10,7 +10,7 @@ use crate::core::config::Config; use crate::core::package::Package; use crate::core::PackageId; use crate::flock::RootFilesystem; -use crate::MANIFEST_FILE_NAME; +use crate::{DEFAULT_TARGET_DIR_NAME, MANIFEST_FILE_NAME}; /// The core abstraction for working with a workspace of packages. /// @@ -19,9 +19,10 @@ use crate::MANIFEST_FILE_NAME; pub struct Workspace<'c> { config: &'c Config, members: BTreeMap, - root_package: Option, manifest_path: Utf8PathBuf, profiles: Vec, + root_package: Option, + target_dir: RootFilesystem, } impl<'c> Workspace<'c> { @@ -36,11 +37,19 @@ impl<'c> Workspace<'c> { .iter() .map(|p| (p.id, p.clone())) .collect::>(); + let target_dir = config.target_dir_override().cloned().unwrap_or_else(|| { + manifest_path + .parent() + .expect("parent of manifest path must always exist") + .join(DEFAULT_TARGET_DIR_NAME) + }); + let target_dir = RootFilesystem::new_output_dir(target_dir); Ok(Self { config, manifest_path, - root_package, profiles, + root_package, + target_dir, members: packages, }) } @@ -52,6 +61,7 @@ impl<'c> Workspace<'c> { ) -> Result { let manifest_path = package.manifest_path().to_path_buf(); let root_package = Some(package.id); + Self::new( manifest_path, vec![package].as_ref(), @@ -77,7 +87,7 @@ impl<'c> Workspace<'c> { } pub fn target_dir(&self) -> &RootFilesystem { - self.config.target_dir() + &self.target_dir } /// Returns the current package of this workspace. diff --git a/scarb/src/ops/clean.rs b/scarb/src/ops/clean.rs index ec8d0806e..abf04ba0a 100644 --- a/scarb/src/ops/clean.rs +++ b/scarb/src/ops/clean.rs @@ -2,10 +2,12 @@ use anyhow::{Context, Result}; use crate::core::Config; use crate::internal::fsx; +use crate::ops; #[tracing::instrument(skip_all, level = "debug")] pub fn clean(config: &Config) -> Result<()> { - let path = config.target_dir().path_unchecked(); + let ws = ops::read_workspace(config.manifest_path(), config)?; + let path = ws.target_dir().path_unchecked(); if path.exists() { fsx::remove_dir_all(path).context("failed to clean generated artifacts")?; } diff --git a/scarb/src/ops/scripts.rs b/scarb/src/ops/scripts.rs index e84bf313d..ff2b871ec 100644 --- a/scarb/src/ops/scripts.rs +++ b/scarb/src/ops/scripts.rs @@ -19,7 +19,7 @@ pub fn execute_script( cwd: &Utf8Path, custom_env: Option>, ) -> Result<()> { - let env_vars = get_env_vars(ws.config())? + let env_vars = get_env_vars(ws)? .into_iter() .map(|(k, v)| { ( diff --git a/scarb/src/ops/subcommands.rs b/scarb/src/ops/subcommands.rs index accff8568..1806d787f 100644 --- a/scarb/src/ops/subcommands.rs +++ b/scarb/src/ops/subcommands.rs @@ -14,14 +14,14 @@ use crate::ops; use crate::process::{exec_replace, is_executable}; use crate::subcommands::{get_env_vars, EXTERNAL_CMD_PREFIX, SCARB_MANIFEST_PATH_ENV}; -#[tracing::instrument(level = "debug", skip(config))] +#[tracing::instrument(level = "debug", skip(ws))] pub fn execute_external_subcommand( cmd: &str, args: &[OsString], - config: &Config, custom_env: Option>, + ws: &Workspace<'_>, ) -> Result<()> { - let Some(cmd) = find_external_subcommand(cmd, config) else { + let Some(cmd) = find_external_subcommand(cmd, ws.config()) else { // TODO(mkaput): Reuse clap's no such command message logic here. bail!("no such command: `{cmd}`"); }; @@ -32,7 +32,7 @@ pub fn execute_external_subcommand( let mut cmd = Command::new(cmd); cmd.args(args); - cmd.envs(get_env_vars(config)?); + cmd.envs(get_env_vars(ws)?); if let Some(env) = custom_env { cmd.envs(env); } @@ -65,7 +65,7 @@ pub fn execute_test_subcommand( &format!("cairo-test {package_name}"), )); let args = args.iter().map(OsString::from).collect::>(); - execute_external_subcommand("cairo-test", args.as_ref(), ws.config(), env) + execute_external_subcommand("cairo-test", args.as_ref(), env, ws) } } diff --git a/scarb/src/subcommands.rs b/scarb/src/subcommands.rs index 73282dd37..04fad6f22 100644 --- a/scarb/src/subcommands.rs +++ b/scarb/src/subcommands.rs @@ -1,4 +1,4 @@ -use crate::core::Config; +use crate::core::Workspace; use crate::SCARB_ENV; use std::collections::HashMap; use std::ffi::OsString; @@ -7,7 +7,8 @@ pub const EXTERNAL_CMD_PREFIX: &str = "scarb-"; pub const SCARB_MANIFEST_PATH_ENV: &str = "SCARB_MANIFEST_PATH"; /// Defines env vars passed to external subcommands. -pub fn get_env_vars(config: &Config) -> anyhow::Result> { +pub fn get_env_vars(ws: &Workspace<'_>) -> anyhow::Result> { + let config = ws.config(); Ok(HashMap::from_iter([ ("PATH".into(), config.dirs().path_env()), ( @@ -25,7 +26,7 @@ pub fn get_env_vars(config: &Config) -> anyhow::Result(); + + let pkg_metadata = Scarb::quick_snapbox() + .args(["--json", "metadata", "--format-version", "1"]) + .current_dir(&pkg1) + .stdout_json::(); + + assert_eq!(root_metadata.target_dir, pkg_metadata.target_dir); + assert_eq!( + root_metadata + .target_dir + .unwrap() + .to_owned() + .into_std_path_buf(), + t.child("target").canonicalize().unwrap() + ); +}