Skip to content

feat: support --noenable_runfiles on linux and windows, new runfiles bat macro, fix tests for windows #872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import %workspace%/.aspect/bazelrc/performance.bazelrc

### YOUR PROJECT SPECIFIC OPTIONS GO HERE ###

# symlinks on windows are required by some tests
startup --windows_enable_symlinks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does require elevated privileges in some environments. Is it possible to not to depend on this? Or mark tests that depend on symlinks to be possible to exclude when maintaining a fork. Thank you!


# For testing our --stamp behavior.
# Normally users would use a --workspace_status_command with a script that calls `git describe`.
common --embed_label=v1.2.3
Expand Down
4 changes: 4 additions & 0 deletions configure.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:: run this on Windows to set up example for use
@echo Configuring workspace for Windows
:: aspect-cli doesn't support windows, so disable it
del %~dp0.bazeliskrc
13 changes: 13 additions & 0 deletions lib/paths.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,16 @@ source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
{ echo>&2 "ERROR: runfiles.bash initializer cannot find $f. An executable rule may have forgotten to expose it in the runfiles, or the binary may require RUNFILES_DIR to be set."; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---
"""

# Convenient helper for macros that generate bash scripts
# Usage example:
# write_file(
# name = "_" + name,
# out = test_sh,
# content = BASH_RLOCATION_PREFIX + [
# "set -o errexit",
# "file=$(rlocation $1)",
# "grep foo $file",
# ],
# )
BASH_RLOCATION_PREFIX = ["#!/usr/bin/env bash"] + BASH_RLOCATION_FUNCTION.split("\n")
18 changes: 13 additions & 5 deletions lib/private/diff_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ command (fc.exe) on Windows (no Bash is required).

load("//lib:utils.bzl", "default_timeout")
load(":directory_path.bzl", "DirectoryPathInfo")
load("//lib:windows_utils.bzl", "BATCH_RLOCATION_FUNCTION")
load("//lib:paths.bzl", "BASH_RLOCATION_FUNCTION", "to_rlocation_path")

def _runfiles_path(f):
if f.root.path:
Expand All @@ -35,21 +37,21 @@ def _diff_test_impl(ctx):

if DirectoryPathInfo in ctx.attr.file1:
file1 = ctx.attr.file1[DirectoryPathInfo].directory
file1_path = "/".join([_runfiles_path(file1), ctx.attr.file1[DirectoryPathInfo].path])
file1_path = "/".join([to_rlocation_path(ctx, file1), ctx.attr.file1[DirectoryPathInfo].path])
else:
if len(ctx.files.file1) != 1:
fail("file1 must be a single file or a target that provides a DirectoryPathInfo")
file1 = ctx.files.file1[0]
file1_path = _runfiles_path(file1)
file1_path = to_rlocation_path(ctx, file1)

if DirectoryPathInfo in ctx.attr.file2:
file2 = ctx.attr.file2[DirectoryPathInfo].directory
file2_path = "/".join([_runfiles_path(file2), ctx.attr.file2[DirectoryPathInfo].path])
file2_path = "/".join([to_rlocation_path(ctx, file2), ctx.attr.file2[DirectoryPathInfo].path])
else:
if len(ctx.files.file2) != 1:
fail("file2 must be a single file or a target that provides a DirectoryPathInfo")
file2 = ctx.files.file2[0]
file2_path = _runfiles_path(file2)
file2_path = to_rlocation_path(ctx, file2)

if file1 == file2:
msg = "diff_test comparing the same file %s" % file1
Expand All @@ -58,9 +60,11 @@ def _diff_test_impl(ctx):
if is_windows:
test_suffix = "-test.bat"
template = ctx.file._diff_test_tmpl_bat
rlocation_function = BATCH_RLOCATION_FUNCTION
else:
test_suffix = "-test.sh"
template = ctx.file._diff_test_tmpl_sh
rlocation_function = BASH_RLOCATION_FUNCTION

test_bin = ctx.actions.declare_file(ctx.label.name + test_suffix)
ctx.actions.expand_template(
Expand All @@ -71,6 +75,7 @@ def _diff_test_impl(ctx):
"{fail_msg}": ctx.attr.failure_message,
"{file1}": file1_path,
"{file2}": file2_path,
"{rlocation_function}": rlocation_function,
"{build_file_path}": ctx.build_file_path,
},
is_executable = True,
Expand All @@ -79,7 +84,7 @@ def _diff_test_impl(ctx):
return DefaultInfo(
executable = test_bin,
files = depset(direct = [test_bin]),
runfiles = ctx.runfiles(files = [test_bin, file1, file2]),
runfiles = ctx.runfiles(files = [test_bin, file1, file2] + ctx.files._bash_runfiles),
)

_diff_test = rule(
Expand All @@ -102,6 +107,9 @@ _diff_test = rule(
default = ":diff_test_tmpl.bat",
allow_single_file = True,
),
"_bash_runfiles": attr.label(
default = Label("@bazel_tools//tools/bash/runfiles"),
),
},
test = True,
implementation = _diff_test_impl,
Expand Down
46 changes: 5 additions & 41 deletions lib/private/diff_test_tmpl.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,12 @@
:: TODO: Add support for XML_OUTPUT_FILE like in diff_test_tmpl.sh
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
set MF=%RUNFILES_MANIFEST_FILE:/=\\%
set PATH=%SYSTEMROOT%\\system32
set F1={file1}
set F2={file2}
if "!F1:~0,9!" equ "external/" (set F1=!F1:~9!) else (set F1=!TEST_WORKSPACE!/!F1!)
if "!F2:~0,9!" equ "external/" (set F2=!F2:~9!) else (set F2=!TEST_WORKSPACE!/!F2!)
for /F "tokens=2* usebackq" %%i in (`findstr.exe /l /c:"!F1! " "%MF%"`) do (
set RF1=%%i
set RF1=!RF1:/=\\!
)
if "!RF1!" equ "" (
if "%RUNFILES_MANIFEST_ONLY%" neq "1" if exist "%RUNFILES_DIR%\\%F1%" (
set RF1="%RUNFILES_DIR%\\%F1%"
) else (
if exist "{file1}" (
set RF1="{file1}"
)
)
if "!RF1!" neq "" ( set RF1=!RF1:/=\\!
) else (
echo>&2 ERROR: !F1! not found
exit /b 1
)
)
for /F "tokens=2* usebackq" %%i in (`findstr.exe /l /c:"!F2! " "%MF%"`) do (
set RF2=%%i
set RF2=!RF2:/=\\!
)
if "!RF2!" equ "" (
if "%RUNFILES_MANIFEST_ONLY%" neq "1" if exist "%RUNFILES_DIR%\\%F2%" (
set RF2="%RUNFILES_DIR%\\%F2%"
) else (
if exist "{file2}" (
set RF2="{file2}"
)
)
if "!RF2!" neq "" ( set RF2=!RF2:/=\\!
) else (
echo>&2 ERROR: !F2! not found
exit /b 1
)
)

{rlocation_function}

call :rlocation {file1} F1
call :rlocation {file2} F2
set DF1=0
set DF2=0
if exist "!RF1!\\*" (
Expand Down
41 changes: 3 additions & 38 deletions lib/private/diff_test_tmpl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,46 +19,11 @@ EOF
echo >&2 "FAIL: $1"
exit 1
}
resolve_exec_root() {
local RUNFILES_PARENT
RUNFILES_PARENT=$(dirname "$RUNFILES_DIR")
local BIN_DIR
BIN_DIR="${RUNFILES_PARENT%$BUILD_FILE_DIR}"
local EXEC_ROOT
EXEC_ROOT=$(dirname $(dirname $(dirname "${BIN_DIR}")))

echo -n "$EXEC_ROOT"
}
find_file() {
local F_RAW="$1"
local F="$2"
local RF=

if [[ -f "$TEST_SRCDIR/$F1" || -d "$TEST_SRCDIR/$F" ]]; then
RF="$TEST_SRCDIR/$F"
elif [[ -d "${RUNFILES_DIR:-/dev/null}" && "${RUNFILES_MANIFEST_ONLY:-}" != 1 ]]; then
EXEC_ROOT=$(resolve_exec_root)
if [[ -e "$EXEC_ROOT/$F_RAW" ]]; then
RF="$EXEC_ROOT/$F_RAW"
else
RF="$RUNFILES_DIR/$F1"
fi
elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
RF="$(grep -F -m1 "$F " "$RUNFILES_MANIFEST_FILE" | sed 's/^[^ ]* //')"
else
echo >&2 "ERROR: could not find \"${F_RAW}\""
exit 1
fi
{rlocation_function}

echo -n "$RF"
}
BUILD_FILE_DIR="$(dirname "{build_file_path}")"
F1="{file1}"
F2="{file2}"
[[ "$F1" =~ ^external/ ]] && F1="${F1#external/}" || F1="$TEST_WORKSPACE/$F1"
[[ "$F2" =~ ^external/ ]] && F2="${F2#external/}" || F2="$TEST_WORKSPACE/$F2"
RF1="$(find_file {file1} "$F1")"
RF2="$(find_file {file2} "$F2")"
RF1="$(rlocation {file1})"
RF2="$(rlocation {file2})"
DF1=
DF2=
[[ ! -d "$RF1" ]] || DF1=1
Expand Down
35 changes: 21 additions & 14 deletions lib/private/write_source_file.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ load(":diff_test.bzl", _diff_test = "diff_test")
load(":directory_path.bzl", "DirectoryPathInfo")
load(":fail_with_message_test.bzl", "fail_with_message_test")
load(":utils.bzl", "utils")
load("//lib:windows_utils.bzl", "BATCH_RLOCATION_FUNCTION")
load("//lib:paths.bzl", "BASH_RLOCATION_PREFIX", "to_rlocation_path")

WriteSourceFileInfo = provider(
"Provider for write_source_file targets",
Expand Down Expand Up @@ -191,9 +193,8 @@ def _write_source_file_sh(ctx, paths):
for target in ctx.attr.additional_update_targets:
additional_update_scripts.append(target[WriteSourceFileInfo].executable)

contents = ["""#!/usr/bin/env bash
contents = BASH_RLOCATION_PREFIX + ["""
set -o errexit -o nounset -o pipefail
runfiles_dir=$PWD
# BUILD_WORKSPACE_DIRECTORY not set when running as a test, uses the sandbox instead
if [[ ! -z "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
cd "$BUILD_WORKSPACE_DIRECTORY"
Expand All @@ -213,7 +214,7 @@ fi"""]

for in_path, out_path in paths:
contents.append("""
in=$runfiles_dir/{in_path}
in=$(rlocation {in_path})
out={out_path}

mkdir -p "$(dirname "$out")"
Expand Down Expand Up @@ -245,11 +246,10 @@ fi
))

contents.extend([
"cd \"$runfiles_dir\"",
"# Run the update scripts for all write_source_file deps",
])
for update_script in additional_update_scripts:
contents.append("./\"{update_script}\"".format(update_script = update_script.short_path))
contents.append("./$(rlocation {update_script})".format(update_script = to_rlocation_path(ctx, update_script)))

ctx.actions.write(
output = updater,
Expand All @@ -273,40 +273,47 @@ def _write_source_file_bat(ctx, paths):

contents = ["""@rem @generated by @aspect_bazel_lib//:lib/private:write_source_file.bzl
@echo off
set runfiles_dir=%cd%
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
set RUNFILES_MANIFEST_ONLY=1
if defined BUILD_WORKSPACE_DIRECTORY (
cd %BUILD_WORKSPACE_DIRECTORY%
)"""]

for in_path, out_path in paths:
contents.append("""
set in=%runfiles_dir%\\{in_path}
call :rlocation {in_path} in
set in=%in:/=\\%
set out={out_path}

if not defined BUILD_WORKSPACE_DIRECTORY (
@rem Because there's no sandboxing in windows, if we copy over the target
@rem file's symlink it will get copied back into the source directory
@rem during tests. Work around this in tests by deleting the target file
@rem symlink before copying over it.
del %out%
if exist %out% del %out%
)

echo Copying %in% to %out% in %cd%

if exist "%in%\\*" (
mkdir "%out%" >NUL 2>NUL
robocopy "%in%" "%out%" /E >NUL
) else (
copy %in% %out% >NUL
)
""".format(in_path = in_path.replace("/", "\\"), out_path = out_path.replace("/", "\\")))
""".format(in_path = in_path, out_path = out_path.replace("/", "\\")))

contents.extend([
"cd %runfiles_dir%",
"@rem Run the update scripts for all write_source_file deps",
])
for update_script in additional_update_scripts:
contents.append("call {update_script}".format(update_script = update_script.short_path))
contents.extend([
"set update_script=",
"call :rlocation {update_script} update_script".format(update_script = to_rlocation_path(ctx, update_script)),
"call %update_script%",
])

contents.append(BATCH_RLOCATION_FUNCTION)

ctx.actions.write(
output = updater,
Expand All @@ -331,15 +338,15 @@ def _write_source_file_impl(ctx):
if ctx.attr.in_file and out_file:
if DirectoryPathInfo in ctx.attr.in_file:
in_path = "/".join([
ctx.attr.in_file[DirectoryPathInfo].directory.short_path,
to_rlocation_path(ctx, ctx.attr.in_file[DirectoryPathInfo].directory),
ctx.attr.in_file[DirectoryPathInfo].path,
])
runfiles.append(ctx.attr.in_file[DirectoryPathInfo].directory)
elif len(ctx.files.in_file) == 0:
msg = "in file {} must provide files".format(ctx.attr.in_file.label)
fail(msg)
elif len(ctx.files.in_file) == 1:
in_path = ctx.files.in_file[0].short_path
in_path = to_rlocation_path(ctx, ctx.files.in_file[0])
else:
msg = "in file {} must be a single file or a target that provides a DirectoryPathInfo".format(ctx.attr.in_file.label)
fail(msg)
Expand Down
Loading