Skip to content

Commit

Permalink
Parse [cairo-plugin] in Scarb.toml
Browse files Browse the repository at this point in the history
commit-id:289e98b3
  • Loading branch information
mkaput committed May 18, 2023
1 parent 7926855 commit 1e1de66
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 26 deletions.
84 changes: 59 additions & 25 deletions scarb/src/core/manifest/toml_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct TomlManifest {
pub package: Option<Box<TomlPackage>>,
pub dependencies: Option<BTreeMap<PackageName, TomlDependency>>,
pub lib: Option<TomlTarget<TomlLibTargetParams>>,
pub cairo_plugin: Option<TomlTarget<TomlCairoPluginTargetParams>>,
pub target: Option<BTreeMap<TomlTargetKind, Vec<TomlTarget<TomlExternalTargetParams>>>>,
pub cairo: Option<TomlCairo>,
pub tool: Option<ToolDefinition>,
Expand Down Expand Up @@ -134,6 +135,12 @@ pub struct TomlLibTargetParams {
pub casm: Option<bool>,
}

#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct TomlCairoPluginTargetParams {
pub builtin: Option<PackageName>,
}

pub type TomlExternalTargetParams = BTreeMap<SmolStr, toml::Value>;

#[derive(Debug, Default, Deserialize, Serialize, Clone)]
Expand Down Expand Up @@ -272,41 +279,35 @@ impl TomlManifest {

let mut targets = Vec::new();

if let Some(lib_toml) = &self.lib {
let name = lib_toml
.name
.clone()
.unwrap_or_else(|| package_name.clone());

let target = Target::try_from_structured_params(
Target::LIB,
name,
default_source_path.clone(),
&lib_toml.params,
)?;
targets.push(target);
}
targets.extend(Self::collect_target(
Target::LIB,
self.lib.as_ref(),
&package_name,
&default_source_path,
)?);

targets.extend(Self::collect_target(
Target::CAIRO_PLUGIN,
self.cairo_plugin.as_ref(),
&package_name,
&default_source_path,
)?);

for (kind_toml, ext_toml) in self
.target
.iter()
.flatten()
.flat_map(|(k, vs)| vs.iter().map(|v| (k.clone(), v)))
{
let name = ext_toml
.name
.clone()
.unwrap_or_else(|| package_name.clone());

let target = Target::try_from_structured_params(
targets.extend(Self::collect_target(
kind_toml,
name,
default_source_path.clone(),
&ext_toml.params,
)?;
targets.push(target);
Some(ext_toml),
&package_name,
&default_source_path,
)?);
}

Self::check_cairo_plugin_target_is_exclusive(&targets)?;
Self::check_unique_targets(&targets, &package_name)?;

if targets.is_empty() {
Expand All @@ -318,6 +319,39 @@ impl TomlManifest {
Ok(targets)
}

fn collect_target<T: Serialize>(
kind: impl Into<SmolStr>,
target: Option<&TomlTarget<T>>,
default_name: &SmolStr,
default_source_path: &Utf8Path,
) -> Result<Option<Target>> {
let Some(target) = target else {
return Ok(None);
};

let name = target.name.clone().unwrap_or_else(|| default_name.clone());

let target = Target::try_from_structured_params(
kind,
name,
default_source_path.to_path_buf(),
&target.params,
)?;

Ok(Some(target))
}

fn check_cairo_plugin_target_is_exclusive(targets: &[Target]) -> Result<()> {
if targets.iter().any(Target::is_cairo_plugin) {
ensure!(
targets.len() == 1,
"target `{}` cannot be mixed with other targets",
Target::CAIRO_PLUGIN,
);
}
Ok(())
}

fn check_unique_targets(targets: &[Target], package_name: &str) -> Result<()> {
let mut used = HashSet::with_capacity(targets.len());
for target in targets {
Expand Down
18 changes: 17 additions & 1 deletion scarb/src/ops/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub fn generate_compilation_units(
let mut units = Vec::with_capacity(ws.members().size_hint().0);
for member in ws.members() {
units.extend(if member.is_cairo_plugin() {
todo!("Compiling Cairo plugins is not implemented yet.")
generate_cairo_plugin_compilation_units(&member)?
} else {
generate_cairo_compilation_units(&member, resolve, ws)?
});
Expand Down Expand Up @@ -240,3 +240,19 @@ fn check_cairo_version_compatibility(packages: &[Package], ws: &Workspace<'_>) -
}
Ok(())
}

fn generate_cairo_plugin_compilation_units(member: &Package) -> Result<Vec<CompilationUnit>> {
let target = member.fetch_target(Target::CAIRO_PLUGIN)?;

// If this is a built-in plugin package, then compiling it boils down to doing nothing.
if target
.params
.as_table()
.map(|t| t.contains_key("builtin"))
.unwrap()
{
return Ok(vec![]);
}

bail!("compiling Cairo plugin packages is possible yet")
}
118 changes: 118 additions & 0 deletions scarb/tests/e2e/build_cairo_plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use assert_fs::TempDir;
use indoc::indoc;

use crate::support::command::Scarb;
use crate::support::project_builder::ProjectBuilder;

#[test]
fn compile_cairo_plugin() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.manifest_extra(r#"[cairo-plugin]"#)
.build(&t);

Scarb::quick_snapbox()
.arg("build")
.current_dir(&t)
.assert()
.failure()
.stdout_matches(indoc! {r#"
error: compiling Cairo plugin packages is possible yet
"#});
}

#[test]
fn compile_known_builtin() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.manifest_extra(indoc! {r#"
[cairo-plugin]
builtin = "starknet"
"#})
.build(&t);

Scarb::quick_snapbox()
.arg("build")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Finished release target(s) in [..]
"#});
}

#[test]
fn compile_unknown_builtin() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.manifest_extra(indoc! {r#"
[cairo-plugin]
builtin = "i_definitely_do_not_exist"
"#})
.build(&t);

Scarb::quick_snapbox()
.arg("build")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Finished release target(s) in [..]
"#});
}

#[test]
fn compile_cairo_plugin_with_lib_target() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.manifest_extra(indoc! {r#"
[lib]
[cairo-plugin]
"#})
.build(&t);

Scarb::quick_snapbox()
.arg("build")
.current_dir(&t)
.assert()
.failure()
.stdout_matches(indoc! {r#"
error: failed to parse manifest at `[..]/Scarb.toml`
Caused by:
target `cairo-plugin` cannot be mixed with other targets
"#});
}

#[test]
fn compile_cairo_plugin_with_other_target() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.manifest_extra(indoc! {r#"
[cairo-plugin]
[[target.starknet-contract]]
"#})
.build(&t);

Scarb::quick_snapbox()
.arg("build")
.current_dir(&t)
.assert()
.failure()
.stdout_matches(indoc! {r#"
error: failed to parse manifest at `[..]/Scarb.toml`
Caused by:
target `cairo-plugin` cannot be mixed with other targets
"#});
}
1 change: 1 addition & 0 deletions scarb/tests/e2e/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod add;
mod build;
mod build_cairo_plugin;
mod build_starknet_contract;
mod build_targets;
mod clean;
Expand Down

0 comments on commit 1e1de66

Please sign in to comment.