pw_presubmit: Move Bazel symlinks from the root

Create the bazel-* symlinks the in presubmit directory rather than the
repo root to avoid polluting the working directory.

Change-Id: Id47f30fe52a104b0231c2cdadac959f12c34101b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/72820
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Rob Mohr <mohrr@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_presubmit/py/pw_presubmit/build.py b/pw_presubmit/py/pw_presubmit/build.py
index 03e19ed..fe8435b 100644
--- a/pw_presubmit/py/pw_presubmit/build.py
+++ b/pw_presubmit/py/pw_presubmit/build.py
@@ -42,6 +42,24 @@
 _LOG = logging.getLogger(__name__)
 
 
+def bazel(ctx: PresubmitContext, cmd: str, *args: str) -> None:
+    """Invokes Bazel with some common flags set.
+
+    Intended for use with bazel build and test. May not work with others.
+    """
+    call(
+        'bazel',
+        cmd,
+        '--verbose_failures',
+        '--verbose_explanations',
+        '--worker_verbose',
+        f'--symlink_prefix={ctx.output_dir / "bazel-"}',
+        '--experimental_no_product_name_out_symlink',  # No top-level bazel-out
+        *args,
+        cwd=ctx.root,
+        env=env_with_clang_vars())
+
+
 def install_package(root: Path, name: str) -> None:
     """Install package with given name in given path."""
     mgr = package_manager.PackageManager(root)
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index d0ada62..348af9c 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -376,43 +376,17 @@
 
 @filter_paths(endswith=(*format_code.C_FORMAT.extensions, '.bazel', '.bzl',
                         'BUILD'))
-def bazel_test(ctx: PresubmitContext):
+def bazel_test(ctx: PresubmitContext) -> None:
     """Runs bazel test on each bazel compatible module"""
-    try:
-        call('bazel',
-             'test',
-             *_MODULES_THAT_TEST_WITH_BAZEL,
-             '--verbose_failures',
-             '--verbose_explanations',
-             '--worker_verbose',
-             '--test_output=errors',
-             cwd=ctx.root,
-             env=build.env_with_clang_vars())
-    except:
-        _LOG.info('If the Bazel build inexplicably fails while the '
-                  'other builds are passing, try deleting the Bazel cache:\n'
-                  '    rm -rf ~/.cache/bazel')
-        raise
+    build.bazel(ctx, 'test', *_MODULES_THAT_TEST_WITH_BAZEL,
+                '--test_output=errors')
 
 
 @filter_paths(endswith=(*format_code.C_FORMAT.extensions, '.bazel', '.bzl',
                         'BUILD'))
-def bazel_build(ctx: PresubmitContext):
-    """Runs Bazel build on each Bazel compatible module"""
-    try:
-        call('bazel',
-             'build',
-             *_MODULES_THAT_BUILD_WITH_BAZEL,
-             '--verbose_failures',
-             '--verbose_explanations',
-             '--worker_verbose',
-             cwd=ctx.root,
-             env=build.env_with_clang_vars())
-    except:
-        _LOG.info('If the Bazel build inexplicably fails while the '
-                  'other builds are passing, try deleting the Bazel cache:\n'
-                  '    rm -rf ~/.cache/bazel')
-        raise
+def bazel_build(ctx: PresubmitContext) -> None:
+    """Runs Bazel build on each Bazel compatible module."""
+    build.bazel(ctx, 'build', *_MODULES_THAT_BUILD_WITH_BAZEL)
 
 
 #