(Rust) "Build your own shell" - Stage Run a program #IP1 always fails despite working before

I’m stuck on Stage #(IP1).

The test used to pass but now always fails I even tried to checkout to the same commit that used to pass and it still fails!!

Here are my logs:

[tester::#IP1] Running tests for Stage #IP1 (Run a program)
[tester::#IP1] Running ./your_shell.sh
[your-program] $ my_exe Emily
[tester::#IP1] Output does not match expected value.
[tester::#IP1] Expected: "Hello Emily! The secret code is 5834763366."
[tester::#IP1] Received: "my_exe: not found"
[your-program] my_exe: not found
[your-program] $
[tester::#IP1] Assertion failed.
[tester::#IP1] Test failed

And here’s a snippet of my code:

fn main() {
    // Wait for user input
    let mut ctx = Context {
        executables: HashMap::new(),
        current_working_dir: env::current_dir().expect("Shouldn't fail?"),
    };

    let paths = PATH.split(':').collect::<Vec<&str>>();
    let _ = populate_executables(&paths, &mut ctx);
    let stdin = io::stdin();
    loop {
        print!("$ ");
        io::stdout().flush().unwrap();
        let mut command = String::new();
        let _ = stdin.read_line(&mut command).unwrap();
        if let Err(e) = eval(&command, &mut ctx) {
            eprintln!("{:?}", e);
        }
    }
}

fn populate_executables(paths: &[&str], ctx: &mut Context) -> Result<()> {
    for path in paths {
        if let Ok(entries) = fs::read_dir(path) {
            for entry in entries.filter_map(Result::ok) {
                let path = entry.path();
                if let Some(file_name) = entry.file_name().to_str() {
                    let _ = ctx.executables.insert(file_name.to_string(), path);
                }
            }
        }
    }
    Ok(())
}

fn eval_executable(command: &str, args: &[&str], ctx: &Context) -> Result<()> {
    if ctx.executables.contains_key(command) {
        let full_path_cmd = ctx.executables[command].to_str().unwrap();
        let mut cmd = Command::new(full_path_cmd);
        let output = cmd.args(args).output().unwrap();
        // Check if the command was successful
        if output.status.success() {
            // Convert the output to a string and print it
            let stdout = String::from_utf8(output.stdout)?;
            print!("{}", stdout);
            Ok(())
        } else {
            // If the command failed, print the error
            let stderr = String::from_utf8(output.stderr)?;
            eprintln!("Error:\n{}", stderr);
            Ok(())
        }
    } else {
        println!("{}: command not found", command);
        Ok(())
    }
}

Hi @omagdy7, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

Yes here it is: GitHub - omagdy7/tiny-shell

Thanks for sharing your code! I’ll take a look and get back to you by the end of the week.

OK I found the problem I was populating the executable apparently before the command is created by the tester so when it gets tested it isn’t found, The current hack is to repopulate the the executable every time before invoking every command though it’s pretty inefficient but works for now I guess. I just found it weird that tests change on the platform apparently because this worked find 1 week ago

2 Likes

Thank you so much! I wasted way to much time on this xD I looked through all paths on startup and my_exe did not exist. Now I do it when the first command is run and the tests pass… :sweat_smile:

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.