Skip to content

Commit ee7f7a2

Browse files
authored
Scarb execute name change, arguments file, error msgs (#1888)
- **Rename scarb-cairo-execute to scarb-execute** - **Support reading arguments from file in scarb execute** - **Unify error messages in scarb execute**
1 parent 5e2567b commit ee7f7a2

File tree

8 files changed

+181
-70
lines changed

8 files changed

+181
-70
lines changed

Cargo.lock

+26-25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = [
33
"scarb",
44
"scarb-metadata",
55
"extensions/scarb-doc",
6-
"extensions/scarb-cairo-execute",
6+
"extensions/scarb-execute",
77
"extensions/scarb-cairo-language-server",
88
"extensions/scarb-cairo-run",
99
"extensions/scarb-cairo-test",

extensions/scarb-cairo-run/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fn main_inner(ui: &Ui, args: Args) -> Result<()> {
111111
ensure!(
112112
path.exists(),
113113
formatdoc! {r#"
114-
package has not been compiled, file does not exist: {filename}
114+
package has not been compiled, file does not exist: `{filename}`
115115
help: run `scarb build` to compile the package
116116
"#}
117117
);

extensions/scarb-cairo-run/tests/examples.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ fn build_can_be_skipped() {
5858

5959
#[cfg(windows)]
6060
snapbox.stdout_eq(indoc! {r#"
61-
error: package has not been compiled, file does not exist: hello_world.sierra.json
61+
error: package has not been compiled, file does not exist: `hello_world.sierra.json`
6262
help: run `scarb build` to compile the package
6363
error: process did not exit successfully: exit code: 1
6464
"#});
6565
#[cfg(not(windows))]
6666
snapbox.stdout_eq(indoc! {r#"
67-
error: package has not been compiled, file does not exist: hello_world.sierra.json
67+
error: package has not been compiled, file does not exist: `hello_world.sierra.json`
6868
help: run `scarb build` to compile the package
6969
"#});
7070
}

extensions/scarb-cairo-execute/Cargo.toml extensions/scarb-execute/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "scarb-cairo-execute"
2+
name = "scarb-execute"
33
publish = false
44

55
authors.workspace = true
@@ -15,6 +15,7 @@ anyhow.workspace = true
1515
bincode.workspace = true
1616
cairo-lang-executable.workspace = true
1717
cairo-lang-runner.workspace = true
18+
cairo-lang-utils.workspace = true
1819
cairo-vm.workspace = true
1920
camino.workspace = true
2021
clap.workspace = true

extensions/scarb-cairo-execute/src/main.rs extensions/scarb-execute/src/main.rs

+48-23
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use anyhow::{bail, ensure, Context, Result};
22
use bincode::enc::write::Writer;
33
use cairo_lang_executable::executable::{EntryPointKind, Executable};
44
use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor};
5+
use cairo_lang_utils::bigint::BigUintAsHex;
56
use cairo_vm::cairo_run::cairo_run_program;
67
use cairo_vm::cairo_run::CairoRunConfig;
78
use cairo_vm::types::layout_name::LayoutName;
@@ -48,9 +49,8 @@ struct Args {
4849

4950
#[derive(Parser, Clone, Debug)]
5051
struct ExecutionArgs {
51-
/// Serialized arguments to the executable function.
52-
#[arg(long, value_delimiter = ',')]
53-
arguments: Vec<BigInt>,
52+
#[command(flatten)]
53+
pub arguments: ProgramArguments,
5454

5555
/// Desired execution output, either default Standard or CairoPie
5656
#[arg(long, default_value = "standard")]
@@ -65,6 +65,37 @@ struct ExecutionArgs {
6565
print_program_output: bool,
6666
}
6767

68+
#[derive(Parser, Debug, Clone)]
69+
pub struct ProgramArguments {
70+
/// Serialized arguments to the executable function.
71+
#[arg(long, value_delimiter = ',')]
72+
arguments: Vec<BigInt>,
73+
74+
/// Serialized arguments to the executable function from a file.
75+
#[arg(long, conflicts_with = "arguments")]
76+
arguments_file: Option<Utf8PathBuf>,
77+
}
78+
79+
impl ProgramArguments {
80+
pub fn read_arguments(self) -> Result<Vec<Arg>> {
81+
if let Some(path) = self.arguments_file {
82+
let file = fs::File::open(&path).with_context(|| "reading arguments file failed")?;
83+
let as_vec: Vec<BigUintAsHex> = serde_json::from_reader(file)
84+
.with_context(|| "deserializing arguments file failed")?;
85+
Ok(as_vec
86+
.into_iter()
87+
.map(|v| Arg::Value(v.value.into()))
88+
.collect())
89+
} else {
90+
Ok(self
91+
.arguments
92+
.iter()
93+
.map(|v| Arg::Value(v.into()))
94+
.collect())
95+
}
96+
}
97+
}
98+
6899
#[derive(ValueEnum, Clone, Debug)]
69100
enum OutputFormat {
70101
CairoPie,
@@ -142,7 +173,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
142173
.entrypoints
143174
.iter()
144175
.find(|e| matches!(e.kind, EntryPointKind::Standalone))
145-
.with_context(|| "No `Standalone` entrypoint found.")?;
176+
.with_context(|| "no `Standalone` entrypoint found")?;
146177
Program::new_for_proof(
147178
entrypoint.builtins.clone(),
148179
data,
@@ -159,7 +190,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
159190
.entrypoints
160191
.iter()
161192
.find(|e| matches!(e.kind, EntryPointKind::Bootloader))
162-
.with_context(|| "No `Bootloader` entrypoint found.")?;
193+
.with_context(|| "no `Bootloader` entrypoint found")?;
163194
Program::new(
164195
entrypoint.builtins.clone(),
165196
data,
@@ -171,17 +202,11 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
171202
None,
172203
)
173204
}
174-
.with_context(|| "Failed setting up program.")?;
205+
.with_context(|| "failed setting up program")?;
175206

176207
let mut hint_processor = CairoHintProcessor {
177208
runner: None,
178-
user_args: vec![vec![Arg::Array(
179-
args.run
180-
.arguments
181-
.iter()
182-
.map(|v| Arg::Value(v.into()))
183-
.collect(),
184-
)]],
209+
user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]],
185210
string_to_hint,
186211
starknet_state: Default::default(),
187212
run_resources: Default::default(),
@@ -203,12 +228,12 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
203228
.with_context(|| "Cairo program run failed")?;
204229

205230
if args.run.print_program_output {
206-
let mut output_buffer = "Program Output:\n".to_string();
231+
let mut output_buffer = "Program output:\n".to_string();
207232
runner.vm.write_output(&mut output_buffer)?;
208-
print!("{output_buffer}");
233+
ui.print(output_buffer.trim_end());
209234
}
210235

211-
let output_dir = scarb_target_dir.join("scarb-execute");
236+
let output_dir = scarb_target_dir.join("execute");
212237
create_output_dir(output_dir.as_std_path())?;
213238

214239
if args.run.output.is_cairo_pie() {
@@ -231,7 +256,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
231256
let relocated_trace = runner
232257
.relocated_trace
233258
.as_ref()
234-
.with_context(|| "Trace not relocated.")?;
259+
.with_context(|| "trace not relocated")?;
235260
let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?;
236261
cairo_run::write_encoded_trace(relocated_trace, &mut writer)?;
237262
writer.flush()?;
@@ -253,7 +278,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> {
253278
.get_air_private_input()
254279
.to_serializable(trace_path.to_string(), memory_path.to_string())
255280
.serialize_json()
256-
.with_context(|| "Failed serializing private input.")?;
281+
.with_context(|| "failed serializing private input")?;
257282
fs::write(air_private_input_path, output_value)?;
258283
}
259284

@@ -275,14 +300,14 @@ fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result<Executa
275300
ensure!(
276301
file_path.exists(),
277302
formatdoc! {r#"
278-
package has not been compiled, file does not exist: {filename}
303+
package has not been compiled, file does not exist: `{filename}`
279304
help: run `scarb build` to compile the package
280305
"#}
281306
);
282307
let file = fs::File::open(&file_path)
283-
.with_context(|| format!("failed to open executable program: {file_path}"))?;
308+
.with_context(|| format!("failed to open executable program: `{file_path}`"))?;
284309
serde_json::from_reader(file)
285-
.with_context(|| format!("failed to deserialize executable program: {file_path}"))
310+
.with_context(|| format!("failed to deserialize executable program: `{file_path}`"))
286311
}
287312

288313
fn incremental_create_output_file(
@@ -294,7 +319,7 @@ fn incremental_create_output_file(
294319
path,
295320
name,
296321
extension,
297-
"Failed to create output directory.",
322+
"failed to create output directory",
298323
|p| {
299324
OpenOptions::new()
300325
.write(true)
@@ -306,7 +331,7 @@ fn incremental_create_output_file(
306331
}
307332

308333
fn incremental_create_output_dir(path: &Utf8Path, name: String) -> Result<Utf8PathBuf> {
309-
incremental_attempt_io_creation(path, name, "", "Failed to create output directory.", |p| {
334+
incremental_attempt_io_creation(path, name, "", "failed to create output directory", |p| {
310335
fs::create_dir(p)
311336
})
312337
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use assert_fs::fixture::{FileWriteStr, PathChild};
2+
use assert_fs::TempDir;
3+
use indoc::indoc;
4+
use scarb_test_support::command::Scarb;
5+
use scarb_test_support::project_builder::ProjectBuilder;
6+
7+
#[test]
8+
fn can_take_big_number_as_arg() {
9+
let t = TempDir::new().unwrap();
10+
11+
ProjectBuilder::start()
12+
.name("hello")
13+
.version("0.1.0")
14+
.manifest_extra(indoc! {r#"
15+
[executable]
16+
"#})
17+
.dep_cairo_execute()
18+
.lib_cairo(indoc! {r#"
19+
#[executable]
20+
fn main(a: felt252, b: felt252) -> felt252 {
21+
b
22+
}
23+
"#})
24+
.build(&t);
25+
26+
Scarb::quick_snapbox()
27+
.arg("execute")
28+
.arg("--print-program-output")
29+
.arg("--arguments")
30+
.arg(r#"1,1129815197211541481934112806673325772687763881719835256646064516195041515616"#)
31+
.current_dir(&t)
32+
.assert()
33+
.success()
34+
.stdout_matches(indoc! {r#"
35+
[..]Compiling hello v0.1.0 ([..]/Scarb.toml)
36+
[..]Finished `dev` profile target(s) in [..]
37+
[..]Executing hello
38+
Program output:
39+
0
40+
1129815197211541481934112806673325772687763881719835256646064516195041515616
41+
Saving output to: target/execute/hello
42+
"#});
43+
}
44+
45+
#[test]
46+
fn can_read_arguments_from_file() {
47+
let t = TempDir::new().unwrap();
48+
49+
ProjectBuilder::start()
50+
.name("hello")
51+
.version("0.1.0")
52+
.manifest_extra(indoc! {r#"
53+
[executable]
54+
"#})
55+
.dep_cairo_execute()
56+
.lib_cairo(indoc! {r#"
57+
#[executable]
58+
fn main(a: felt252, b: felt252) -> felt252 {
59+
b
60+
}
61+
"#})
62+
.build(&t);
63+
64+
t.child("args.txt")
65+
.write_str(r#"["0x1","0x27F73E6C94FA8249EC9F2F4EEC607ACC97FA632C9E8FB6C49437E62390D9860"]"#)
66+
.unwrap();
67+
68+
Scarb::quick_snapbox()
69+
.arg("execute")
70+
.arg("--print-program-output")
71+
.args(["--arguments-file", "args.txt"])
72+
.current_dir(&t)
73+
.assert()
74+
.success()
75+
.stdout_matches(indoc! {r#"
76+
[..]Compiling hello v0.1.0 ([..]/Scarb.toml)
77+
[..]Finished `dev` profile target(s) in [..]
78+
[..]Executing hello
79+
Program output:
80+
0
81+
1129815197211541481934112806673325772687763881719835256646064516195041515616
82+
Saving output to: target/execute/hello
83+
"#});
84+
}

0 commit comments

Comments
 (0)