Skip to content

Commit 7717157

Browse files
committed
fix test & non-interactive logic
1 parent 358e921 commit 7717157

File tree

5 files changed

+92
-187
lines changed

5 files changed

+92
-187
lines changed

crates/cargo-pvm-contract/src/main.rs

Lines changed: 75 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,16 @@ enum Commands {
2828

2929
#[derive(Parser, Debug, Default)]
3030
struct PvmContractArgs {
31-
#[arg(long, value_enum, requires = "non_interactive")]
31+
#[arg(long, value_enum)]
3232
init_type: Option<InitType>,
33-
#[arg(long, requires = "non_interactive")]
33+
#[arg(long)]
3434
example: Option<String>,
35-
#[arg(long, value_enum, requires = "non_interactive")]
35+
#[arg(long, value_enum)]
3636
memory_model: Option<MemoryModel>,
37-
#[arg(long, requires = "non_interactive")]
37+
#[arg(long)]
3838
name: Option<String>,
39-
#[arg(long, requires = "non_interactive")]
40-
sol_file: Option<PathBuf>,
4139
#[arg(long)]
42-
non_interactive: bool,
40+
sol_file: Option<PathBuf>,
4341
}
4442

4543
#[derive(Debug, Clone, Copy, PartialEq, ValueEnum)]
@@ -143,218 +141,128 @@ fn main() -> Result<()> {
143141
}
144142

145143
fn init_command(args: PvmContractArgs) -> Result<()> {
146-
let builder_path = std::env::var("CARGO_PVM_CONTRACT_BUILDER_PATH")
147-
.ok()
148-
.filter(|value| !value.trim().is_empty())
149-
.map(PathBuf::from);
150-
151-
if let Some(path) = builder_path.as_deref()
152-
&& !path.exists()
153-
{
154-
anyhow::bail!("Builder path does not exist: {}", path.display());
155-
}
156-
157-
if args.non_interactive {
158-
init_command_non_interactive(args, builder_path.as_deref())
159-
} else {
160-
init_command_interactive(builder_path.as_deref())
161-
}
162-
}
163-
164-
fn init_command_interactive(builder_path: Option<&std::path::Path>) -> Result<()> {
165-
// First, prompt for initialization type
166-
let init_types = vec![InitType::SolidityFile, InitType::Example, InitType::Blank];
167-
let init_type = Select::new("How do you want to initialize the project?", init_types)
168-
.prompt()
169-
.context("Failed to get initialization type")?;
144+
// Get init_type from args or prompt
145+
let init_type = match args.init_type {
146+
Some(t) => t,
147+
None => {
148+
let init_types = vec![InitType::SolidityFile, InitType::Example, InitType::Blank];
149+
Select::new("How do you want to initialize the project?", init_types)
150+
.prompt()
151+
.context("Failed to get initialization type")?
152+
}
153+
};
170154

171155
match init_type {
172156
InitType::Blank => {
173-
// Ask for name without prefill
174-
let contract_name = Text::new("What is your contract name?")
175-
.with_help_message("This will be the name of the project directory")
176-
.prompt()
177-
.context("Failed to get contract name")?;
178-
179-
if contract_name.is_empty() {
180-
anyhow::bail!("Contract name cannot be empty");
181-
}
182-
157+
let contract_name = prompt_name(args.name, None)?;
183158
check_dir_exists(&contract_name)?;
184159
debug!("Initializing blank contract: {contract_name}");
185-
scaffold::init_blank_contract(&contract_name, builder_path)
160+
scaffold::init_blank_contract(&contract_name)
186161
}
187162
InitType::Example => {
188163
let examples = load_examples()?;
189-
let example = Select::new("Select an example:", examples)
190-
.prompt()
191-
.context("Failed to get example choice")?;
192164

193-
// Prompt for memory model
194-
let memory_models = vec![MemoryModel::AllocWithAlloy, MemoryModel::NoAlloc];
195-
let memory_model = Select::new("Which memory model do you want to use?", memory_models)
196-
.prompt()
197-
.context("Failed to get memory model choice")?;
165+
// Get example from args or prompt
166+
let example = match args.example {
167+
Some(example_name) => find_example(&examples, &example_name)?,
168+
None => Select::new("Select an example:", examples)
169+
.prompt()
170+
.context("Failed to get example choice")?,
171+
};
198172

199-
// Ask for name with example name as default
200-
let contract_name = Text::new("What is your contract name?")
201-
.with_default(&example.name)
202-
.with_help_message("This will be the name of the project directory")
203-
.prompt()
204-
.context("Failed to get contract name")?;
205-
206-
if contract_name.is_empty() {
207-
anyhow::bail!("Contract name cannot be empty");
208-
}
173+
let memory_model = prompt_memory_model(args.memory_model)?;
174+
let contract_name = prompt_name(args.name, Some(&example.name))?;
209175

210176
check_dir_exists(&contract_name)?;
211177
debug!(
212178
"Initializing from example: {} with memory model: {:?}",
213179
example.filename, memory_model
214180
);
215181

216-
init_from_example(&example, &contract_name, memory_model, builder_path)
182+
init_from_example(&example, &contract_name, memory_model)
217183
}
218184
InitType::SolidityFile => {
219-
// Prompt for .sol file path
220-
let sol_file = Text::new("Enter path to your .sol file:")
221-
.with_help_message("Path to a Solidity interface file")
222-
.prompt()
223-
.context("Failed to get .sol file path")?;
185+
// Get sol_file from args or prompt
186+
let sol_path = match args.sol_file {
187+
Some(path) => path,
188+
None => {
189+
let sol_file = Text::new("Enter path to your .sol file:")
190+
.with_help_message("Path to a Solidity interface file")
191+
.prompt()
192+
.context("Failed to get .sol file path")?;
193+
194+
if sol_file.is_empty() {
195+
anyhow::bail!("Solidity file path cannot be empty");
196+
}
197+
PathBuf::from(sol_file)
198+
}
199+
};
224200

225-
if sol_file.is_empty() {
226-
anyhow::bail!("Solidity file path cannot be empty");
227-
}
228-
229-
// Verify file exists
230-
let sol_path = PathBuf::from(&sol_file);
231201
if !sol_path.exists() {
232-
anyhow::bail!("Solidity file not found: {sol_file}");
202+
anyhow::bail!("Solidity file not found: {}", sol_path.display());
233203
}
234204

235-
// Extract default name from .sol filename
236205
let default_name = sol_path
237206
.file_stem()
238207
.and_then(|s| s.to_str())
239208
.unwrap_or("contract")
240209
.to_string();
241210

242-
// Prompt for memory model
243-
let memory_models = vec![MemoryModel::AllocWithAlloy, MemoryModel::NoAlloc];
244-
let memory_model = Select::new("Which memory model do you want to use?", memory_models)
245-
.prompt()
246-
.context("Failed to get memory model choice")?;
247-
248-
// Ask for name with .sol filename as default
249-
let contract_name = Text::new("What is your contract name?")
250-
.with_default(&default_name)
251-
.with_help_message("This will be the name of the project directory")
252-
.prompt()
253-
.context("Failed to get contract name")?;
254-
255-
if contract_name.is_empty() {
256-
anyhow::bail!("Contract name cannot be empty");
257-
}
211+
let memory_model = prompt_memory_model(args.memory_model)?;
212+
let contract_name = prompt_name(args.name, Some(&default_name))?;
258213

259214
check_dir_exists(&contract_name)?;
260215
debug!(
261-
"Initializing from Solidity file: {sol_file} with memory model: {:?}",
216+
"Initializing from Solidity file: {} with memory model: {:?}",
217+
sol_path.display(),
262218
memory_model
263219
);
264220

221+
let sol_file = sol_path.to_str().ok_or_else(|| {
222+
anyhow::anyhow!("Solidity file path is not valid UTF-8: {:?}", sol_path)
223+
})?;
265224
let use_alloc = memory_model == MemoryModel::AllocWithAlloy;
266-
scaffold::init_from_solidity_file(&sol_file, &contract_name, use_alloc, builder_path)
225+
scaffold::init_from_solidity_file(sol_file, &contract_name, use_alloc)
267226
}
268227
}
269228
}
270229

271-
fn init_command_non_interactive(
272-
args: PvmContractArgs,
273-
builder_path: Option<&std::path::Path>,
274-
) -> Result<()> {
275-
let init_type = args
276-
.init_type
277-
.ok_or_else(|| anyhow::anyhow!("--init-type is required with --non-interactive"))?;
278-
279-
match init_type {
280-
InitType::Blank => {
281-
let contract_name = args
282-
.name
283-
.filter(|name| !name.is_empty())
284-
.ok_or_else(|| anyhow::anyhow!("--name is required for blank initialization"))?;
285-
286-
check_dir_exists(&contract_name)?;
287-
debug!("Initializing blank contract: {contract_name}");
288-
scaffold::init_blank_contract(&contract_name, builder_path)
230+
fn prompt_memory_model(arg: Option<MemoryModel>) -> Result<MemoryModel> {
231+
match arg {
232+
Some(m) => Ok(m),
233+
None => {
234+
let memory_models = vec![MemoryModel::AllocWithAlloy, MemoryModel::NoAlloc];
235+
Select::new("Which memory model do you want to use?", memory_models)
236+
.prompt()
237+
.context("Failed to get memory model choice")
289238
}
290-
InitType::Example => {
291-
let examples = load_examples()?;
292-
let example_name = args.example.ok_or_else(|| {
293-
anyhow::anyhow!("--example is required for example initialization")
294-
})?;
295-
let example = find_example(&examples, &example_name)?;
296-
let memory_model = args.memory_model.ok_or_else(|| {
297-
anyhow::anyhow!("--memory-model is required for example initialization")
298-
})?;
299-
let contract_name = args.name.unwrap_or_else(|| example.name.clone());
239+
}
240+
}
300241

301-
if contract_name.is_empty() {
302-
anyhow::bail!("Contract name cannot be empty");
242+
fn prompt_name(arg: Option<String>, default: Option<&str>) -> Result<String> {
243+
let contract_name = match arg {
244+
Some(name) => name,
245+
None => {
246+
let mut prompt = Text::new("What is your contract name?")
247+
.with_help_message("This will be the name of the project directory");
248+
if let Some(d) = default {
249+
prompt = prompt.with_default(d);
303250
}
304-
305-
check_dir_exists(&contract_name)?;
306-
debug!(
307-
"Initializing from example: {} with memory model: {:?}",
308-
example.filename, memory_model
309-
);
310-
311-
init_from_example(&example, &contract_name, memory_model, builder_path)
251+
prompt.prompt().context("Failed to get contract name")?
312252
}
313-
InitType::SolidityFile => {
314-
let sol_path = args.sol_file.ok_or_else(|| {
315-
anyhow::anyhow!("--sol-file is required for Solidity initialization")
316-
})?;
253+
};
317254

318-
if !sol_path.exists() {
319-
anyhow::bail!("Solidity file not found: {}", sol_path.display());
320-
}
321-
322-
let default_name = sol_path
323-
.file_stem()
324-
.and_then(|s| s.to_str())
325-
.unwrap_or("contract")
326-
.to_string();
327-
let contract_name = args.name.unwrap_or(default_name);
328-
329-
if contract_name.is_empty() {
330-
anyhow::bail!("Contract name cannot be empty");
331-
}
332-
333-
let memory_model = args.memory_model.ok_or_else(|| {
334-
anyhow::anyhow!("--memory-model is required for Solidity initialization")
335-
})?;
336-
337-
check_dir_exists(&contract_name)?;
338-
debug!(
339-
"Initializing from Solidity file: {} with memory model: {:?}",
340-
sol_path.display(),
341-
memory_model
342-
);
343-
344-
let sol_file = sol_path.to_str().ok_or_else(|| {
345-
anyhow::anyhow!("Solidity file path is not valid UTF-8: {:?}", sol_path)
346-
})?;
347-
let use_alloc = memory_model == MemoryModel::AllocWithAlloy;
348-
scaffold::init_from_solidity_file(sol_file, &contract_name, use_alloc, builder_path)
349-
}
255+
if contract_name.is_empty() {
256+
anyhow::bail!("Contract name cannot be empty");
350257
}
258+
259+
Ok(contract_name)
351260
}
352261

353262
fn init_from_example(
354263
example: &ExampleContract,
355264
contract_name: &str,
356265
memory_model: MemoryModel,
357-
builder_path: Option<&std::path::Path>,
358266
) -> Result<()> {
359267
// Get the embedded example .sol file
360268
let example_path = format!("examples/{}", example.filename);
@@ -383,7 +291,6 @@ fn init_from_example(
383291
temp_sol_path.to_str().unwrap(),
384292
contract_name,
385293
use_alloc,
386-
builder_path,
387294
);
388295

389296
// Clean up temp file

crates/cargo-pvm-contract/src/scaffold.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,7 @@ fn to_screaming_snake_case(s: &str) -> String {
230230
// Public API
231231
// ============================================================================
232232

233-
pub fn init_blank_contract(
234-
contract_name: &str,
235-
builder_path: Option<&std::path::Path>,
236-
) -> Result<()> {
233+
pub fn init_blank_contract(contract_name: &str) -> Result<()> {
237234
let target_dir = std::env::current_dir()?.join(contract_name);
238235
if target_dir.exists() {
239236
anyhow::bail!("Directory already exists: {target_dir:?}");
@@ -260,7 +257,7 @@ target = "riscv64imac-unknown-none-elf"
260257
let build_rs_content = generate_build_rs()?;
261258
fs::write(target_dir.join("build.rs"), build_rs_content)?;
262259

263-
let cargo_toml_content = generate_cargo_toml(contract_name, false, builder_path)?;
260+
let cargo_toml_content = generate_cargo_toml(contract_name, false)?;
264261
fs::write(target_dir.join("Cargo.toml"), cargo_toml_content)?;
265262

266263
println!("Successfully initialized blank contract project: {target_dir:?}");
@@ -274,7 +271,6 @@ pub fn init_from_solidity_file(
274271
sol_file: &str,
275272
contract_name: &str,
276273
use_alloc: bool,
277-
builder_path: Option<&std::path::Path>,
278274
) -> Result<()> {
279275
let sol_path = PathBuf::from(sol_file);
280276
if !sol_path.exists() {
@@ -334,7 +330,7 @@ target = "riscv64imac-unknown-none-elf"
334330
fs::write(target_dir.join("build.rs"), build_rs_content)?;
335331

336332
// Create Cargo.toml
337-
let cargo_toml_content = generate_cargo_toml(contract_name, use_alloc, builder_path)?;
333+
let cargo_toml_content = generate_cargo_toml(contract_name, use_alloc)?;
338334
fs::write(target_dir.join("Cargo.toml"), cargo_toml_content)?;
339335

340336
println!("Successfully initialized contract project from {sol_file}: {target_dir:?}");
@@ -591,16 +587,23 @@ fn generate_rust_code_no_alloc(metadata: &ContractMetadata, contract_name: &str)
591587
.context("Failed to render no-alloc template")
592588
}
593589

594-
fn generate_cargo_toml(
595-
contract_name: &str,
596-
use_alloc: bool,
597-
builder_path: Option<&std::path::Path>,
598-
) -> Result<String> {
590+
fn generate_cargo_toml(contract_name: &str, use_alloc: bool) -> Result<String> {
591+
let builder_path = std::env::var("CARGO_PVM_CONTRACT_BUILDER_PATH")
592+
.ok()
593+
.filter(|value| !value.trim().is_empty());
594+
595+
if let Some(ref path) = builder_path {
596+
let path = std::path::Path::new(path);
597+
if !path.exists() {
598+
anyhow::bail!("Builder path does not exist: {}", path.display());
599+
}
600+
}
601+
599602
let template = CargoTomlTemplate {
600603
contract_name,
601604
use_alloc,
602605
builder_version: BUILDER_VERSION,
603-
builder_path: builder_path.map(|path| path.display().to_string()),
606+
builder_path,
604607
};
605608
template
606609
.render()

0 commit comments

Comments
 (0)