Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ tasks:
- "//..."
test_targets:
- "//..."
windows:
build_targets:
- "//..."
test_targets:
- "//..."

e2e_ubuntu2204:
platform: ubuntu2204
Expand Down
25 changes: 25 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
###############################################################################
## Bazel Configuration Flags
##
## `.bazelrc` is a Bazel configuration file.
## https://bazel.build/docs/best-practices#bazelrc-file
###############################################################################

# https://github.com/bazelbuild/bazel/issues/8195
build --incompatible_disallow_empty_glob=true

# https://github.com/bazelbuild/bazel/issues/12821
build --nolegacy_external_runfiles

# https://github.com/bazelbuild/bazel/issues/23043.
build --incompatible_autoload_externally=

###############################################################################
## Custom user flags
##
## This should always be the last thing in the `.bazelrc` file to ensure
## consistent behavior when setting flags in that file as `.bazelrc` files are
## evaluated top to bottom.
###############################################################################

try-import %workspace%/user.bazelrc
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/e2e/*/bazel-*
.idea
*.sw*
user.bazelrc
3 changes: 1 addition & 2 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module(
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "rules_cc", version = "0.0.17")
bazel_dep(name = "rules_shell", version = "0.4.0")

repos = use_extension("@rules_perl//perl:extensions.bzl", "perl_repositories")
use_repo(
Expand All @@ -35,5 +36,3 @@ use_repo(
"fcgi",
"genhtml",
)

bazel_dep(name = "rules_shell", version = "0.4.0", dev_dependency = True)
25 changes: 21 additions & 4 deletions examples/genhtml/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,33 @@

load("@rules_perl//perl:perl.bzl", "perl_test")

genrule(
name = "generated_html",
srcs = [
"coverage.dat",
"genhtml_test.t",
],
outs = ["index.html"],
cmd = "$(execpath @genhtml//:genhtml_bin) --quiet --output-directory $$(dirname $(execpath index.html)) $(execpath coverage.dat)",
tools = [
"@genhtml//:genhtml_bin",
],
)

perl_test(
name = "genhtml_test",
srcs = ["genhtml_test.t"],
data = [
"coverage.dat",
"genhtml_test.t",
"@genhtml//:genhtml_bin",
":index.html",
],
env = {
"GENHTML_BIN": "$(rlocationpath @genhtml//:genhtml_bin)",
"COVERAGE_INDEX_HTML": "$(rootpath :index.html)",
},
# TODO: A runfiles API should be implemented to find the `index.html` file for this test.
# For more details see: https://github.com/bazel-contrib/rules_perl/issues/85
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
visibility = ["//visibility:public"],
)
15 changes: 12 additions & 3 deletions examples/genhtml/genhtml_test.t
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@

use strict;
use warnings;
use Test::More;

use Test::More tests => 1;
my $file = $ENV{'COVERAGE_INDEX_HTML'};
ok(defined $file, 'COVERAGE_INDEX_HTML is set');

`../$ENV{GENHTML_BIN} -o $ENV{TEST_UNDECLARED_OUTPUTS_DIR} examples/genhtml/coverage.dat`;
ok(-e "$ENV{TEST_UNDECLARED_OUTPUTS_DIR}/index.html", 'genhtml generated index.html');
if (defined $file) {
open my $fh, '<', $file or die "Could not open file '$file': $!\n";
my $content = do { local $/; <$fh> };
close $fh;

like($content, qr{<title>LCOV - coverage\.dat</title>}, 'Expected <title> tag found');
}

done_testing;
7 changes: 6 additions & 1 deletion examples/hello_world/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.

load("//perl:perl.bzl", "perl_binary")
load("//perl:perl.bzl", "perl_binary", "perl_test")

package(default_visibility = ["//visibility:public"])

perl_binary(
name = "hello_world",
srcs = ["hello_world.pl"],
)

perl_test(
name = "hello_world_test",
srcs = ["hello_world_test.t"],
)
5 changes: 5 additions & 0 deletions examples/hello_world/hello_world_test.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use strict;
use warnings;
use Test::More tests => 1;

is(1 + 2, 3, '1 + 2 equals 3');
6 changes: 5 additions & 1 deletion perl/BUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
load("//:platforms.bzl", "platforms")
load(":toolchain.bzl", "current_perl_toolchain", "perl_toolchain")

exports_files(["binary_wrapper.tpl"])
alias(
name = "binary_wrapper.tpl",
actual = "//perl/private:binary_wrapper.tpl",
visibility = ["//visibility:public"],
)

# toolchain_type defines a name for a kind of toolchain. Our toolchains
# declare that they have this type. Our rules request a toolchain of this type.
Expand Down
8 changes: 8 additions & 0 deletions perl/deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ def perl_rules_dependencies():
sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
)

_maybe(
http_archive,
name = "rules_shell",
sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
strip_prefix = "rules_shell-0.4.0",
url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)

def _maybe(rule, name, **kwargs):
"""Declares an external repository if it hasn't been declared already."""
if name not in native.existing_rules():
Expand Down
15 changes: 14 additions & 1 deletion perl/private/BUILD
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
exports_files(["binary_wrapper.tpl"])
exports_files([
"binary_wrapper.bat.tpl",
"binary_wrapper.sh.tpl",
"entrypoint.pl",
])

alias(
name = "binary_wrapper.tpl",
actual = select({
"@platforms//os:windows": "binary_wrapper.bat.tpl",
"//conditions:default": "binary_wrapper.sh.tpl",
}),
visibility = ["//visibility:public"],
)
76 changes: 76 additions & 0 deletions perl/private/binary_wrapper.bat.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@ECHO OFF

SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION

@REM Usage of rlocation function:
@REM
@REM call :rlocation <runfile_path> <abs_path>
@REM
@REM The rlocation function maps the given <runfile_path> to its absolute
@REM path and stores the result in a variable named <abs_path>. This
@REM function fails if the <runfile_path> doesn't exist in mainifest file.
:: Start of rlocation
goto :rlocation_end
:rlocation
if "%~2" equ "" (
echo>&2 ERROR: Expected two arguments for rlocation function.
exit 1
)
if exist "%RUNFILES_DIR%" (
set RUNFILES_MANIFEST_FILE=%RUNFILES_DIR%_manifest
)
if "%RUNFILES_MANIFEST_FILE%" equ "" (
set RUNFILES_MANIFEST_FILE=%~f0.runfiles\MANIFEST
)
if not exist "%RUNFILES_MANIFEST_FILE%" (
set RUNFILES_MANIFEST_FILE=%~f0.runfiles_manifest
)
set MF=%RUNFILES_MANIFEST_FILE:/=\%
if not exist "%MF%" (
echo>&2 ERROR: Manifest file %MF% does not exist.
exit 1
)
set runfile_path=%~1
for /F "tokens=2* usebackq" %%i in (`%SYSTEMROOT%\system32\findstr.exe /l /c:"!runfile_path! " "%MF%"`) do (
set abs_path=%%i
)
if "!abs_path!" equ "" (
echo>&2 ERROR: !runfile_path! not found in runfiles manifest
exit 1
)
set %~2=!abs_path!
exit /b 0
:rlocation_end


@REM Function to replace forward slashes with backslashes.
goto :slocation_end
:slocation
set "input=%~1"
set "varName=%~2"
set "output="

@REM Replace forward slashes with backslashes
set "output=%input:/=\%"

@REM Assign the sanitized path to the specified variable
set "%varName%=%output%"
exit /b 0
:slocation_end


call :rlocation "{interpreter}" INTERPRETER
call :rlocation "{entrypoint}" ENTRYPOINT
call :rlocation "{config}" CONFIG
call :rlocation "{main}" MAIN

@REM Unset runfiles dir so windows consistently works with and without it.
set RUNFILES_DIR=

%INTERPRETER% ^
%ENTRYPOINT% ^
%CONFIG% ^
%MAIN% ^
"--" ^
%*
30 changes: 30 additions & 0 deletions perl/private/binary_wrapper.sh.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash

# --- begin runfiles.bash initialization v3 ---
# Copy-pasted from the Bazel Bash runfiles library v3.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
# shellcheck disable=SC1090
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---

set -euo pipefail

INTERPRETER="$(rlocation "{interpreter}")"
ENTRYPOINT="$(rlocation "{entrypoint}")"
CONFIG="$(rlocation "{config}")"
MAIN="$(rlocation "{main}")"

runfiles_export_envvars

exec \
"${INTERPRETER}" \
"${ENTRYPOINT}" \
"${CONFIG}" \
"${MAIN}" \
-- \
"$@"
15 changes: 0 additions & 15 deletions perl/private/binary_wrapper.tpl

This file was deleted.

90 changes: 90 additions & 0 deletions perl/private/entrypoint.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use strict;
use warnings;
use File::Spec;
use File::Temp qw/tempdir/;
use File::Path qw/make_path/;
use File::Copy qw/copy/;
use File::Basename qw/dirname/;
use Cwd 'abs_path';
use JSON::PP;

# Ensure enough args
die "Usage: $0 <config.json> <main.pl> -- [args...]" unless @ARGV >= 3;

# Extract config path and main script path
my $config_path = shift @ARGV;
my $main_path = shift @ARGV;

# Find `--` separator
my $separator_index = 0;
$separator_index++ until $separator_index >= @ARGV || $ARGV[$separator_index] eq '--';
die "Missing -- separator after config and main script paths" if $separator_index == @ARGV;

# Get args after --
my @extra_args = @ARGV[ $separator_index + 1 .. $#ARGV ];
splice(@ARGV, $separator_index); # remove args after --

# Load JSON config
open my $fh, '<', $config_path or die "Can't open config file '$config_path': $!";
my $json_text = do { local $/; <$fh> };
close $fh;

my $config = decode_json($json_text);
my $includes = $config->{includes} // [];

# Create RUNFILES_DIR if not set
my $runfiles = $ENV{RUNFILES_DIR};
unless (defined $runfiles) {
my $manifest = $ENV{RUNFILES_MANIFEST_FILE}
or die "RUNFILES_DIR is not set and RUNFILES_MANIFEST_FILE is not provided.\n";

# Create a temporary runfiles directory
$runfiles = tempdir(CLEANUP => 1);
if (defined $ENV{RULES_PERL_DEBUG}) {
warn "[DEBUG] RUNFILES_DIR created: $runfiles\n";
}
$ENV{RUNFILES_DIR} = $runfiles;

# Copy entries from manifest
open my $mfh, '<', $manifest or die "Failed to open manifest file '$manifest': $!";
while (my $line = <$mfh>) {
chomp $line;
next if $line =~ /^\s*$/; # skip blank lines

my ($rel_path, $real_path) = split ' ', $line, 2;
die "Invalid manifest line: $line" unless defined $real_path;

my $dst_path = File::Spec->catfile($runfiles, $rel_path);
make_path(dirname($dst_path));
copy($real_path, $dst_path)
or die "Failed to copy '$real_path' to '$dst_path': $!";
}
close $mfh;
}

# Make sure RUNFILES_DIR is absolute
unless (File::Spec->file_name_is_absolute($runfiles)) {
$runfiles = File::Spec->rel2abs($runfiles);
$ENV{RUNFILES_DIR} = $runfiles;
}

# Build include paths relative to RUNFILES_DIR
my @include_paths = map { File::Spec->catfile($runfiles, $_) } @$includes;

# Get current Perl interpreter
my $perl = abs_path($^X);

# Build -I include flags
my @inc_flags = map { ('-I', $_) } @include_paths;

# Build the full command array
my @cmd = ($perl, @inc_flags, $main_path, @extra_args);

# Debug output if RULES_PERL_DEBUG is set
if (defined $ENV{RULES_PERL_DEBUG}) {
warn "[DEBUG] Subprocess command: @cmd\n";
}

# Run the command in a subprocess, exit with its code
my $exit = system(@cmd);
exit($exit >> 8);
Loading