Skip to content

install: fix simplify conditional expressions and improve error handling #34364

install: fix simplify conditional expressions and improve error handling

install: fix simplify conditional expressions and improve error handling #34364

Workflow file for this run

name: CICD
# spell-checker:ignore (abbrev/names) CACHEDIR CICD CodeCOV MacOS MinGW MSVC musl taiki
# spell-checker:ignore (env/flags) Awarnings Ccodegen Coverflow Cpanic Dwarnings RUSTDOCFLAGS RUSTFLAGS Zpanic CARGOFLAGS CLEVEL nodocs
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain fuzzers dedupe devel profdata
# spell-checker:ignore (people) Peltoche rivy dtolnay Anson dawidd
# spell-checker:ignore (shell/tools) binutils choco clippy dmake esac fakeroot fdesc fdescfs gmake grcov halium lcov libclang libfuse libssl limactl mkdir nextest nocross pacman popd printf pushd redoxer rsync rustc rustfmt rustup shopt sccache utmpdump xargs zstd
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils defconfig DESTDIR gecos getenforce gnueabihf issuecomment maint manpages msys multisize noconfirm nofeatures nullglob onexitbegin onexitend pell runtest Swatinem tempfile testsuite toybox uutils libsystemd codspeed wasip
env:
PROJECT_NAME: coreutils
PROJECT_DESC: "Core universal (cross-platform) utilities"
PROJECT_AUTH: "uutils"
RUST_MIN_SRV: "1.88.0"
# * style job configuration
STYLE_FAIL_ON_FAULT: true ## (bool) fail the build if a style job contains a fault (error or warning); may be overridden on a per-job basis
on:
pull_request:
push:
tags:
- '*'
branches:
- '*'
permissions:
contents: read # to fetch code (actions/checkout)
# End the current execution if there is a new changeset in the PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
cargo-deny:
name: Style/cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: EmbarkStudios/cargo-deny-action@v2
style_deps:
## ToDO: [2021-11-10; rivy] 'Style/deps' needs more informative output and better integration of results into the GHA dashboard
name: Style/deps
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
# note: `cargo-udeps` panics when processing stdbuf/libstdbuf ("uu_stdbuf_libstdbuf"); either b/c of the 'cpp' crate or 'libstdbuf' itself
# ... b/c of the panic, a more limited feature set is tested (though only excluding `stdbuf`)
- { os: ubuntu-latest , features: "feat_Tier1,feat_require_unix,feat_require_unix_utmpx" }
- { os: macos-latest , features: "feat_Tier1,feat_require_unix,feat_require_unix_utmpx" }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: taiki-e/install-action@cargo-udeps
- uses: Swatinem/rust-cache@v2
- name: Initialize workflow variables
id: vars
shell: bash
run: |
echo "RUSTC_BOOTSTRAP=1" >> "${GITHUB_ENV}" # Use -Z
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
outputs CARGO_FEATURES_OPTION
- name: Detect unused dependencies
shell: bash
run: |
## Detect unused dependencies
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
#
cargo udeps ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --all-targets &> udeps.log || cat udeps.log
grep --ignore-case "all deps seem to have been used" udeps.log || { printf "%s\n" "::${fault_type} ::${fault_prefix}: \`cargo udeps\`: style violation (unused dependency found)" ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
doc_warnings:
name: Documentation/warnings
runs-on: ${{ matrix.job.os }}
env:
CARGO_INCREMENTAL: 0
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
# for now, don't build it on mac & windows because the doc is only published from linux
# + it needs a bunch of duplication for build
# and I don't want to add a doc step in the regular build to avoid long builds
# - { os: macos-latest , features: feat_os_macos }
# - { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
- name: Install/setup prerequisites
shell: bash
run: |
sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu libselinux1-dev
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='--all-features' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features ${{ matrix.job.features }}' ; fi
outputs CARGO_FEATURES_OPTION
# * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})"
echo UTILITY_LIST=${UTILITY_LIST}
CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)"
outputs CARGO_UTILITY_LIST_OPTIONS
- name: "`cargo doc` with warnings"
shell: bash
run: |
RUSTDOCFLAGS="-Dwarnings" cargo doc ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-deps --workspace --document-private-items
- uses: DavidAnson/markdownlint-cli2-action@v22
with:
fix: "true"
globs: |
*.md
docs/src/*.md
src/uu/*/*.md
min_version:
name: MinRustV # Minimum supported rust version (aka, MinSRV or MSRV)
runs-on: ${{ matrix.job.os }}
env:
CARGO_INCREMENTAL: 0
strategy:
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_MIN_SRV }}
components: rustfmt
- uses: taiki-e/install-action@nextest
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# target-specific options
# * CARGO_FEATURES_OPTION
unset CARGO_FEATURES_OPTION
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
outputs CARGO_FEATURES_OPTION
- name: Confirm MinSRV compatible '*/Cargo.lock'
shell: bash
run: |
## Confirm MinSRV compatible '*/Cargo.lock'
# * '*/Cargo.lock' is required to be in a format that `cargo` of MinSRV can interpret (eg, v1-format for MinSRV < v1.38)
for dir in "." "fuzz"; do
( cd "$dir" && cargo fetch --locked --quiet --target $(rustc --print host-tuple)) || { echo "::error file=$dir/Cargo.lock::Incompatible (or out-of-date) '$dir/Cargo.lock' file; update using \`cd '$dir' && cargo +${{ env.RUST_MIN_SRV }} update\`" ; exit 1 ; }
done
- name: Install/setup prerequisites
shell: bash
run: |
# Install a package for one of the tests
sudo apt-get -y update ; sudo apt-get -y install attr
- name: Info
shell: bash
run: |
## Info
# environment
echo "## environment"
echo "CI='${CI}'"
# tooling info display
echo "## tooling"
which gcc >/dev/null 2>&1 && (gcc --version | head -1) || true
rustup -V 2>/dev/null
rustup show active-toolchain
cargo -V
rustc -V
cargo tree -V
# dependencies
echo "## dependency list"
## * using the 'stable' toolchain is necessary to avoid "unexpected '--filter-platform'" errors
cargo +stable fetch --locked --quiet --target $(rustc --print host-tuple)
cargo +stable tree --no-dedupe --locked -e=no-dev --prefix=none ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} | grep -vE "$PWD" | sort --unique
- name: Test
run: cargo nextest run --hide-progress-bar --profile ci ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils
env:
RUSTFLAGS: "-Awarnings"
RUST_BACKTRACE: "1"
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
files: target/nextest/ci/junit.xml
disable_search: true
flags: msrv,${{ matrix.job.os }}
fail_ci_if_error: false
deps:
name: Dependencies
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: "`cargo update` testing"
shell: bash
run: |
## `cargo update` testing
# * convert any errors/warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
for dir in "." "fuzz"; do
( cd "$dir" && cargo fetch --locked --quiet --target $(rustc --print host-tuple)) || { echo "::error file=$dir/Cargo.lock::'$dir/Cargo.lock' file requires update (use \`cd '$dir' && cargo +${{ env.RUST_MIN_SRV }} update\`)" ; exit 1 ; }
done
build_rust_stable:
name: Build/stable
needs: [ min_version, deps ]
runs-on: ${{ matrix.job.os }}
timeout-minutes: 90
env:
CARGO_INCREMENTAL: 0
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
- { os: macos-latest , features: feat_os_macos }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@nextest
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
- name: Test
run: cargo nextest run --hide-progress-bar --profile ci --features ${{ matrix.job.features }}
env:
RUST_BACKTRACE: "1"
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
files: target/nextest/ci/junit.xml
disable_search: true
flags: stable,${{ matrix.job.os }}
fail_ci_if_error: false
build_rust_nightly:
name: Build/nightly
needs: [ min_version, deps ]
runs-on: ${{ matrix.job.os }}
timeout-minutes: 90
env:
CARGO_INCREMENTAL: 0
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
- { os: macos-latest , features: feat_os_macos }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@nightly
- uses: taiki-e/install-action@nextest
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
- name: Test
run: cargo nextest run --hide-progress-bar --profile ci --features ${{ matrix.job.features }}
env:
RUST_BACKTRACE: "1"
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
files: target/nextest/ci/junit.xml
disable_search: true
flags: nightly,${{ matrix.job.os }}
fail_ci_if_error: false
build:
permissions:
contents: write # to create GitHub release (softprops/action-gh-release)
name: Build
needs: [ min_version, deps ]
runs-on: ${{ matrix.job.os }}
timeout-minutes: 90
env:
DOCKER_OPTS: '--volume /etc/passwd:/etc/passwd --volume /etc/group:/etc/group'
CARGO_INCREMENTAL: 0
strategy:
fail-fast: false
matrix:
job:
# - { os , target , cargo-options , default-features, features , use-cross , toolchain, skip-tests, workspace-tests, skip-package, skip-publish }
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , features: feat_os_unix_gnueabihf , use-cross: use-cross , skip-tests: true }
- { os: ubuntu-24.04-arm , target: aarch64-unknown-linux-gnu , features: feat_os_unix_gnueabihf }
- { os: ubuntu-latest , target: aarch64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross , skip-tests: true }
- { os: ubuntu-latest , target: riscv64gc-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross , skip-tests: true }
# - { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_selinux , use-cross: use-cross }
- { os: ubuntu-latest , target: i686-unknown-linux-gnu , features: "feat_os_unix,test_risky_names", use-cross: use-cross }
- { os: ubuntu-latest , target: i686-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: "feat_os_unix,test_risky_names", use-cross: use-cross, skip-publish: true }
- { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: "feat_os_unix,uudoc" , use-cross: no, workspace-tests: true }
- { os: ubuntu-latest , target: x86_64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-redox , features: feat_os_unix_redox , use-cross: redoxer , skip-tests: true , check-only: true }
- { os: ubuntu-latest , target: wasm32-wasip1, default-features: false, features: feat_wasm, skip-tests: true }
- { os: macos-latest , target: aarch64-apple-darwin , features: feat_os_macos, workspace-tests: true } # M1 CPU
# PR #7964: chcon should not break build without the feature. cargo check is enough to detect it.
- { os: macos-latest , target: aarch64-apple-darwin , workspace-tests: true, check-only: true } # M1 CPU
- { os: macos-latest , target: x86_64-apple-darwin , features: feat_os_macos, workspace-tests: true }
- { os: windows-latest , target: i686-pc-windows-msvc , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
- { os: windows-latest , target: aarch64-pc-windows-msvc , features: feat_os_windows, use-cross: use-cross , skip-tests: true }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Avoid no space left on device
run: sudo rm -rf /usr/share/dotnet /usr/local/lib/android &
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_MIN_SRV }}
targets: ${{ matrix.job.target }}
- uses: Swatinem/rust-cache@v2
with:
key: "${{ matrix.job.os }}_${{ matrix.job.target }}"
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# toolchain
TOOLCHAIN="stable" ## default to "stable" toolchain
# * specify alternate/non-default TOOLCHAIN for *-pc-windows-gnu targets; gnu targets on Windows are broken for the standard *-pc-windows-msvc toolchain (refs: GH:rust-lang/rust#47048, GH:rust-lang/rust#53454, GH:rust-lang/cargo#6754)
case ${{ matrix.job.target }} in *-pc-windows-gnu) TOOLCHAIN="stable-${{ matrix.job.target }}" ;; esac;
# * use requested TOOLCHAIN if specified
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
outputs TOOLCHAIN
# staging directory
STAGING='_staging'
outputs STAGING
# parse commit reference info
echo GITHUB_REF=${GITHUB_REF}
echo GITHUB_SHA=${GITHUB_SHA}
REF_NAME=${GITHUB_REF#refs/*/}
unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac;
unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac;
REF_SHAS=${GITHUB_SHA:0:10}
outputs REF_NAME REF_BRANCH REF_TAG REF_SHAS
# parse target
unset TARGET_ARCH
case '${{ matrix.job.target }}' in
aarch64-*) TARGET_ARCH=arm64 ;;
riscv64gc-*) TARGET_ARCH=riscv64 ;;
arm-*-*hf) TARGET_ARCH=armhf ;;
i686-*) TARGET_ARCH=i686 ;;
x86_64-*) TARGET_ARCH=x86_64 ;;
esac;
unset TARGET_OS
case '${{ matrix.job.target }}' in
*-linux-*) TARGET_OS=linux ;;
*-apple-*) TARGET_OS=macos ;;
*-windows-*) TARGET_OS=windows ;;
*-redox*) TARGET_OS=redox ;;
esac
outputs TARGET_ARCH TARGET_OS
# package name
PKG_suffix=".tar.gz" ; case '${{ matrix.job.target }}' in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
# Some 3rd party utils need version at file names
# But we remove it from tag/latest-commit
test ${REF_TAG} \
&& PKG_BASENAME=${PROJECT_NAME}-${REF_TAG}-${{ matrix.job.target }} \
|| PKG_BASENAME=${PROJECT_NAME}-${{ matrix.job.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
outputs PKG_suffix PKG_BASENAME PKG_NAME
# deployable tag? (ie, leading "vM" or "M"; M == version number)
unset DEPLOY ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOY='true' ; fi
outputs DEPLOY
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features=${{ matrix.job.features }}' ; fi
outputs CARGO_FEATURES_OPTION
# * CARGO_DEFAULT_FEATURES_OPTION
CARGO_DEFAULT_FEATURES_OPTION='' ;
if [ "${{ matrix.job.default-features }}" == "false" ]; then CARGO_DEFAULT_FEATURES_OPTION='--no-default-features' ; fi
outputs CARGO_DEFAULT_FEATURES_OPTION
# * CARGO_CMD
CARGO_CMD='cross'
CARGO_CMD_OPTIONS='+${{ env.RUST_MIN_SRV }}'
# Added suffix for artifacts, needed when multiple jobs use the same target.
ARTIFACTS_SUFFIX=''
case '${{ matrix.job.use-cross }}' in
''|0|f|false|n|no)
CARGO_CMD='cargo'
ARTIFACTS_SUFFIX='-nocross'
;;
redoxer)
CARGO_CMD='redoxer'
CARGO_CMD_OPTIONS=''
;;
esac
# needed for target "aarch64-apple-darwin". There are two jobs, and the difference between them is whether "features" is set
if [ -z "${{ matrix.job.features }}" ]; then ARTIFACTS_SUFFIX='-nofeatures' ; fi
outputs CARGO_CMD
outputs CARGO_CMD_OPTIONS
outputs ARTIFACTS_SUFFIX
CARGO_TEST_OPTIONS=''
case '${{ matrix.job.workspace-tests }}' in
1|t|true|y|yes)
# This also runs tests in other packages in the source directory (e.g. uucore).
# We cannot enable this everywhere as some platforms are currently broken, and
# we cannot use `cross` as its Docker image is ancient (Ubuntu 16.04) and is
# missing required system dependencies (e.g. recent libclang-dev).
CARGO_TEST_OPTIONS='--workspace'
;;
esac
- uses: taiki-e/install-action@v2
if: steps.vars.outputs.CARGO_CMD == 'cross'
with:
tool: cross@0.2.5
- name: Create all needed build/work directories
shell: bash
run: |
## Create build/work space
mkdir -p '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}'
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
case '${{ matrix.job.target }}' in
arm-unknown-linux-gnueabihf)
sudo apt-get -y update
sudo apt-get -y install gcc-arm-linux-gnueabihf
;;
aarch64-unknown-linux-*)
sudo apt-get -y update
sudo apt-get -y install gcc-aarch64-linux-gnu
;;
riscv64gc-unknown-linux-*)
sudo apt-get -y update
sudo apt-get -y install gcc-riscv64-linux-gnu
;;
*-redox*)
sudo apt-get -y update
sudo apt-get -y install fuse3 libfuse-dev
;;
esac
case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for testing
esac
case '${{ matrix.job.os }}' in
ubuntu-*)
# selinux and systemd headers needed to build tests
sudo apt-get -y update
sudo apt-get -y install libselinux1-dev libsystemd-dev
# pinky is a tool to show logged-in users from utmp, and gecos fields from /etc/passwd.
# In GitHub Action *nix VMs, no accounts log in, even the "runner" account that runs the commands, and "system boot" entry is missing.
# The account also has empty gecos fields.
# To work around these issues for pinky (and who) tests, we create a fake utmp file with a
# system boot entry and a login entry for the GH runner account.
FAKE_UTMP_2='[2] [00000] [~~ ] [reboot] [~ ] [6.0.0-test] [0.0.0.0] [2022-02-22T22:11:22,222222+00:00]'
FAKE_UTMP_7='[7] [999999] [tty2] [runner] [tty2] [ ] [0.0.0.0] [2022-02-22T22:22:22,222222+00:00]'
(echo "$FAKE_UTMP_2" ; echo "$FAKE_UTMP_7") | sudo utmpdump -r -o /var/run/utmp
# ... and add a full name to each account with a gecos field but no full name.
sudo sed -i 's/:,/:runner name,/' /etc/passwd
# We also create a couple optional files pinky looks for
touch /home/runner/.project
echo "foo" > /home/runner/.plan
# add user with digital username for testing with issue #7787
echo 200:x:2000:2000::/home/200:/bin/bash | sudo tee -a /etc/passwd
echo 200:x:2000: | sudo tee -a /etc/group
;;
esac
- uses: taiki-e/install-action@v2
if: steps.vars.outputs.CARGO_CMD == 'redoxer'
with:
tool: redoxer@0.2.56
- name: Initialize toolchain-dependent workflow variables
id: dep_vars
shell: bash
run: |
## Dependent VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})"
echo UTILITY_LIST=${UTILITY_LIST}
CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)"
outputs CARGO_UTILITY_LIST_OPTIONS
- name: Info
shell: bash
run: |
## Info
# commit info
echo "## commit"
echo GITHUB_REF=${GITHUB_REF}
echo GITHUB_SHA=${GITHUB_SHA}
# environment
echo "## environment"
echo "CI='${CI}'"
# tooling info display
echo "## tooling"
which gcc >/dev/null 2>&1 && (gcc --version | head -1) || true
rustup -V 2>/dev/null
rustup show active-toolchain
cargo -V
rustc -V
cargo tree -V
# dependencies
echo "## dependency list"
cargo fetch --locked --quiet --target $(rustc --print host-tuple)
cargo tree --locked --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.vars.outputs.CARGO_DEFAULT_FEATURES_OPTION }} --no-dedupe -e=no-dev --prefix=none | grep -vE "$PWD" | sort --unique
- name: Check
shell: bash
if: matrix.job.skip-publish != true && matrix.job.check-only == true
run: |
# expr breaks redox
sed -i.b '/"expr",/d' Cargo.toml
${{ steps.vars.outputs.CARGO_CMD }} ${{ steps.vars.outputs.CARGO_CMD_OPTIONS }} check \
--target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.vars.outputs.CARGO_DEFAULT_FEATURES_OPTION }}
- name: Test
if: matrix.job.skip-tests != true && matrix.job.check-only != true
shell: bash
run: |
## Test
${{ steps.vars.outputs.CARGO_CMD }} ${{ steps.vars.outputs.CARGO_CMD_OPTIONS }} test --target=${{ matrix.job.target }} \
${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.vars.outputs.CARGO_DEFAULT_FEATURES_OPTION }} \
${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} -p coreutils
env:
RUST_BACKTRACE: "1"
- name: Build coreutils
shell: bash
if: matrix.job.skip-publish != true && matrix.job.check-only != true && matrix.job.target != 'x86_64-pc-windows-msvc'
run: |
## Build
${{ steps.vars.outputs.CARGO_CMD }} ${{ steps.vars.outputs.CARGO_CMD_OPTIONS }} build --release --config=profile.release.strip=true \
--target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.vars.outputs.CARGO_DEFAULT_FEATURES_OPTION }}
# We don't want to have many duplicated long jobs at here
# So we build individual binaries for few platforms until we deduplicate many release build for Linux
- name: Build individual binaries
if: matrix.job.skip-tests != true && matrix.job.target == 'x86_64-pc-windows-msvc'
shell: bash
run: |
${{ steps.vars.outputs.CARGO_CMD }} ${{ steps.vars.outputs.CARGO_CMD_OPTIONS }} build --release --config=profile.release.strip=true \
--target=${{ matrix.job.target }} ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
- name: Package
if: matrix.job.skip-publish != true && matrix.job.check-only != true
shell: bash
run: |
## Package artifact(s)
find target/${{ matrix.job.target }}/release -maxdepth 1 -type f \
\( -name "*.wasm" -o -name "*.exe" -o -perm -u+x \) \
-exec ln -v {} "${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/" \;
# README and LICENSE
# * spell-checker:ignore EADME ICENSE
(shopt -s nullglob; for f in [R]"EADME"{,.*}; do cp $f '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/' ; done)
(shopt -s nullglob; for f in [L]"ICENSE"{-*,}{,.*}; do cp $f '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/' ; done)
# core compressed package
pushd '${{ steps.vars.outputs.STAGING }}/' >/dev/null
case '${{ matrix.job.target }}' in
*-pc-windows-*) 7z -y a '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* | tail -2 ;;
*) tar czf '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* ;;
esac
popd >/dev/null
- name: Package manpages and completions
if: matrix.job.target == 'x86_64-unknown-linux-gnu' && matrix.job.features == 'feat_os_unix,uudoc'
run: |
mkdir -p share/{man/man1,bash-completion/completions,fish/vendor_completions.d,zsh/site-functions,elvish/lib}
_uudoc=target/${{ matrix.job.target }}/release/uudoc
for bin in $('target/${{ matrix.job.target }}/release/coreutils' --list) coreutils;do
${_uudoc} manpage ${bin} > share/man/man1/${bin}.1
${_uudoc} completion ${bin} bash > share/bash-completion/completions/${bin}.bash
${_uudoc} completion ${bin} fish > share/fish/vendor_completions.d/${bin}.fish
${_uudoc} completion ${bin} zsh > share/zsh/site-functions/_${bin}
${_uudoc} completion ${bin} elvish > share/elvish/lib/${bin}.elv
done
rm share/zsh/site-functions/_[ # not supported
tar --zstd -cf docs.tar.zst share
- name: Publish
uses: softprops/action-gh-release@v2
if: steps.vars.outputs.DEPLOY && matrix.job.skip-publish != true && matrix.job.check-only != true
with:
draft: true
files: |
${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_NAME }}
docs.tar.zst
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish latest commit
uses: softprops/action-gh-release@v2
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.job.skip-publish != true && matrix.job.check-only != true
with:
tag_name: latest-commit
body: |
commit: ${{ github.sha }}
draft: false
prerelease: true
files: |
${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_NAME }}
docs.tar.zst
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
coverage:
name: Code Coverage
runs-on: ${{ matrix.job.os }}
timeout-minutes: 90
env:
CARGO_INCREMENTAL: 0
RUSTC_BOOTSTRAP: 1
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: unix }
# FIXME: Re-enable macos code coverage
# - { os: macos-latest , features: macos }
# FIXME: Re-enable Code Coverage on windows, which currently fails due to "profiler_builtins". See #6686.
# - { os: windows-latest , features: windows, toolchain: stable-x86_64-pc-windows-gnu }
steps:
- uses: actions/checkout@v6
- uses: taiki-e/install-action@v2
with:
tool: nextest,grcov@0.8.24
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
id: sccache-setup
uses: mozilla-actions/sccache-action@v0.0.9
continue-on-error: true
- name: Export sccache
if: steps.sccache-setup.outcome == 'success'
run: |
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
# - name: Reattach HEAD ## may be needed for accurate code coverage info
# run: git checkout ${{ github.head_ref }}
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac;
# * use requested TOOLCHAIN if specified
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
outputs TOOLCHAIN
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='--all-features' ; ## default to '--all-features' for code coverage
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features=${{ matrix.job.features }}' ; fi
outputs CARGO_FEATURES_OPTION
# * CODECOV_FLAGS
CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' )
outputs CODECOV_FLAGS
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for testing
esac
case '${{ matrix.job.os }}' in
ubuntu-latest)
# selinux and systemd headers needed to build tests
sudo apt-get -y update
sudo apt-get -y install libselinux1-dev libsystemd-dev
# pinky is a tool to show logged-in users from utmp, and gecos fields from /etc/passwd.
# In GitHub Action *nix VMs, no accounts log in, even the "runner" account that runs the commands, and "system boot" entry is missing.
# The account also has empty gecos fields.
# To work around these issues for pinky (and who) tests, we create a fake utmp file with a
# system boot entry and a login entry for the GH runner account.
FAKE_UTMP_2='[2] [00000] [~~ ] [reboot] [~ ] [6.0.0-test] [0.0.0.0] [2022-02-22T22:11:22,222222+00:00]'
FAKE_UTMP_7='[7] [999999] [tty2] [runner] [tty2] [ ] [0.0.0.0] [2022-02-22T22:22:22,222222+00:00]'
(echo "$FAKE_UTMP_2" ; echo "$FAKE_UTMP_7") | sudo utmpdump -r -o /var/run/utmp
# ... and add a full name to each account with a gecos field but no full name.
sudo sed -i 's/:,/:runner name,/' /etc/passwd
# We also create a couple optional files pinky looks for
touch /home/runner/.project
echo "foo" > /home/runner/.plan
# add user with digital username for testing with issue #7787
echo 200:x:2000:2000::/home/200:/bin/bash | sudo tee -a /etc/passwd
echo 200:x:2000: | sudo tee -a /etc/group
;;
esac
## Install the llvm-tools component to get access to `llvm-profdata`
rustup component add llvm-tools
- name: Run test and coverage
id: run_test_cov
run: |
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# Run the coverage script
./util/build-run-test-coverage-linux.sh
outputs REPORT_FILE
env:
COVERAGE_DIR: ${{ github.workspace }}/coverage
FEATURES_OPTION: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
# RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }}
- name: Upload coverage results (to Codecov.io)
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ steps.run_test_cov.outputs.report }}
## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
name: codecov-umbrella
fail_ci_if_error: false
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
files: target/nextest/coverage/junit.xml
disable_search: true
flags: coverage,${{ matrix.job.os }}
fail_ci_if_error: false
test_selinux:
name: Build/SELinux
needs: [ min_version, deps ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Setup Lima
uses: lima-vm/lima-actions/setup@v1
id: lima-actions-setup
- name: Cache ~/.cache/lima
uses: actions/cache@v5
with:
path: ~/.cache/lima
key: lima-${{ steps.lima-actions-setup.outputs.version }}
- name: Start Fedora VM with SELinux
run: limactl start --plain --name=default --cpus=4 --disk=30 --memory=4 --network=lima:user-v2 template:fedora
- run: rsync -v -a -e ssh . lima-default:~/work/
- name: Setup Rust and other build deps in VM
run: |
lima sudo dnf install --nodocs gcc g++ git rustup libselinux-devel clang-devel attr -y
lima rustup-init -y --default-toolchain stable --profile minimal -c clippy
- name: Verify SELinux Status
run: |
lima getenforce
lima ls -laZ /etc/selinux
- name: Build and Test with SELinux
run: |
lima ls
lima bash -c "cd work && cargo test --features 'feat_selinux' --no-default-features"
- name: Lint with SELinux
run: lima bash -c "cd work && cargo clippy --all-targets --features 'feat_selinux' --no-default-features -- -D warnings"
test_selinux_stubs:
name: Build/SELinux-Stubs (Non-Linux)
needs: [ min_version, deps ]
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: macos-latest , features: feat_os_macos }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build SELinux utilities as stubs
run: cargo build -p uu_chcon -p uu_runcon
- name: Verify stub binaries exist
shell: bash
run: |
test -f target/debug/chcon || test -f target/debug/chcon.exe
test -f target/debug/runcon || test -f target/debug/runcon.exe
# check is enough to detect workspace breakage by chcon
- name: Verify workspace builds with stubs
run: cargo check --features ${{ matrix.job.features }}
test_safe_traversal:
name: Safe Traversal Security Check
runs-on: ubuntu-latest
needs: [ min_version, deps ]
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install strace
run: sudo apt-get update && sudo apt-get install -y strace
- name: Build utilities with safe traversal
run: cargo build --profile=release-small -p uu_rm -p uu_chmod -p uu_chown -p uu_chgrp -p uu_mv -p uu_du
- name: Run safe traversal verification
run: ./util/check-safe-traversal.sh