Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scarb: cairo run #171

Merged
merged 1 commit into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
687 changes: 145 additions & 542 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ glob = "0.3.0"
cairo-felt = "0.8.2"

# Cairo runner dependencies
cairo-lang-test-runner = {git = "https://github.com/starkware-libs/cairo", tag = "v2.3.0"}
cairo-lang-test-plugin = {git = "https://github.com/starkware-libs/cairo", tag = "v2.3.0"}
cairo-lang-test-runner = {git = "https://github.com/starkware-libs/cairo", rev = "bf91adecc5a1cb2ced041ba383d7b7c38dd2fa7f"}
cairo-lang-test-plugin = {git = "https://github.com/starkware-libs/cairo", rev = "bf91adecc5a1cb2ced041ba383d7b7c38dd2fa7f"}
cairo-lang-runner = {git = "https://github.com/starkware-libs/cairo", rev = "bf91adecc5a1cb2ced041ba383d7b7c38dd2fa7f"}
cairo-lang-sierra = {git = "https://github.com/starkware-libs/cairo", rev = "bf91adecc5a1cb2ced041ba383d7b7c38dd2fa7f"}
scarb = { git = "https://github.com/software-mansion/scarb", version = "2.3.0" }
scarb-ui = { git = "https://github.com/software-mansion/scarb", version = "0.1.0" }

Expand Down
44 changes: 22 additions & 22 deletions info.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
[[exercises]]
name = "intro1"
path = "exercises/intro/intro1.cairo"
mode = "build"
mode = "run"
hint = """
No hints this time ;)
"""

[[exercises]]
name = "intro2"
path = "exercises/intro/intro2.cairo"
mode = "build"
mode = "run"
hint = """
No hints this time ;)
"""
Expand All @@ -21,15 +21,15 @@ No hints this time ;)
[[exercises]]
name = "variables1"
path = "exercises/variables/variables1.cairo"
mode = "build"
mode = "run"
hint = """
The declaration on line 8 is missing a keyword that is needed in Cairo
to create a new variable binding."""

[[exercises]]
name = "variables2"
path = "exercises/variables/variables2.cairo"
mode = "build"
mode = "run"
hint = """
What happens if you annotate line 7 with a type annotation?
What if you give x a value?
Expand All @@ -40,7 +40,7 @@ What if x is the same type as 10? What if it's a different type? (e.g. a u8)"""
[[exercises]]
name = "variables3"
path = "exercises/variables/variables3.cairo"
mode = "build"
mode = "run"
hint = """
Oops! In this exercise, we have a variable binding that we've created on
line 7, and we're trying to use it on line 8, but we haven't given it a
Expand All @@ -51,7 +51,7 @@ programming language -- thankfully the Cairo compiler has caught this for us!"""
[[exercises]]
name = "variables4"
path = "exercises/variables/variables4.cairo"
mode = "build"
mode = "run"
hint = """
In Cairo, variable bindings are immutable by default. But here we're trying
to reassign a different value to x! There's a keyword we can use to make
Expand All @@ -60,7 +60,7 @@ a variable binding mutable instead."""
[[exercises]]
name = "variables5"
path = "exercises/variables/variables5.cairo"
mode = "build"
mode = "run"
hint = """
In variables4 we already learned how to make an immutable variable mutable
using a special keyword. Unfortunately this doesn't help us much in this exercise
Expand All @@ -75,7 +75,7 @@ Try to solve this exercise afterwards using this technique."""
[[exercises]]
name = "variables6"
path = "exercises/variables/variables6.cairo"
mode = "build"
mode = "run"
hint = """
We know about variables and mutability, but there is another important type of
variable available: constants.
Expand All @@ -90,19 +90,19 @@ You can read about the constants here: https://book.cairo-lang.org/ch02-01-varia
[[exercises]]
name = "primitive_types1"
path = "exercises/primitive_types/primitive_types1.cairo"
mode = "build"
mode = "run"
hint = "No hints this time ;)"

[[exercises]]
name = "primitive_types2"
path = "exercises/primitive_types/primitive_types2.cairo"
mode = "build"
mode = "run"
hint = "No hints this time ;)"

[[exercises]]
name = "primitive_types3"
path = "exercises/primitive_types/primitive_types3.cairo"
mode = "build"
mode = "run"
hint = """
You'll need to make a pattern to bind `name` and `age` to the appropriate parts
of the tuple.
Expand Down Expand Up @@ -168,7 +168,7 @@ conditions checking different input values."""
[[exercises]]
name = "functions1"
path = "exercises/functions/functions1.cairo"
mode = "build"
mode = "run"
hint = """
This main function is calling a function that it expects to exist, but the
function doesn't exist. It expects this function to have the name `call_me`.
Expand All @@ -178,15 +178,15 @@ Sounds a lot like `main`, doesn't it?"""
[[exercises]]
name = "functions2"
path = "exercises/functions/functions2.cairo"
mode = "build"
mode = "run"
hint = """
Cairo requires that all parts of a function's signature have type annotations,
but `call_me` is missing the type annotation of `num`. What is the basic type in Cairo?"""

