rust/ci/check_diff.sh
Yacin Tmimi 37489e43b6 Update how LD_LIBRARY_PATH is set for rustfmt binaries in diff check
rustfmt currently has a runtime dependency on the sysroot. So when we
build a standalone rustfmt binary we need to set `LD_LIBRARY_PATH` so
each rustfmt binary knows where to find it's dependencies.

When running our Diff-Check job to test PRs for breaking changes it's
often the case that both the master rustfmt binary and the feature
branch binary have the same runtime dependencies so we only need to
set `LD_LIBRARY_PATH` once.

However, when running the diff-check job against a subtree sync PR that
assumption doesn't hold. The subtree sync PR bumps the required
toolchain used to build rustfmt and therefore the binary that gets built
for the subtree sync PR has a different runtime dependency than the
master rustfmt binary.

Now we set `LD_LIBRARY_PATH` twice to account for this potential
difference.
2023-11-01 20:21:47 -05:00

235 lines
7.9 KiB
Bash
Executable File

#!/bin/bash
set -e
function print_usage() {
echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
}
if [ $# -le 1 ]; then
print_usage
exit 1
fi
REMOTE_REPO=$1
FEATURE_BRANCH=$2
OPTIONAL_COMMIT_HASH=$3
OPTIONAL_RUSTFMT_CONFIGS=$4
# OUTPUT array used to collect all the status of running diffs on various repos
STATUSES=()
# Clone a git repository and cd into it.
#
# Parameters:
# $1: git clone url
# $2: directory where the repo should be cloned
function clone_repo() {
GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
}
# Initialize Git submoduels for the repo.
#
# Parameters
# $1: list of directories to initialize
function init_submodules() {
git submodule update --init $1
}
# Run rusfmt with the --check flag to see if a diff is produced.
#
# Parameters:
# $1: Path to a rustfmt binary
# $2: Output file path for the diff
# $3: Any additional configuration options to pass to rustfmt
#
# Globlas:
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
function create_diff() {
local config;
if [ -z "$3" ]; then
config="--config=error_on_line_overflow=false,error_on_unformatted=false"
else
config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS"
fi
for i in `find . | grep "\.rs$"`
do
$1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null
done
}
# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs
#
# Parameters
# $1: Name of the repository (used for logging)
#
# Globlas:
# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
function check_diff() {
echo "running rustfmt (master) on $1"
create_diff $RUSFMT_BIN rustfmt_diff.txt
echo "running rustfmt (feature) on $1"
create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS
echo "checking diff"
local diff;
# we don't add color to the diff since we added color when running rustfmt --check.
# tail -n + 6 removes the git diff header info
# cut -c 2- removes the leading diff characters("+","-"," ") from running git diff.
# Again, the diff output we care about was already added when we ran rustfmt --check
diff=$(
git --no-pager diff --color=never \
--unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2-
)
if [ -z "$diff" ]; then
echo "no diff detected between rustfmt and the feture branch"
return 0
else
echo "$diff"
return 1
fi
}
# Compiles and produces two rustfmt binaries.
# One for the current master, and another for the feature branch
#
# Parameters:
# $1: Directory where rustfmt will be cloned
#
# Globlas:
# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
# $FEATURE_BRANCH: Name of the feature branch
# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
function compile_rustfmt() {
RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
clone_repo $RUSTFMT_REPO $1
git remote add feature $REMOTE_REPO
git fetch feature $FEATURE_BRANCH
CARGO_VERSON=$(cargo --version)
echo -e "\ncompiling with $CARGO_VERSON\n"
# Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each
# binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675
# This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary
export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
echo "Building rustfmt from src"
cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then
git switch $FEATURE_BRANCH
else
git switch $OPTIONAL_COMMIT_HASH --detach
fi
# This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary.
# In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build
# in `compile_rustfmt`, however, there are scenarios where each binary has different runtime
# dependencies. For example, during subtree syncs we bump the nightly toolchain required to build
# rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies.
export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
echo "Building feature rustfmt from src"
cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
RUSFMT_BIN=$1/rustfmt
RUSTFMT_VERSION=$($RUSFMT_BIN --version)
echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n"
FEATURE_BIN=$1/feature_rustfmt
FEATURE_VERSION=$($FEATURE_BIN --version)
echo -e "FEATURE_BIN $FEATURE_VERSION\n"
}
# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
#
# Parameters
# $1: Clone URL for the repo
# $2: Name of the repo (mostly used for logging)
# $3: Path to any submodules that should be initialized
function check_repo() {
WORKDIR=$(pwd)
REPO_URL=$1
REPO_NAME=$2
SUBMODULES=$3
local tmp_dir;
tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
clone_repo $REPO_URL $tmp_dir
if [ ! -z "$SUBMODULES" ]; then
init_submodules $SUBMODULES
fi
# rustfmt --check returns 1 if a diff was found
# Also check_diff returns 1 if there was a diff between master rustfmt and the feature branch
# so we want to ignore the exit status check
set +e
check_diff $REPO_NAME
# append the status of running `check_diff` to the STATUSES array
STATUSES+=($?)
set -e
echo -e "removing tmp_dir $tmp_dir\n\n"
rm -rf $tmp_dir
cd $WORKDIR
}
function main() {
tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
echo Created tmp_dir $tmp_dir
compile_rustfmt $tmp_dir
# run checks
check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
check_repo "https://github.com/rust-lang/cargo.git" cargo
check_repo "https://github.com/rust-lang/miri.git" miri
check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
check_repo "https://github.com/bitflags/bitflags.git" bitflags
check_repo "https://github.com/rust-lang/log.git" log
check_repo "https://github.com/rust-lang/mdBook.git" mdBook
check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
check_repo "https://github.com/Stebalien/tempfile.git" tempfile
check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
check_repo "https://github.com/dtolnay/anyhow.git" anyhow
check_repo "https://github.com/dtolnay/thiserror.git" thiserror
check_repo "https://github.com/dtolnay/syn.git" syn
check_repo "https://github.com/serde-rs/serde.git" serde
check_repo "https://github.com/rust-lang/rustlings.git" rustlings
check_repo "https://github.com/rust-lang/rustup.git" rustup
check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
check_repo "https://github.com/rustls/rustls.git" rustls
check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
check_repo "https://github.com/hyperium/hyper.git" hyper
check_repo "https://github.com/actix/actix.git" actix
check_repo "https://github.com/denoland/deno.git" denoland_deno
# cleanup temp dir
echo removing tmp_dir $tmp_dir
rm -rf $tmp_dir
# figure out the exit code
for status in ${STATUSES[@]}
do
if [ $status -eq 1 ]; then
echo "formatting diff found 💔"
return 1
fi
done
echo "no diff found 😊"
}
main