diff --git a/.editorconfig b/.editorconfig index 053c57353..a753582e0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,16 +13,20 @@ max_line_length = 100 indent_style = tab [*.{md,rst}] +max_line_length = unset trim_trailing_whitespace = false -[*.{sh,ac}] -indent_size = 2 +[*.sh] +indent_size = 4 + +[build_tools/release.sh] +max_line_length = 72 [Dockerfile] indent_size = 2 [share/{completions,functions}/**.fish] -max_line_length = off +max_line_length = unset -[{COMMIT_EDITMSG,git-revise-todo}] -max_line_length = 80 +[{COMMIT_EDITMSG,git-revise-todo,*.jjdescription}] +max_line_length = 72 diff --git a/.github/actions/rust-toolchain@oldest-supported/action.yml b/.github/actions/rust-toolchain@oldest-supported/action.yml new file mode 100644 index 000000000..5bde7cf45 --- /dev/null +++ b/.github/actions/rust-toolchain@oldest-supported/action.yml @@ -0,0 +1,20 @@ +name: Oldest Supported Rust Toolchain + +inputs: + targets: + description: Comma-separated list of target triples to install for this toolchain + required: false + components: + description: Comma-separated list of components to be additionally installed + required: false + +permissions: + contents: read + +runs: + using: "composite" + steps: + - uses: dtolnay/rust-toolchain@1.70 + with: + targets: ${{ inputs.targets }} + components: ${{ inputs.components}} diff --git a/.github/actions/rust-toolchain@stable/action.yml b/.github/actions/rust-toolchain@stable/action.yml new file mode 100644 index 000000000..e3d4bd0e5 --- /dev/null +++ b/.github/actions/rust-toolchain@stable/action.yml @@ -0,0 +1,20 @@ +name: Stable Rust Toolchain + +inputs: + targets: + description: Comma-separated list of target triples to install for this toolchain + required: false + components: + description: Comma-separated list of components to be additionally installed + required: false + +permissions: + contents: read + +runs: + using: "composite" + steps: + - uses: dtolnay/rust-toolchain@1.89 + with: + targets: ${{ inputs.targets }} + components: ${{ inputs.components }} diff --git a/.github/workflows/mac_codesign.yml b/.github/workflows/mac_codesign.yml deleted file mode 100644 index 10ebbaa58..000000000 --- a/.github/workflows/mac_codesign.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: macOS build and codesign - -on: - workflow_dispatch: # Enables manual trigger from GitHub UI - -jobs: - build-and-code-sign: - runs-on: macos-latest - environment: macos-codesign - steps: - - uses: actions/checkout@v4 - - name: Install Rust 1.73.0 - uses: dtolnay/rust-toolchain@1.73.0 - with: - targets: x86_64-apple-darwin - - name: Install Rust Stable - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-apple-darwin - - name: build-and-codesign - run: | - cargo install apple-codesign - mkdir -p "$FISH_ARTEFACT_PATH" - echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode > /tmp/app.p12 - echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode > /tmp/installer.p12 - echo "$MACOS_NOTARIZE_JSON" > /tmp/notarize.json - ./build_tools/make_pkg.sh -s -f /tmp/app.p12 -i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" -n -j /tmp/notarize.json - rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json - env: - MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }} - MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }} - MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }} - MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }} - # macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead - # of crates.io, so give this a try. It's also sometimes significantly faster on all platforms. - CARGO_NET_GIT_FETCH_WITH_CLI: true - FISH_ARTEFACT_PATH: /tmp/fish-built - - uses: actions/upload-artifact@v4 - with: - name: macOS Artefacts - path: /tmp/fish-built/* - if-no-files-found: error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..2d3b1f34f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,211 @@ +name: Create a new release + +on: + push: + tags: + - '*.*.*' + +permissions: + contents: write + +jobs: + is-release-tag: + name: Pre-release checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Workaround for https://github.com/actions/checkout/issues/882 + ref: ${{ github.ref }} + - name: Check if the pushed tag looks like a release + run: | + set -x + commit_subject=$(git log -1 --format=%s) + tag=$(git describe) + [ "$commit_subject" = "Release $tag" ] + + + source-tarball: + needs: [is-release-tag] + name: Create the source tarball + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + tarball-name: ${{ steps.version.outputs.tarball-name }} + steps: + - uses: actions/checkout@v4 + with: + # Workaround for https://github.com/actions/checkout/issues/882 + ref: ${{ github.ref }} + - name: Install dependencies + run: sudo apt install cmake gettext ninja-build python3-pip python3-sphinx + - name: Create tarball + run: | + set -x + mkdir /tmp/fish-built + FISH_ARTEFACT_PATH=/tmp/fish-built ./build_tools/make_tarball.sh + { + pip install sphinx-markdown-builder==0.6.8 + relnotes_tmp=$(mktemp -d) + mkdir "$relnotes_tmp/src" "$relnotes_tmp/out" + version=$(git describe) + minor_version=${version%.*} + # Delete notes for prior releases. + # Also fix up any relative references to other documentation files. + awk "$relnotes_tmp/src"/index.rst \ + -e 's,:doc:`\(.*\) <\([^>]*\)>`,`\1 `_,g' \ + -e 's,:envvar:`\([^`]*\)`,``$\1``,g' + # In future, we could reuse doctree from when we made HTML docs. + sphinx-build -j 1 $(: "sphinx-markdown-builder is not marked concurrency-safe") \ + -W -E -b markdown -c doc_src \ + -d "$relnotes_tmp/doctree" "$relnotes_tmp/src" $relnotes_tmp/out + # Delete title + sed -n 1p "$relnotes_tmp/out/index.md" | grep -q "^# fish .*" + sed -n 2p "$relnotes_tmp/out/index.md" | grep -q '^$' + sed -i 1,2d "$relnotes_tmp/out/index.md" + { + cat "$relnotes_tmp/out/index.md" - </tmp/fish-built/release-notes.md + rm -r "$relnotes_tmp" + } + - name: Upload tarball artifact + uses: actions/upload-artifact@v4 + with: + name: source-tarball + path: | + /tmp/fish-built/fish-${{ github.ref_name }}.tar.xz + /tmp/fish-built/release-notes.md + if-no-files-found: error + + packages-for-linux: + needs: [is-release-tag] + name: Build single-file fish for Linux (experimental) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Workaround for https://github.com/actions/checkout/issues/882 + ref: ${{ github.ref }} + - name: Install Rust Stable + uses: ./.github/actions/rust-toolchain@stable + with: + targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl + - name: Install dependencies + run: sudo apt install crossbuild-essential-arm64 musl-tools python3-sphinx + - name: Build statically-linked executables + run: | + set -x + CFLAGS="-D_FORTIFY_SOURCE=2" \ + CMAKE_WITH_GETTEXT=0 \ + CC=aarch64-linux-gnu-gcc \ + RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" \ + cargo build --release --target aarch64-unknown-linux-musl --bin fish + cargo build --release --target x86_64-unknown-linux-musl --bin fish + - name: Compress + run: | + set -x + for arch in x86_64 aarch64; do + tar -cazf fish-$(git describe)-linux-$arch.tar.xz \ + -C target/$arch-unknown-linux-musl/release fish + done + - uses: actions/upload-artifact@v4 + with: + name: Static builds for Linux + path: fish-${{ github.ref_name }}-linux-*.tar.xz + if-no-files-found: error + + create-draft-release: + needs: + - is-release-tag + - source-tarball + - packages-for-linux + name: Create release draft + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Workaround for https://github.com/actions/checkout/issues/882 + ref: ${{ github.ref }} + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + path: /tmp/artifacts + - name: List artifacts + run: find /tmp/artifacts -type f + - name: Create draft release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: fish ${{ github.ref_name }} + body_path: /tmp/artifacts/release-notes.md + draft: true + files: | + /tmp/artifacts/fish-${{ github.ref_name }}.tar.xz + /tmp/artifacts/fish-${{ github.ref_name }}-linux-*.tar.xz + + packages-for-macos: + needs: [is-release-tag, create-draft-release] + name: Build packages for macOS + runs-on: macos-latest + environment: macos-codesign + steps: + - uses: actions/checkout@v4 + with: + # Workaround for https://github.com/actions/checkout/issues/882 + ref: ${{ github.ref }} + - name: Install Rust + uses: ./.github/actions/rust-toolchain@oldest-supported + with: + targets: x86_64-apple-darwin + - name: Install Rust Stable + uses: ./.github/actions/rust-toolchain@stable + with: + targets: aarch64-apple-darwin + - name: Build and codesign + run: | + die() { echo >&2 "$*"; exit 1; } + [ -n "$MAC_CODESIGN_APP_P12_BASE64" ] || die "Missing MAC_CODESIGN_APP_P12_BASE64" + [ -n "$MAC_CODESIGN_INSTALLER_P12_BASE64" ] || die "Missing MAC_CODESIGN_INSTALLER_P12_BASE64" + [ -n "$MAC_CODESIGN_PASSWORD" ] || die "Missing MAC_CODESIGN_PASSWORD" + [ -n "$MACOS_NOTARIZE_JSON" ] || die "Missing MACOS_NOTARIZE_JSON" + set -x + export FISH_ARTEFACT_PATH=/tmp/fish-built + # macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead + # of crates.io, so give this a try. It's also sometimes significantly faster on all platforms. + export CARGO_NET_GIT_FETCH_WITH_CLI=true + cargo install apple-codesign + mkdir -p "$FISH_ARTEFACT_PATH" + echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode >/tmp/app.p12 + echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode >/tmp/installer.p12 + echo "$MACOS_NOTARIZE_JSON" >/tmp/notarize.json + ./build_tools/make_macos_pkg.sh -s -f /tmp/app.p12 \ + -i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" \ + -n -j /tmp/notarize.json + [ -f "${FISH_ARTEFACT_PATH}/fish-${{ github.ref_name }}.app.zip" ] + [ -f "${FISH_ARTEFACT_PATH}/fish-${{ github.ref_name }}.pkg" ] + rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json + env: + MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }} + MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }} + MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }} + MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }} + - name: Add macOS packages to the release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload $(git describe) \ + /tmp/fish-built/fish-${{ github.ref_name }}.app.zip \ + /tmp/fish-built/fish-${{ github.ref_name }}.pkg diff --git a/.github/workflows/staticbuild.yml b/.github/workflows/staticbuild.yml deleted file mode 100644 index da8db230a..000000000 --- a/.github/workflows/staticbuild.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: staticbuilds - -on: - # release: - # types: [published] - # schedule: - # - cron: "14 13 * * *" - workflow_dispatch: - -env: - CTEST_PARALLEL_LEVEL: "1" - CMAKE_BUILD_PARALLEL_LEVEL: "4" - -jobs: - staticbuilds: - - runs-on: ubuntu-latest - - permissions: - contents: read - - steps: - - uses: dtolnay/rust-toolchain@1.70 - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Prepare - run: | - sudo apt install python3-sphinx - rustup target add x86_64-unknown-linux-musl - rustup target add aarch64-unknown-linux-musl - sudo apt install musl-tools crossbuild-essential-arm64 -y - - name: Build - run: | - CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CMAKE_WITH_GETTEXT=0 CC=aarch64-linux-gnu-gcc RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" cargo build --release --target aarch64-unknown-linux-musl - cargo build --release --target x86_64-unknown-linux-musl - - name: Compress - run: | - tar -cazf fish-amd64.tar.xz -C target/x86_64-unknown-linux-musl/release/ fish{,_indent,_key_reader} - tar -cazf fish-aarch64.tar.xz -C target/aarch64-unknown-linux-musl/release/ fish{,_indent,_key_reader} - - uses: actions/upload-artifact@v4 - with: - name: fish - path: | - fish-amd64.tar.xz - fish-aarch64.tar.xz - retention-days: 14 diff --git a/build_tools/make_macos_pkg.sh b/build_tools/make_macos_pkg.sh new file mode 100755 index 000000000..782e1e848 --- /dev/null +++ b/build_tools/make_macos_pkg.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash + +# Script to produce an OS X installer .pkg and .app(.zip) + +usage() { + echo "Build macOS packages, optionally signing and notarizing them." + echo "Usage: $0 options" + echo "Options:" + echo " -s Enables code signing" + echo " -f Path to .p12 file for application signing" + echo " -i Path to .p12 file for installer signing" + echo " -p Password for the .p12 files (necessary to access the certificates)" + echo " -e (Optional) Path to an entitlements XML file" + echo " -n Enables notarization. This will fail if code signing is not also enabled." + echo " -j Path to JSON file generated with \`rcodesign encode-app-store-connect-api-key\` (required for notarization)" + echo + exit 1 +} + +set -x +set -e + +SIGN= +NOTARIZE= + +ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0' +X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9' + +# As of this writing, the most recent Rust release supports macOS back to 10.12. +# The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64. +# We wish to support back to 10.9 on x86-64; the last version of Rust to support that is +# version 1.73.0. +RUST_VERSION_X86_64=1.70.0 + +while getopts "sf:i:p:e:nj:" opt; do + case $opt in + s) SIGN=1;; + f) P12_APP_FILE=$(realpath "$OPTARG");; + i) P12_INSTALL_FILE=$(realpath "$OPTARG");; + p) P12_PASSWORD="$OPTARG";; + e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");; + n) NOTARIZE=1;; + j) API_KEY_FILE=$(realpath "$OPTARG");; + \?) usage;; + esac +done + +if [ -n "$SIGN" ] && { [ -z "$P12_APP_FILE" ] || [ -z "$P12_INSTALL_FILE" ] || [ -z "$P12_PASSWORD" ]; }; then + usage +fi + +if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then + usage +fi + +VERSION=$(git describe --always --dirty 2>/dev/null) +if test -z "$VERSION" ; then + echo "Could not get version from git" + if test -f version; then + VERSION=$(cat version) + fi +fi + +echo "Version is $VERSION" + +PKGDIR=$(mktemp -d) +echo "$PKGDIR" + +SRC_DIR=$PWD +OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built} + +mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst" + +# Build and install for arm64. +# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish, +# and will probably not be built universal, so the package will fail to validate/run on other systems. +# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app. +{ cd "$PKGDIR/build_arm64" \ + && cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \ + -DWITH_GETTEXT=OFF \ + -DRust_CARGO_TARGET=aarch64-apple-darwin \ + -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ + -DFISH_USE_SYSTEM_PCRE2=OFF \ + "$SRC_DIR" \ + && env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \ + && env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install; +} + +# Build for x86-64 but do not install; instead we will make some fat binaries inside the root. +# Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9. +{ cd "$PKGDIR/build_x86_64" \ + && cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \ + -DWITH_GETTEXT=OFF \ + -DRust_TOOLCHAIN="$RUST_VERSION_X86_64" \ + -DRust_CARGO_TARGET=x86_64-apple-darwin \ + -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ + -DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \ + && env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; } + +# Fatten them up. +for FILE in "$PKGDIR"/root/usr/local/bin/*; do + X86_FILE="$PKGDIR/build_x86_64/$(basename "$FILE")" + rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE" + chmod 755 "$FILE" +done + +if test -n "$SIGN"; then + echo "Signing executables" + ARGS=( + --p12-file "$P12_APP_FILE" + --p12-password "$P12_PASSWORD" + --code-signature-flags runtime + --for-notarization + ) + if [ -n "$ENTITLEMENTS_FILE" ]; then + ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE") + fi + for FILE in "$PKGDIR"/root/usr/local/bin/*; do + (set +x; rcodesign sign "${ARGS[@]}" "$FILE") + done +fi + +pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg" +productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg" + +if test -n "$SIGN"; then + echo "Signing installer" + ARGS=( + --p12-file "$P12_INSTALL_FILE" + --p12-password "$P12_PASSWORD" + --code-signature-flags runtime + --for-notarization + ) + (set +x; rcodesign sign "${ARGS[@]}" "$OUTPUT_PATH/fish-$VERSION.pkg") +fi + +# Make the app +(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp) +(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp) + +# Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake. +cd "$PKGDIR/build_arm64" +for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do + X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")" + rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE" + + # macho-universal-create screws up the permissions. + chmod 755 "$FILE" +done + +if test -n "$SIGN"; then + echo "Signing app" + ARGS=( + --p12-file "$P12_APP_FILE" + --p12-password "$P12_PASSWORD" + --code-signature-flags runtime + --for-notarization + ) + if [ -n "$ENTITLEMENTS_FILE" ]; then + ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE") + fi + (set +x; rcodesign sign "${ARGS[@]}" "fish.app") + +fi + +cp -R "fish.app" "$OUTPUT_PATH/fish-$VERSION.app" +cd "$OUTPUT_PATH" + +# Maybe notarize. +if test -n "$NOTARIZE"; then + echo "Notarizing" + rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.pkg" + rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.app" +fi + +# Zip it up. +zip -r "fish-$VERSION.app.zip" "fish-$VERSION.app" && rm -Rf "fish-$VERSION.app" + +rm -rf "$PKGDIR" diff --git a/build_tools/make_pkg.sh b/build_tools/make_pkg.sh index 6f70b63db..782e1e848 100755 --- a/build_tools/make_pkg.sh +++ b/build_tools/make_pkg.sh @@ -3,18 +3,18 @@ # Script to produce an OS X installer .pkg and .app(.zip) usage() { - echo "Build macOS packages, optionally signing and notarizing them." - echo "Usage: $0 options" - echo "Options:" - echo " -s Enables code signing" - echo " -f Path to .p12 file for application signing" - echo " -i Path to .p12 file for installer signing" - echo " -p Password for the .p12 files (necessary to access the certificates)" - echo " -e (Optional) Path to an entitlements XML file" - echo " -n Enables notarization. This will fail if code signing is not also enabled." - echo " -j Path to JSON file generated with `rcodesign encode-app-store-connect-api-key` (required for notarization)" - echo - exit 1 + echo "Build macOS packages, optionally signing and notarizing them." + echo "Usage: $0 options" + echo "Options:" + echo " -s Enables code signing" + echo " -f Path to .p12 file for application signing" + echo " -i Path to .p12 file for installer signing" + echo " -p Password for the .p12 files (necessary to access the certificates)" + echo " -e (Optional) Path to an entitlements XML file" + echo " -n Enables notarization. This will fail if code signing is not also enabled." + echo " -j Path to JSON file generated with \`rcodesign encode-app-store-connect-api-key\` (required for notarization)" + echo + exit 1 } set -x @@ -30,35 +30,35 @@ X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9' # The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64. # We wish to support back to 10.9 on x86-64; the last version of Rust to support that is # version 1.73.0. -RUST_VERSION_X86_64=1.73.0 +RUST_VERSION_X86_64=1.70.0 while getopts "sf:i:p:e:nj:" opt; do - case $opt in - s) SIGN=1;; - f) P12_APP_FILE=$(realpath "$OPTARG");; - i) P12_INSTALL_FILE=$(realpath "$OPTARG");; - p) P12_PASSWORD="$OPTARG";; - e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");; - n) NOTARIZE=1;; - j) API_KEY_FILE=$(realpath "$OPTARG");; - \?) usage;; - esac + case $opt in + s) SIGN=1;; + f) P12_APP_FILE=$(realpath "$OPTARG");; + i) P12_INSTALL_FILE=$(realpath "$OPTARG");; + p) P12_PASSWORD="$OPTARG";; + e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");; + n) NOTARIZE=1;; + j) API_KEY_FILE=$(realpath "$OPTARG");; + \?) usage;; + esac done -if [ -n "$SIGN" ] && ([ -z "$P12_APP_FILE" ] || [-z "$P12_INSTALL_FILE"] || [ -z "$P12_PASSWORD" ]); then - usage +if [ -n "$SIGN" ] && { [ -z "$P12_APP_FILE" ] || [ -z "$P12_INSTALL_FILE" ] || [ -z "$P12_PASSWORD" ]; }; then + usage fi if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then - usage + usage fi VERSION=$(git describe --always --dirty 2>/dev/null) if test -z "$VERSION" ; then - echo "Could not get version from git" - if test -f version; then - VERSION=$(cat version) - fi + echo "Could not get version from git" + if test -f version; then + VERSION=$(cat version) + fi fi echo "Version is $VERSION" @@ -76,7 +76,7 @@ mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/in # and will probably not be built universal, so the package will fail to validate/run on other systems. # Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app. { cd "$PKGDIR/build_arm64" \ - && cmake \ + && cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \ -DWITH_GETTEXT=OFF \ @@ -91,7 +91,7 @@ mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/in # Build for x86-64 but do not install; instead we will make some fat binaries inside the root. # Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9. { cd "$PKGDIR/build_x86_64" \ - && cmake \ + && cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \ -DWITH_GETTEXT=OFF \ @@ -99,11 +99,11 @@ mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/in -DRust_CARGO_TARGET=x86_64-apple-darwin \ -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ -DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \ - && env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; } + && env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; } # Fatten them up. for FILE in "$PKGDIR"/root/usr/local/bin/*; do - X86_FILE="$PKGDIR/build_x86_64/$(basename $FILE)" + X86_FILE="$PKGDIR/build_x86_64/$(basename "$FILE")" rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE" chmod 755 "$FILE" done @@ -145,7 +145,7 @@ fi # Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake. cd "$PKGDIR/build_arm64" for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do - X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename $FILE)" + X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")" rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE" # macho-universal-create screws up the permissions. diff --git a/build_tools/release.sh b/build_tools/release.sh new file mode 100755 index 000000000..37fed3d55 --- /dev/null +++ b/build_tools/release.sh @@ -0,0 +1,176 @@ +#!/bin/sh + +{ + +set -ex + +version=$1 +repository_owner=fish-shell +remote=origin +if [ -n "$2" ]; then + set -u + repository_owner=$2 + remote=$3 + set +u + [ $# -eq 3 ] +fi + +[ -n "$version" ] + +for tool in \ + bundle \ + gh \ + ruby \ + timeout \ +; do + if ! command -v "$tool" >/dev/null; then + echo >&2 "$0: missing command: $1" + exit 1 + fi +done + +repo_root="$(dirname "$0")/.." +fish_site=$repo_root/../fish-site + +for path in . "$fish_site" +do + if ! git -C "$path" diff HEAD --quiet; then + echo >&2 "$0: index and worktree must be clean" + exit 1 + fi +done + +if git tag | grep -qxF "$version"; then + echo >&2 "$0: tag $version already exists" + exit 1 +fi + +sed -n 1p CHANGELOG.rst | grep -q '^fish .*(released ???)$' +sed -n 2p CHANGELOG.rst | grep -q '^===*$' + +changelog_title="fish $version (released $(date +'%B %d, %Y'))" +sed -i \ + -e "1c$changelog_title" \ + -e "2c$(printf %s "$changelog_title" | sed s/./=/g)" \ + CHANGELOG.rst + +CommitVersion() { + sed -i "s/^version = \".*\"/version = \"$1\"/g" Cargo.toml + cargo fetch --offline + git add CHANGELOG.rst Cargo.toml Cargo.lock + git commit -m "$2 + +Created by ./build_tools/release.sh $version" +} + +CommitVersion "$version" "Release $version" + +# N.B. this is not GPG-signed. +git tag --annotate --message="Release $version" $version + +git push $remote $version + +gh() { + command gh --repo "$repository_owner/fish-shell" "$@" +} + +run_id= +while [ -z "$run_id" ] && sleep 5 +do + run_id=$(gh run list \ + --json=databaseId --jq=.[].databaseId \ + --workflow=release.yml --limit=1 \ + --commit="$(git rev-parse "$version^{commit}")") +done + +# Update fishshell.com +tag_oid=$(git rev-parse "$version") +tmpdir=$(mktemp -d) +while ! \ + gh release download "$version" --dir="$tmpdir" \ + --pattern="fish-$version.tar.xz" +do + timeout 30 gh run watch "$run_id" ||: +done +actual_tag_oid=$(git ls-remote "$remote" | + awk '$2 == "refs/tags/'"$version"'" { print $1 }') +[ "$tag_oid" = "$actual_tag_oid" ] +tar -C "$tmpdir" xf fish-$version.tar.xz +minor_version=${version%.*} +CopyDocs() { + rm -rf "fish-site/site/docs/$1" + cp -r "$tmpdir/fish-$version/user_doc/html" "fish-site/site/docs/$1" + git -C fish-site add "site/docs/$1" +} +CopyDocs "$minor_version" +latest_release=$( + releases=$(git tag | grep '^[0-9]*\.[0-9]*\.[0-9]*.*' | + sed $(: "De-prioritize release candidates (1.2.3-rc0)") \ + 's/-/~/g' | LC_ALL=C sort --version-sort) + printf %s\\n "$releases" | tail -1 +) +if [ "$version" = "$latest_release" ]; then + CopyDocs current +fi +rm -rf "$tmpdir" +( + cd "$fish_site" + make new-release + git add -u + git commit --message="$(printf %s "\ + | Release $version + | + | Created by ../fish-shell/build_tools/release.sh + " | sed 's,^\s*| ,,')" +) + +# N.B. --exit-status doesn't fail reliably. +gh run view "$run_id" --verbose --log-failed --exit-status + +while { + ! draft=$(gh release view "$version" --json=isDraft --jq=.isDraft) \ + || [ "$draft" = true ] +} +do + sleep 20 +done + +( + cd "$fish_site" + git push git@github.com:$repository_owner/fish-site +) + +if git merge-base --is-ancestor $remote/master $version +then + git push $remote $version:master +else + # Probably on an integration branch. + # TODO Maybe push when that's safe (or move this to CI). + : +fi + +if [ "$repository_owner" = fish-shell ]; then { + mail=$(mktemp) + cat >$mail < +Subject: fish $version released + +See https://github.com/fish-shell/fish-shell/releases/tag/$version +EOF + git send-email --suppress-cc=all $mail + rm $mail +} fi + +changelog=$(cat - CHANGELOG.rst <CHANGELOG.rst +CommitVersion ${version}-snapshot "start new cycle" + +exit + +} diff --git a/cmake/MacApp.cmake b/cmake/MacApp.cmake index 9a2b5566c..afc86e95b 100644 --- a/cmake/MacApp.cmake +++ b/cmake/MacApp.cmake @@ -24,7 +24,7 @@ add_executable(fish_macapp EXCLUDE_FROM_ALL # Compute the version. Note this is done at generation time, not build time, # so cmake must be re-run after version changes for the app to be updated. But -# generally this will be run by make_pkg.sh which always re-runs cmake. +# generally this will be run by make_macos_pkg.sh which always re-runs cmake. execute_process( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_tools/git_version_gen.sh --stdout COMMAND cut -d- -f1 @@ -32,7 +32,7 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE) -# Note CMake appends .app, so the real output name will be fish.app. +# Note CMake appends .app, so the real output name will be fish.app. # This target does not include the 'base' resource. set_target_properties(fish_macapp PROPERTIES OUTPUT_NAME "fish") diff --git a/doc_src/conf.py b/doc_src/conf.py index 21fbafd24..52ac617b7 100644 --- a/doc_src/conf.py +++ b/doc_src/conf.py @@ -10,9 +10,19 @@ import glob import os.path import subprocess import sys +from sphinx.highlighting import lexers from sphinx.errors import SphinxWarning from docutils import nodes +try: + import sphinx_markdown_builder + + extensions = [ + "sphinx_markdown_builder", + ] +except ImportError: + pass + # -- Helper functions -------------------------------------------------------- @@ -35,11 +45,14 @@ def issue_role(name, rawtext, text, lineno, inliner, options=None, content=None) return [link], [] +def remove_fish_indent_lexer(app): + if app.builder.name in ("man", "markdown"): + del lexers["fish-docs-samples"] + + # -- Load our extensions ------------------------------------------------- def setup(app): # Our own pygments lexers - from sphinx.highlighting import lexers - this_dir = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, this_dir) from fish_indent_lexer import FishIndentLexer @@ -52,6 +65,8 @@ def setup(app): app.add_config_value("issue_url", default=None, rebuild="html") app.add_role("issue", issue_role) + app.connect("builder-inited", remove_fish_indent_lexer) + # The default language to assume highlight_language = "fish-docs-samples" @@ -59,7 +74,7 @@ highlight_language = "fish-docs-samples" # -- Project information ----------------------------------------------------- project = "fish-shell" -copyright = "2024, fish-shell developers" +copyright = "fish-shell developers" author = "fish-shell developers" issue_url = "https://github.com/fish-shell/fish-shell/issues" @@ -72,7 +87,7 @@ elif "FISH_BUILD_VERSION" in os.environ: ret = os.environ["FISH_BUILD_VERSION"] else: ret = subprocess.check_output( - ("fish_indent", "--version"), stderr=subprocess.STDOUT + ("../build_tools/git_version_gen.sh", "--stdout"), stderr=subprocess.STDOUT ).decode("utf-8") # The full version, including alpha/beta/rc tags