[[exercises]]
name = "functions3"
path = "exercises/functions/functions3.cairo"
mode = "build"
mode = "run"
hint = """
This time, the function *declaration* is okay, but there's something wrong
with the place where we're calling the function.
Expand All @@ -197,7 +197,7 @@ Watch mode will only jump to the next exercise if you remove the I AM NOT DONE c
[[exercises]]
name = "functions4"
path = "exercises/functions/functions4.cairo"
mode = "build"
mode = "run"
hint = """
The error message points to line 18 and says it expects a type after the
`->`. This is where the function's return type should be -- take a look at
Expand Down Expand Up @@ -235,13 +235,13 @@ You can return values from loops by adding the value you want returned after the
[[exercises]]
name = "enums1"
path = "exercises/enums/enums1.cairo"
mode = "build"
mode = "run"
hint = "https://book.cairo-lang.org/ch06-01-enums.html"

[[exercises]]
name = "enums2"
path = "exercises/enums/enums2.cairo"
mode = "build"
mode = "run"
hint = """
You can create enumerations that have different variants with different types
such as no data, structs, a single felt string, tuples, ...etc
Expand Down Expand Up @@ -385,7 +385,7 @@ This section will help you understanding more about methods https://book.cairo-l
[[exercises]]
name = "move_semantics1"
path = "exercises/move_semantics/move_semantics1.cairo"
mode = "build"
mode = "run"
hint = """
So you've got the "ref argument must be a mutable variable." error on line 17,
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 17
Expand All @@ -399,7 +399,7 @@ Read more about move semantics and ownership here: https://book.cairo-lang.org/c
[[exercises]]
name = "move_semantics2"
path = "exercises/move_semantics/move_semantics2.cairo"
mode = "build"
mode = "run"
hint = """
So, `arr0` is passed into the `fill_arr` function as an argument. In Cairo,
when an argument is passed to a function and it's not explicitly returned,
Expand All @@ -420,7 +420,7 @@ There's a few ways to fix this, try them all if you want:
[[exercises]]
name = "move_semantics3"
path = "exercises/move_semantics/move_semantics3.cairo"
mode = "build"
mode = "run"
hint = """
The difference between this one and the previous ones is that the first line
of `fn fill_arr` that had `let mut arr = arr;` is no longer there. You can,
Expand All @@ -430,7 +430,7 @@ an existing binding to be a mutable binding instead of an immutable one :)"""
[[exercises]]
name = "move_semantics4"
path = "exercises/move_semantics/move_semantics4.cairo"
mode = "build"
mode = "run"
hint = """
Stop reading whenever you feel like you have enough direction :) Or try
doing one step and then fixing the compiler errors that result!
Expand All @@ -456,7 +456,7 @@ Can we still use it later on?
[[exercises]]
name = "move_semantics6"
path = "exercises/move_semantics/move_semantics6.cairo"
mode = "build"
mode = "run"
hint = """
The first problem is that `get_value` is taking ownership of the Number struct.
So `Number` is moved and can't be used for `set_value`
Expand Down
8 changes: 7 additions & 1 deletion src/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::io::Read;
use std::path::PathBuf;
use std::process::{self};

use crate::scarb::{scarb_build, scarb_test};
use crate::scarb::{scarb_build, scarb_run, scarb_test};

const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE";
const CONTEXT: usize = 2;
Expand All @@ -29,6 +29,8 @@ fn temp_file() -> String {
pub enum Mode {
// Indicates that the exercise should be compiled as a binary
Build,
// Indicates that the exercise should run
Run,
// Indicates that the exercise should be tested
Test,
}
Expand Down Expand Up @@ -95,6 +97,10 @@ impl Exercise {
scarb_build(&self.path)
}

pub fn run(&self) -> anyhow::Result<String> {
scarb_run(&self.path)
}

pub fn test(&self) -> anyhow::Result<String> {
scarb_test(&self.path)
}
Expand Down
27 changes: 23 additions & 4 deletions src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::exercise::{Exercise, Mode};
// the output from the test harnesses (if the mode of the exercise is test)
pub fn run(exercise: &Exercise) -> Result<(), ()> {
match exercise.mode {
Mode::Build => run_cairo(exercise)?,
Mode::Build => build_cairo(exercise)?,
Mode::Run => run_cairo(exercise)?,
Mode::Test => test_cairo(exercise)?,
}
Ok(())
Expand All @@ -30,8 +31,8 @@ pub fn reset(exercise: &Exercise) -> Result<(), ()> {
// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
fn run_cairo(exercise: &Exercise) -> Result<(), ()> {
println!("\nRunning {exercise}...\n");
fn build_cairo(exercise: &Exercise) -> Result<(), ()> {
println!("\nBuilding {exercise}...\n");
let output = exercise.build();

if let Some(error) = output.as_ref().err() {
Expand All @@ -45,6 +46,24 @@ fn run_cairo(exercise: &Exercise) -> Result<(), ()> {
}
}

// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
fn run_cairo(exercise: &Exercise) -> Result<(), ()> {
println!("\nRunning {exercise}...\n");
let output = exercise.run();

if let Some(error) = output.as_ref().err() {
println!("{error}");
Err(())
} else {
let message = output.unwrap();
println!("{message}");
success!("Successfully ran {}", exercise);
Ok(())
}
}

// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
Expand All @@ -58,7 +77,7 @@ fn test_cairo(exercise: &Exercise) -> Result<(), ()> {
} else {
let message = output.unwrap();
println!("{message}");
success!("Successfully built {}", exercise);
success!("Successfully tested {}", exercise);
Ok(())
}
}
84 changes: 84 additions & 0 deletions src/scarb.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::{env::current_dir, fs, path::PathBuf};

use anyhow::Context;
use cairo_lang_runner::{RunResultValue, SierraCasmRunner, StarknetState};
use cairo_lang_sierra::program::VersionedProgram;
use cairo_lang_test_plugin::TestCompilation;
use cairo_lang_test_runner::{CompiledTestRunner, TestRunConfig};
use camino::Utf8PathBuf;

use itertools::Itertools;
use scarb::{
core::{Config, TargetKind},
ops::{self, collect_metadata, CompileOpts, MetadataOptions},
Expand Down Expand Up @@ -39,6 +42,87 @@ pub fn scarb_build(file_path: &PathBuf) -> anyhow::Result<String> {
}
}

// Runs the crate with scarb
pub fn scarb_run(file_path: &PathBuf) -> anyhow::Result<String> {
let crate_path = prepare_crate_for_exercise(file_path);
let config = scarb_config(crate_path);

let ws = ops::read_workspace(config.manifest_path(), &config)?;

// Compile before running tests, with test targets true
compile(&config, false)?;

let metadata = collect_metadata(
&MetadataOptions {
version: 1,
no_deps: false,
},
&ws,
)?;

let profile = "dev";
let default_target_dir = metadata.runtime_manifest.join("target");

let target_dir = metadata
.target_dir
.clone()
.unwrap_or(default_target_dir)
.join(profile);

// Process 'exercise_crate' targets
// Largely same as this
// https://github.com/software-mansion/scarb/blob/50e5d942f72a7b756c36fdc57b7899ad8b6ff7c7/extensions/scarb-cairo-run/src/main.rs#L61
for package in metadata.packages.iter() {
if package.name != "exercise_crate" {
continue;
}
// Loop through targets and run compiled file tests
for target in package.targets.iter() {
// Skip test targets
if target.kind == "test" {
continue;
}

let file_path = target_dir.join(format!("{}.sierra.json", target.name.clone()));

assert!(
file_path.exists(),
"File {file_path} missing, please compile the project."
);

let sierra_program = serde_json::from_str::<VersionedProgram>(
&fs::read_to_string(file_path.clone())
.with_context(|| format!("failed to read Sierra file: {file_path}"))?,
)
.with_context(|| format!("failed to deserialize Sierra program: {file_path}"))?
.into_v1()
.with_context(|| format!("failed to load Sierra program: {file_path}"))?;

let runner = SierraCasmRunner::new(sierra_program.program, None, Default::default())?;

let result = runner
.run_function_with_starknet_context(
runner.find_function("::main")?,
&[],
None,
StarknetState::default(),
)
.context("failed to run the function")?;

return match result.value {
RunResultValue::Success(return_val) => {
Ok(return_val.iter().map(|el| el.to_string()).join(","))
}
RunResultValue::Panic(error) => {
anyhow::bail!(format!("error running the code, {:?}", error))
}
};
}
}

Ok("".into())
}

// Runs tests on the testing crate with scarb
pub fn scarb_test(file_path: &PathBuf) -> anyhow::Result<String> {
let crate_path = prepare_crate_for_exercise(file_path);
Expand Down
Loading