Skip to content

Commit aa331b4

Browse files
committed
gnd: Prompt for new directory on collision instead of exiting with error
When the target directory already exists during `gnd init`, instead of failing with an error, the user is now prompted to enter an alternative directory name. This applies to all init modes: --from-contract, --from-example, and --from-subgraph. The new `resolve_directory_collision()` function in prompt.rs handles the prompting loop, continuing until a non-existent directory is chosen.
1 parent e7b095b commit aa331b4

2 files changed

Lines changed: 56 additions & 25 deletions

File tree

gnd/src/commands/init.rs

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::output::{step, with_spinner, Step};
2323
use crate::prompt::{
2424
get_subgraph_basename, prompt_add_another_contract, prompt_contract_address,
2525
prompt_contract_name, prompt_directory_with_confirm, prompt_start_block,
26-
prompt_subgraph_slug_with_confirm, InitForm, SourceType,
26+
prompt_subgraph_slug_with_confirm, resolve_directory_collision, InitForm, SourceType,
2727
};
2828
use crate::scaffold::{generate_scaffold, init_git, install_dependencies, ScaffoldOptions};
2929
use crate::services::{ContractInfo, ContractService, IpfsClient, NetworksRegistry};
@@ -325,7 +325,7 @@ async fn init_from_contract(opt: &InitOpt) -> Result<()> {
325325
.unwrap_or_else(|| format!("user/{}", contract_name.to_lowercase()));
326326

327327
// Determine directory
328-
let directory = opt.directory.clone().unwrap_or_else(|| {
328+
let initial_directory = opt.directory.clone().unwrap_or_else(|| {
329329
PathBuf::from(
330330
subgraph_name
331331
.split('/')
@@ -334,13 +334,8 @@ async fn init_from_contract(opt: &InitOpt) -> Result<()> {
334334
)
335335
});
336336

337-
// Check if directory already exists
338-
if directory.exists() {
339-
return Err(anyhow!(
340-
"Directory '{}' already exists. Please choose a different name or remove the existing directory.",
341-
directory.display()
342-
));
343-
}
337+
// Resolve directory collision by prompting for a new name if needed
338+
let directory = PathBuf::from(resolve_directory_collision(&initial_directory)?);
344339

345340
// Determine start block
346341
let start_block = opt
@@ -524,7 +519,7 @@ fn init_from_example(opt: &InitOpt) -> Result<()> {
524519
};
525520

526521
// Determine directory - prompt if not provided and in terminal
527-
let directory = if let Some(dir) = &opt.directory {
522+
let initial_directory = if let Some(dir) = &opt.directory {
528523
dir.clone()
529524
} else if io::stdin().is_terminal() {
530525
let default_dir = get_subgraph_basename(&subgraph_name);
@@ -533,13 +528,8 @@ fn init_from_example(opt: &InitOpt) -> Result<()> {
533528
PathBuf::from(get_subgraph_basename(&subgraph_name))
534529
};
535530

536-
// Check if directory already exists
537-
if directory.exists() {
538-
return Err(anyhow!(
539-
"Directory '{}' already exists. Please choose a different name or remove the existing directory.",
540-
directory.display()
541-
));
542-
}
531+
// Resolve directory collision by prompting for a new name if needed
532+
let directory = PathBuf::from(resolve_directory_collision(&initial_directory)?);
543533

544534
// Clone example with spinner
545535
clone_example_with_spinner(example, &directory)?;
@@ -948,17 +938,12 @@ async fn init_from_subgraph(opt: &InitOpt) -> Result<()> {
948938
.unwrap_or_else(|| "composed-subgraph".to_string());
949939

950940
// Determine directory
951-
let directory = opt.directory.clone().unwrap_or_else(|| {
941+
let initial_directory = opt.directory.clone().unwrap_or_else(|| {
952942
PathBuf::from(subgraph_name.split('/').next_back().unwrap_or("subgraph"))
953943
});
954944

955-
// Check if directory already exists
956-
if directory.exists() {
957-
return Err(anyhow!(
958-
"Directory '{}' already exists. Please choose a different name or remove the existing directory.",
959-
directory.display()
960-
));
961-
}
945+
// Resolve directory collision by prompting for a new name if needed
946+
let directory = PathBuf::from(resolve_directory_collision(&initial_directory)?);
962947

963948
// Generate scaffold with immutable entities
964949
let scaffold_options = ScaffoldOptions {

gnd/src/prompt.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! This module provides wrappers around the `inquire` crate to provide
44
//! consistent prompting behavior similar to the TypeScript graph-cli.
55
6+
use std::path::Path;
7+
68
use anyhow::Result;
79
use console::{style, Term};
810
use inquire::validator::Validation;
@@ -321,6 +323,50 @@ pub fn prompt_directory_with_confirm(default: Option<&str>) -> Result<String> {
321323
Ok(dir)
322324
}
323325

326+
/// Resolve directory collision by prompting for a new directory name.
327+
///
328+
/// If the given directory already exists, asks the user for an alternative
329+
/// directory name instead of failing with an error. Continues prompting
330+
/// until a non-existent directory is chosen.
331+
///
332+
/// Returns the resolved directory path as a String.
333+
pub fn resolve_directory_collision(initial_dir: &Path) -> Result<String> {
334+
if !initial_dir.exists() {
335+
return Ok(initial_dir.to_str().unwrap_or("subgraph").to_string());
336+
}
337+
338+
// Directory exists, warn and prompt for a new name
339+
eprintln!(
340+
"{} Directory '{}' already exists",
341+
style("!").yellow(),
342+
initial_dir.display()
343+
);
344+
345+
loop {
346+
let dir = Text::new("Enter a different directory name:")
347+
.with_help_message("Choose a directory that doesn't exist")
348+
.with_validator(|input: &str| {
349+
if input.trim().is_empty() {
350+
Ok(Validation::Invalid("Directory cannot be empty".into()))
351+
} else {
352+
Ok(Validation::Valid)
353+
}
354+
})
355+
.prompt()?;
356+
357+
let path = Path::new(&dir);
358+
if path.exists() {
359+
eprintln!(
360+
"{} Directory '{}' also exists, please try another name",
361+
style("!").yellow(),
362+
dir
363+
);
364+
} else {
365+
return Ok(dir);
366+
}
367+
}
368+
}
369+
324370
/// Format a subgraph name to be valid.
325371
fn format_subgraph_name(name: &str) -> String {
326372
name.trim()

0 commit comments

Comments
 (0)