keith / rules_multirun

Bazel rules for running multiple commands in parallel in a single bazel invocation
Apache License 2.0
65 stars 13 forks source link

multirun.py cannot launch command: FileNotFoundError #19

Closed Place1 closed 1 year ago

Place1 commented 1 year ago

Hello, i'm trying to use multirun for a similar use-case discussed here: https://github.com/bazel-contrib/rules_oci/issues/248#issuecomment-1558154145

I've got the following rules:

oci_push(
    name = "push",
    # ...
)

command(
    name = "push_command",
    command = ":push",
    arguments = [],
)

multirun(
    name = "push_multi",
    commands = [":push_command"],
)

I've found that running bazel run :push or bazel run :push_command works as expected but i'm having trouble with bazel run :push_multi

$ bazel run //:push_multi
INFO: Analyzed target //:push_multi (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:push_multi up-to-date:
  bazel-bin/push_multi.bash
INFO: Elapsed time: 0.044s, Critical Path: 0.01s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/push_multi.bash
Running @//:push_command
Traceback (most recent call last):
  File "/home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_multi.bash.runfiles/rules_multirun/internal/multirun.py", line 67, in <module>
    _main(sys.argv[-1])
  File "/home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_multi.bash.runfiles/rules_multirun/internal/multirun.py", line 61, in _main
    success = _perform_serially(commands, instructions["print_command"])
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_multi.bash.runfiles/rules_multirun/internal/multirun.py", line 42, in _perform_serially
    _run_command(command, block=True)
  File "/home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_multi.bash.runfiles/rules_multirun/internal/multirun.py", line 20, in _run_command
    return subprocess.check_call(args, env=env)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 408, in check_call
    retcode = call(*popenargs, **kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 389, in call
    with Popen(*popenargs, **kwargs) as p:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 1024, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.11/subprocess.py", line 1917, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'push_command.bash'

I've attempted to debug by adding a print(os.getcwd()) to the multirun.py script to check if the push_command.bash script exists and it does.

╭─me@martin ~/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_images.bash.runfiles/project
╰─$ ls -lah
total 32K
drwxr-xr-x 3 me 4.0K Jun 21 09:39 ./
drwxrwxrwx 7 me 4.0K Jun 21 09:39 ../
lrwxrwxrwx 1 me  135 Jun 21 09:39 push_command.bash -> /home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_command.bash*
lrwxrwxrwx 1 me  134 Jun 20 15:54 push_images.bash -> /home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_images.bash*
lrwxrwxrwx 1 me  134 Jun 20 15:54 push_images.json -> /home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_images.json*
lrwxrwxrwx 1 me  130 Jun 21 09:39 push_push.sh -> /home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/push_push.sh*
lrwxrwxrwx 1 me  132 Jun 21 09:39 _push.tags.txt -> /home/me/.cache/bazel/_bazel_me/xxxxxxxxxxxxxxxxxxxxx/execroot/project/bazel-out/k8-fastbuild/bin/_push.tags.txt*

If I edit the multirun.py script so that it executes ./push_command.bash instead then it works. The ./ prefix may be needed?

keith commented 1 year ago

Interesting, we hadn't hit this case because we don't have any multiruns in the root BUILD file in our project, so our paths end up being tools/whatever/foo.bash which solves this. I think doing either ./ or computing the absolute path with os.path.abspath(command.path) would solve this. I'm not sure which is better, I guess doing ./, want to submit that as a PR?

Place1 commented 1 year ago

Thanks for replying @keith i've put up a PR. This change allows my workspace to use the multirun as expected.

Surprisingly the tests still pass with this change. I'm not sure how to add a test for this. Perhaps you can help me with that?

keith commented 1 year ago

Sorry I didn't see that until I had merged your PR. Submitted this: https://github.com/keith/rules_multirun/pull/21