Dual-command pipeline #BR6 Rust

I’m stuck on Stage #BR6.

Here are my logs:

❯ codecrafters test
Initiating test run...

⚡ This is a turbo test run. https://codecrafters.io/turbo

Running tests on your code. Logs should appear shortly...

[compile]    Compiling codecrafters-shell v0.1.0 (/app)
[compile]     Finished `release` profile [optimized] target(s) in 2.03s
[compile] Moved ./.codecrafters/run.sh → ./your_program.sh
[compile] Compilation successful.

Debug = true

[tester::#BR6] Running tests for Stage #BR6 (Pipelines - Dual-command pipeline)
[tester::#BR6] [setup] export PATH=/tmp/apple/raspberry/orange:$PATH
[tester::#BR6] Running ./your_program.sh
[tester::#BR6] [setup] echo "blueberry grape\napple mango\npineapple raspberry\npear banana\norange strawberry" > "/tmp/qux/file-67"
[your-program] $ cat /tmp/qux/file-67 | wc
[your-program]        5      10      78
[tester::#BR6] ✓ Received expected response
[tester::#BR6] [setup] echo "1. orange strawberry\n2. grape apple\n3. pear blueberry" > "/tmp/foo/file-53"
[your-program] $ tail -f /tmp/foo/file-53 | head -n 5
[tester::#BR6] Didn't find expected line.
[tester::#BR6] Expected: "1. orange strawberry"
[tester::#BR6] Received: "" (no line received)
[tester::#BR6] Assertion failed.
[tester::#BR6] Test failed

View our article on debugging test failures: https://codecrafters.io/debug

And here’s a snippet of my code:

        _ => {
            if pipeline_length == 1 {
                // there is only one command in the pipeline
                run_executable(
                    &command,
                    arguments,
                    Stdio::null(),
                    parsed_command.stdout,
                    parsed_command.stderr,
                    None,
                )
                .expect("TODO: panic message");
            } else if index == 0 {
                // first command in the pipeline
                let mut child = Command::new(&command)
                    .args(arguments.map(|(_, argument)| argument))
                    .stdin(Stdio::null())
                    .stdout(Stdio::piped())
                    .spawn()?;
                previous_output = child.stdout.take();
                previous_child = Some(child);
            } else if index < pipeline_length - 1 {
                // middle command in the pipeline
                let mut child = Command::new(&command)
                    .args(arguments.map(|(_, argument)| argument))
                    .stdin(Stdio::from(previous_output.take().unwrap()))
                    .stdout(Stdio::piped())
                    .spawn()?;
                previous_child.take().unwrap().wait()?;
                previous_output = child.stdout.take();
                previous_child = Some(child);
            } else {
                // last command in the pipeline
                run_executable(
                    &command,
                    arguments,
                    Stdio::from(previous_output.take().unwrap()),
                    parsed_command.stdout,
                    parsed_command.stderr,
                    previous_child.take(),
                )
                .expect("TODO: panic message");
            }
        }

See full code at: codecrafters-shell-rust/src/main.rs at 19502199cf7255da52f6ca6380f28ffe93af7e7e · feamcor/codecrafters-shell-rust · GitHub

I tried to test from command line and was able to succeed by appending extra lines in the tailed file from another terminal window, but the automated test doesn’t work.

Also, it is not clear if automated testing is expecting \n and \t inside a double-quoted string to be escaped, or not.

I implemented the escaping but it ends up failing previous tests. See code at codecrafters-shell-rust/src/main.rs at 19502199cf7255da52f6ca6380f28ffe93af7e7e · feamcor/codecrafters-shell-rust · GitHub

The reason I ask is because commands like the one below won’t append multiple lines to the file, but just one with literal \n.

echo "1. orange strawberry\n2. grape apple\n3. pear blueberry" > "/tmp/foo/file-53"

BTW, echo is built-in, so I checked the shell behavior versus bash behavior and I get the same (i.e., just one line).

❯ echo "1. orange strawberry\n2. grape apple\n3. pear blueberry" > "test"

❯ cat test
1. orange strawberry\n2. grape apple\n3. pear blueberry

❯ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/codecrafters-shell`
$ echo "1. orange strawberry\n2. grape apple\n3. pear blueberry" > "test2"
$ cat test2
1. orange strawberry\n2. grape apple\n3. pear blueberry
$ exit

❯ cat test2
1. orange strawberry\n2. grape apple\n3. pear blueberry

Please advise.
Thanks.

I updated the code to handle \n and \t when between double quotes for an echo command.
Anyway, problem with #BR6 persists.

Hey @feamcor, thanks for the detailed report and all the context. Super helpful!

The test files are meant to contain actual newlines, not the literal string "\n".

We should’ve shown the echo commands with the -e flag, like this:

echo -e "1. orange strawberry\n2. grape apple\n3. pear blueberry" > "/tmp/foo/file-53"

We’re addressing the display issue in this PR to make the behavior clearer.

BTW you don’t need to specifically handle \n or \t inside double quotes for echo commands, since these echo commands are there to show how the files are set up by the tester itself.

Hi @andy1li, echo is built-in and I don’t remember the implementation of -e or any other feature flag on previous tasks. I will change my code to implement it, but maybe the task to implement echo should be extended also. Thanks.

Please let me know in case you have any clue of why the test doesn’t succeed.
I’ll keep trying, but I’m stuck there for a couple of days already.
Thanks.

@feamcor Looks like tail -f isn’t being executable properly.

The output only appears after I press Ctrl+C:

Whereas in a real shell, it shows up immediately:

Let me know if you’d like me to dig into this further.

Hi @andy1li , don’t worry, I will figure out what I’m doing wrong when using Command for a command like tail -f. Thanks.

1 Like

Finally the issue is fixed :partying_face:

You can see the changes at codecrafters submit [skip ci] · feamcor/codecrafters-shell-rust@548fd62 · GitHub

Issue was between the use of .spawn() or .output() when a command is inheriting the stdout and stderr. I had to branch the command execution if stdout or stderr are being redirected to a file or inherited from parent process.

1 Like

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