diff --git a/scarb/src/compiler/plugin/mod.rs b/scarb/src/compiler/plugin/mod.rs index 6f7fe3c3a..702c2146c 100644 --- a/scarb/src/compiler/plugin/mod.rs +++ b/scarb/src/compiler/plugin/mod.rs @@ -5,14 +5,35 @@ use std::fmt; use anyhow::{anyhow, bail, Result}; use cairo_lang_semantic::plugin::PluginSuite; use itertools::Itertools; +use serde::{Deserialize, Serialize}; -use crate::core::PackageId; +use crate::core::{Package, PackageId, TargetKind, Workspace}; use self::builtin::{BuiltinStarkNetPlugin, BuiltinTestPlugin}; pub mod builtin; pub mod proc_macro; +/// Properties that can be defined on Cairo plugin target. +#[derive(Debug, Serialize, Deserialize, Default)] +#[serde(rename_all = "kebab-case")] +pub struct CairoPluginProps { + /// Mark this macro plugin as builtin. + /// Builtin plugins are assumed to be available in `CairoPluginRepository` for the whole Scarb execution. + pub builtin: bool, +} + +pub fn fetch_cairo_plugin(package: &Package, ws: &Workspace<'_>) -> Result<()> { + assert!(package.is_cairo_plugin()); + let target = package.fetch_target(&TargetKind::CAIRO_PLUGIN)?; + let props: CairoPluginProps = target.props()?; + // No need to fetch for buildin plugins. + if !props.builtin { + proc_macro::fetch_package(package, ws)?; + } + Ok(()) +} + pub trait CairoPlugin: Sync { fn id(&self) -> PackageId; fn instantiate(&self) -> Result>; diff --git a/scarb/src/compiler/plugin/proc_macro/compilation.rs b/scarb/src/compiler/plugin/proc_macro/compilation.rs index 5e150de25..b85bd9715 100644 --- a/scarb/src/compiler/plugin/proc_macro/compilation.rs +++ b/scarb/src/compiler/plugin/proc_macro/compilation.rs @@ -40,23 +40,24 @@ impl SharedLibraryProvider for Package { } pub fn compile_unit(unit: ProcMacroCompilationUnit, ws: &Workspace<'_>) -> Result<()> { - run_cargo(CargoAction::Build, unit, ws) + let package = unit.components.first().unwrap().package.clone(); + run_cargo(CargoAction::Build, &package, ws) } pub fn check_unit(unit: ProcMacroCompilationUnit, ws: &Workspace<'_>) -> Result<()> { - run_cargo(CargoAction::Check, unit, ws) + let package = unit.components.first().unwrap().package.clone(); + run_cargo(CargoAction::Check, &package, ws) } -fn run_cargo( - action: CargoAction, - unit: ProcMacroCompilationUnit, - ws: &Workspace<'_>, -) -> Result<()> { - let main_package = unit.components.first().unwrap().package.clone(); +pub fn fetch_package(package: &Package, ws: &Workspace<'_>) -> Result<()> { + run_cargo(CargoAction::Fetch, package, ws) +} + +fn run_cargo(action: CargoAction, package: &Package, ws: &Workspace<'_>) -> Result<()> { let cmd = CargoCommand { action, - current_dir: main_package.root().to_path_buf(), - target_dir: main_package + current_dir: package.root().to_path_buf(), + target_dir: package .target_path(ws.config()) .path_unchecked() .to_path_buf(), @@ -80,6 +81,7 @@ fn run_cargo( enum CargoAction { Build, Check, + Fetch, } struct CargoCommand { @@ -95,12 +97,18 @@ impl From for Command { cmd.stderr(Stdio::inherit()); cmd.current_dir(args.current_dir); match args.action { + CargoAction::Fetch => cmd.arg("fetch"), CargoAction::Build => cmd.arg("build"), CargoAction::Check => cmd.arg("check"), }; - cmd.arg("--release"); - cmd.arg("--target-dir"); - cmd.arg(args.target_dir); + match args.action { + CargoAction::Fetch => (), + _ => { + cmd.arg("--release"); + cmd.arg("--target-dir"); + cmd.arg(args.target_dir); + } + } cmd } } diff --git a/scarb/src/compiler/plugin/proc_macro/mod.rs b/scarb/src/compiler/plugin/proc_macro/mod.rs index 0f77e16b0..e4419b22a 100644 --- a/scarb/src/compiler/plugin/proc_macro/mod.rs +++ b/scarb/src/compiler/plugin/proc_macro/mod.rs @@ -2,6 +2,6 @@ pub mod compilation; mod ffi; mod host; -pub use compilation::{check_unit, compile_unit}; +pub use compilation::{check_unit, compile_unit, fetch_package}; pub use ffi::*; pub use host::*; diff --git a/scarb/src/ops/resolve.rs b/scarb/src/ops/resolve.rs index 41ed9c8a1..bf771ac13 100644 --- a/scarb/src/ops/resolve.rs +++ b/scarb/src/ops/resolve.rs @@ -1,12 +1,6 @@ use std::collections::HashMap; -use anyhow::{bail, Result}; -use cairo_lang_filesystem::cfg::{Cfg, CfgSet}; -use futures::TryFutureExt; -use indoc::formatdoc; -use itertools::Itertools; -use serde::{Deserialize, Serialize}; - +use crate::compiler::plugin::{fetch_cairo_plugin, CairoPluginProps}; use crate::compiler::{ CairoCompilationUnit, CompilationUnit, CompilationUnitAttributes, CompilationUnitCairoPlugin, CompilationUnitComponent, ProcMacroCompilationUnit, @@ -27,6 +21,11 @@ use crate::core::{ use crate::internal::to_version::ToVersion; use crate::ops::lockfile::{read_lockfile, write_lockfile}; use crate::{resolver, DEFAULT_SOURCE_PATH}; +use anyhow::{bail, Result}; +use cairo_lang_filesystem::cfg::{Cfg, CfgSet}; +use futures::TryFutureExt; +use indoc::formatdoc; +use itertools::Itertools; pub struct WorkspaceResolve { pub resolve: Resolve, @@ -125,6 +124,12 @@ pub fn resolve_workspace_with_opts( let packages = collect_packages_from_resolve_graph(&resolve, &patched).await?; + packages + .values() + .filter(|p| p.is_cairo_plugin()) + .map(|p| fetch_cairo_plugin(p, ws)) + .collect::>>()?; + Ok(WorkspaceResolve { resolve, packages }) } .into_future(), @@ -304,15 +309,6 @@ fn generate_cairo_compilation_units( .collect::>>() } -/// Properties that can be defined on Cairo plugin target. -#[derive(Debug, Serialize, Deserialize, Default)] -#[serde(rename_all = "kebab-case")] -struct CairoPluginProps { - /// Mark this macro plugin as builtin. - /// Builtin plugins are assumed to be available in `CairoPluginRepository` for the whole Scarb execution. - pub builtin: bool, -} - pub struct PackageSolutionCollector<'a> { member: &'a Package, resolve: &'a WorkspaceResolve, diff --git a/scarb/tests/build_cairo_plugin.rs b/scarb/tests/build_cairo_plugin.rs index 76f35f059..37e3cbf3d 100644 --- a/scarb/tests/build_cairo_plugin.rs +++ b/scarb/tests/build_cairo_plugin.rs @@ -122,6 +122,20 @@ fn check_cairo_plugin() { "#}); } +#[test] +fn resolve_fetched_plugins() { + let t = TempDir::new().unwrap(); + simple_project(&t); + assert!(!t.child("Cargo.lock").exists()); + let output = Scarb::quick_snapbox() + .arg("fetch") + .current_dir(&t) + .output() + .unwrap(); + assert!(output.status.success()); + assert!(t.child("Cargo.lock").exists()) +} + #[test] fn compile_cairo_plugin_with_lib_target() { let t = TempDir::new().unwrap();