From d9fa7c8404b9d03ae8c6d75da4661d10750ed9c2 Mon Sep 17 00:00:00 2001 From: deborahjalfont <80630578+deborahjalfont@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:43:39 +0300 Subject: [PATCH 1/6] RED-158292 add unstable build packaging of homebrew distribution (#21) --- .github/workflows/build-binary-dists.yml | 160 +++++++++-------------- .github/workflows/test.yml | 105 +++++++++------ scripts/build.sh | 25 ++-- 3 files changed, 139 insertions(+), 151 deletions(-) diff --git a/.github/workflows/build-binary-dists.yml b/.github/workflows/build-binary-dists.yml index 93355ff..aee03dd 100644 --- a/.github/workflows/build-binary-dists.yml +++ b/.github/workflows/build-binary-dists.yml @@ -1,4 +1,4 @@ -name: Build Redis CE MacOS Binary Distributions +name: Build Redis CE MacOS Unstable Package on: push: @@ -7,66 +7,41 @@ on: - '.github/workflows/build-binary-dists.yml' - 'configs/**' - 'scripts/**' - - pull_request: - branches: [ main ] - types: [ labeled ] - paths: - - '.github/workflows/build-binary-dists.yml' - - 'configs/**' - - 'scripts/**' + workflow_call: permissions: id-token: write contents: read jobs: - set_variables: - name: Extract variables from JSON config - if: ${{ (github.event.label.name == 'build-binary-dists') || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} - runs-on: ubuntu-latest - outputs: - redis_version: ${{ steps.read-attribute.outputs.redis_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - id: version - run: | - echo "json<> "$GITHUB_OUTPUT" - cat ./configs/redis_version.json >> "$GITHUB_OUTPUT" - echo >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - - name: Extract redis_version - id: read-attribute - run: echo "redis_version=${{fromJson(steps.version.outputs.json).ref}}" >> "$GITHUB_OUTPUT" - build: - if: ${{ (github.event.label.name == 'build-binary-dists') || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} - needs: [set_variables] - name: Build Redis CE MacOS Binary Distributions + name: Build Redis CE MacOS Unstable Package strategy: fail-fast: false matrix: os_version: # See: https://github.com/actions/runner-images/blob/main/README.md#available-images - macos-13 # macOS 13 x86_64 - macos-13-xlarge # macOS 13 arm64 - + runs-on: ${{ matrix.os_version }} - + steps: - uses: actions/checkout@v4 + with: + # Use unstable branch when called via workflow_call (from nightly scheduler) + # Use current branch when triggered by PR (for testing) + ref: ${{ github.event_name == 'workflow_call' && 'unstable' || github.ref }} - name: Install build dependencies run: | scripts/install_deps.sh - - name: Build Redis CE + - name: Build Redis CE Unstable id: build run: | - scripts/build.sh ${{ needs.set_variables.outputs.redis_version }} - echo "UNSIGNED_REDIS_BINARY=unsigned-redis-ce-${{ needs.set_variables.outputs.redis_version }}-$(uname -m).zip" >> $GITHUB_OUTPUT + # Use unstable branch instead of tagged version + scripts/build.sh + echo "UNSIGNED_REDIS_BINARY=unsigned-redis-ce-unstable-$(uname -m).zip" >> $GITHUB_OUTPUT - name: Upload Redis CE Binary Distribution uses: actions/upload-artifact@v4 @@ -74,68 +49,57 @@ jobs: path: ./${{ steps.build.outputs.UNSIGNED_REDIS_BINARY }} name: ${{ steps.build.outputs.UNSIGNED_REDIS_BINARY }} - - name: Setup Keychain and Certificate - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - # Decode and save certificate - echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 - - # Create and configure keychain - security create-keychain -p "${{ secrets.MACOS_KEYCHAIN_PASSWORD }}" build.keychain - security unlock-keychain -p "${{ secrets.MACOS_KEYCHAIN_PASSWORD }}" build.keychain - security set-keychain-settings -t 3600 -l build.keychain - - # Add to search list and set as default - security list-keychains -d user -s build.keychain login.keychain - security default-keychain -s build.keychain - - # Import and trust certificate - security import certificate.p12 -k build.keychain -P "${{ secrets.MACOS_CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.MACOS_KEYCHAIN_PASSWORD }}" build.keychain - - # Debug certificate presence - security find-identity -v -p codesigning build.keychain - - - name: Sign Binaries - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - id: sign + - name: Capture build logs on failure + if: failure() run: | - # Get identity from specific keychain - CODESIGN_IDENTITY=$(security find-identity -v -p codesigning build.keychain | grep -o '[0-9A-F]\{40\}' | head -n 1) - echo "Using identity: ${CODESIGN_IDENTITY}" - - # Check if entitlements file exists - if [ ! -f configs/entitlements.xml ]; then - echo "Entitlements file not found!" - exit 1 + mkdir -p /tmp/build-logs + + echo "Build failed for homebrew on ${{ matrix.os_version }}" + echo "Capturing detailed logs for troubleshooting..." + + # Get system info + uname -a > /tmp/build-logs/system-info.log 2>&1 + brew --version > /tmp/build-logs/brew-info.log 2>&1 + + # Get build directory contents if it exists + if [ -d "build_dir" ]; then + find build_dir -type f > /tmp/build-logs/build-dir-contents.log 2>&1 || echo "Failed to list build directory" fi - - # Sign binaries with explicit keychain - for i in $(ls build_dir/bin); do - /usr/bin/codesign --keychain build.keychain --options=runtime --timestamp -v --sign "${CODESIGN_IDENTITY}" --entitlements configs/entitlements.xml -f build_dir/bin/$i - done - - # Sign libraries with explicit keychain - for i in $(ls build_dir/lib/redis/modules); do - /usr/bin/codesign --keychain build.keychain --options=runtime --timestamp -v --sign "${CODESIGN_IDENTITY}" --entitlements configs/entitlements.xml -f build_dir/lib/redis/modules/$i - done - - # Create distribution archive - (cd build_dir && zip -r ../redis-ce-${{ needs.set_variables.outputs.redis_version }}-$(uname -m).zip .) - echo "REDIS_BINARY=redis-ce-${{ needs.set_variables.outputs.redis_version }}-$(uname -m).zip" >> $GITHUB_OUTPUT - - - name: Notarize Redis CE Binary Distribution - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - sh scripts/notarize.sh ${{ steps.sign.outputs.REDIS_BINARY }} com.redis.redis ${{ secrets.MAC_NOTARIZE_USERNAME }} ${{ secrets.MAC_NOTARIZE_PASSWORD }} ${{ secrets.MAC_NOTARIZE_TEAM_ID }} - - uses: aws-actions/configure-aws-credentials@v4 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + # Get Redis build logs if they exist + if [ -f "redis-unstable/src/Makefile" ]; then + make -C redis-unstable -n > /tmp/build-logs/makefile-dry-run.log 2>&1 || echo "Failed to get makefile dry run" + fi + + # Create a summary file + { + echo "Build failure summary for homebrew on ${{ matrix.os_version }}" + echo "Date: $(date)" + echo "GitHub SHA: ${{ github.sha }}" + echo "OS Version: ${{ matrix.os_version }}" + echo "Distribution: homebrew" + } > /tmp/build-logs/failure-summary.txt + + echo "Log capture complete" + + - name: Upload build failure logs + if: failure() + uses: actions/upload-artifact@v4 with: - aws-region: ${{ secrets.S3_REGION }} - role-to-assume: ${{ secrets.S3_IAM_ARN }} + name: build-failure-${{ matrix.os_version }}-homebrew + path: /tmp/build-logs/ + if-no-files-found: warn - - name: Upload Redis CE Binary Distribution to S3 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - aws s3 cp ${{ steps.sign.outputs.REDIS_BINARY }} s3://${{ secrets.S3_BUCKET }}/homebrew/ --acl public-read + test: + name: Test Redis CE Unstable Package + needs: build + strategy: + fail-fast: false + matrix: + os_version: + - macos-13 # macOS 13 x86_64 + - macos-13-xlarge # macOS 13 arm64 + uses: ./.github/workflows/test.yml + with: + artifact_name: unsigned-redis-ce-unstable-${{ matrix.os_version == 'macos-13' && 'x86_64' || 'arm64' }}.zip + runner: ${{ matrix.os_version }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c107370..20b7442 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,59 +1,79 @@ -name: Test Redis CE +name: Test Redis Unstable CE Package on: - pull_request: - types: [ labeled ] - branches: [ main ] - paths: - - '.github/workflows/test.yml' - - 'Casks/**' - - 'configs/**' - - '!configs/redis_version.json' + workflow_call: + inputs: + artifact_name: + description: 'Name of the Redis artifact to download for test' + required: true + type: string + runner: + description: 'OS version to run tests on' + required: true + type: string jobs: test: - if: github.event.label.name == 'run-tests' name: Test Redis CE - strategy: - fail-fast: false - matrix: - os_version: # See: https://github.com/actions/runner-images/blob/main/README.md#available-images - - macos-15-large # macOS 15 x86_64 - - macos-15 # macOS 15 arm64 - - macos-14-large # macOS 14 x86_64 - - macos-14 # macOS 14 arm64 - - macos-13 # macOS 13 x86_64 - - macos-13-xlarge # macOS 13 arm64 - cask: - - redis - - redis-rc - - runs-on: ${{ matrix.os_version }} - + runs-on: ${{ inputs.runner }} steps: - uses: actions/checkout@v4 + with: + # Use unstable branch when called via workflow_call (from nightly scheduler) + # Use current branch when triggered by PR (for testing) + ref: ${{ github.event_name == 'workflow_call' && 'unstable' || github.ref }} - - name: Set up Homebrew + - name: Download built package + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.artifact_name }} + + - name: Install runtime dependencies run: | - export HOMEBREW_GITHUB_API_TOKEN=$GITHUB_TOKEN - brew update - brew tap redis/redis . + # Extract runtime dependencies from cask file + DEPS=$(grep 'depends_on formula:' Casks/redis.rb | sed 's/.*depends_on formula: "\([^"]*\)".*/\1/' | tr '\n' ' ') + echo "Installing runtime dependencies from cask file: $DEPS" + brew install $DEPS - - name: Install Redis CE + - name: Extract and setup Redis run: | - brew install --cask ${{ matrix.cask }} --debug --verbose - ls -al $(brew --prefix)/etc/redis.conf - ls -al $(brew --prefix)/lib/redis/modules - ls -al $(brew --prefix)/bin/redis* + unzip unsigned-redis-ce-unstable-*.zip + echo "REDIS_HOME=$(pwd)" >> $GITHUB_ENV + echo "$(pwd)/bin" >> $GITHUB_PATH + chmod +x bin/redis-* - name: Test Redis Installation run: | redis-server --version - redis-server $(brew --prefix)/etc/redis.conf - for i in {1..30}; do redis-cli ping && break || echo "Waiting for Redis... $i" && sleep 1; done - redis-cli info server || { echo "Cannot get server info"; exit 1; } + + # Load modules manually since we're using a custom build without pre-configured redis.conf + # (unlike the official cask which has modules pre-configured in the config file) + redis-server --port 6379 --daemonize yes --logfile redis-server.log \ + --loadmodule "$REDIS_HOME/lib/redis/modules/redisbloom.so" \ + --loadmodule "$REDIS_HOME/lib/redis/modules/redisearch.so" \ + --loadmodule "$REDIS_HOME/lib/redis/modules/redistimeseries.so" \ + --loadmodule "$REDIS_HOME/lib/redis/modules/rejson.so" + + # Wait for Redis to start (same pattern as public repo) + for i in {1..30}; do + redis-cli ping && break || echo "Waiting for Redis... $i" && sleep 1 + done + + # Verify Redis is running and get info (same as public repo) + redis-cli info server || { echo "Cannot get server info"; cat redis-server.log; exit 1; } redis-cli module list + # Save logs for debugging + mkdir -p /tmp/redis-logs + cp redis-server.log /tmp/redis-logs/ 2>/dev/null || echo "No Redis logs to save" + + - name: Upload Redis logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: redis-logs-${{ inputs.runner }} + path: /tmp/redis-logs/ + - name: Verify Installed Modules run: | modules=$(redis-cli module list) @@ -81,6 +101,7 @@ jobs: [ "$(redis-cli BF.EXISTS popular_keys "redis:list")" = "0" ] || \ { echo "RedisBloom test failed: 'redis:list' found unexpectedly"; exit 1; } echo "RedisBloom test passed successfully" + - name: Test RediSearch run: | redis-cli FT.CREATE redis_commands ON HASH PREFIX 1 cmd: SCHEMA name TEXT SORTABLE description TEXT @@ -94,6 +115,7 @@ jobs: echo "RediSearch test failed: expected commands not found in search results" exit 1 fi + - name: Test RedisTimeSeries run: | redis-cli TS.CREATE redis:cpu:usage RETENTION 86400 @@ -109,6 +131,7 @@ jobs: echo "RedisTimeSeries test failed: expected values not found in time series" exit 1 fi + - name: Test ReJSON run: | redis-cli JSON.SET redis:config $ '{"maxmemory":"2gb","maxmemory-policy":"allkeys-lru"}' @@ -121,7 +144,7 @@ jobs: exit 1 fi - - name: Test uninstall + - name: Cleanup + if: always() run: | - brew uninstall ${{ matrix.cask }} - brew untap redis/redis + redis-cli shutdown || true diff --git a/scripts/build.sh b/scripts/build.sh index 568f032..a74c584 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,25 +2,26 @@ export HOMEBREW_PREFIX="$(brew --prefix)" export BUILD_WITH_MODULES=yes +export MODULE_VERSION=master export BUILD_TLS=yes export DISABLE_WERRORS=yes PATH="$HOMEBREW_PREFIX/opt/libtool/libexec/gnubin:$HOMEBREW_PREFIX/opt/llvm@18/bin:$HOMEBREW_PREFIX/opt/make/libexec/gnubin:$HOMEBREW_PREFIX/opt/gnu-sed/libexec/gnubin:$HOMEBREW_PREFIX/opt/coreutils/libexec/gnubin:$PATH" # Override macOS defaults. export LDFLAGS="-L$HOMEBREW_PREFIX/opt/llvm@18/lib" export CPPFLAGS="-I$HOMEBREW_PREFIX/opt/llvm@18/include" -# Check if Redis version is provided as an argument -if [ $# -lt 1 ]; then - echo "Usage: $0 " - exit 1 -fi +curl -L "https://github.com/redis/redis/archive/refs/heads/unstable.tar.gz" -o redis-unstable.tar.gz +tar xzf redis-unstable.tar.gz -REDIS_VERSION="$1" - -curl -L "https://github.com/redis/redis/archive/refs/tags/$REDIS_VERSION.tar.gz" -o redis.tar.gz -tar xzf redis.tar.gz +# Update module versions to use master branch +for module in redisbloom redisearch redistimeseries redisjson; do + if [ -f "redis-unstable/modules/${module}/Makefile" ]; then + sed -i 's/MODULE_VERSION = .*/MODULE_VERSION = master/' "redis-unstable/modules/${module}/Makefile" + echo "Updated MODULE_VERSION to master for ${module}" + fi +done mkdir -p build_dir/etc -make -C redis-$REDIS_VERSION -j "$(nproc)" all OS=macos -make -C redis-$REDIS_VERSION install PREFIX=$(pwd)/build_dir OS=macos +make -C redis-unstable -j "$(nproc)" all OS=macos +make -C redis-unstable install PREFIX=$(pwd)/build_dir OS=macos cp ./configs/redis.conf build_dir/etc/redis.conf -(cd build_dir && zip -r ../redis-ce-$REDIS_VERSION-$(uname -m).zip .) +(cd build_dir && zip -r ../unsigned-redis-ce-unstable-$(uname -m).zip .) From 2a74c9733b277787906825f842f353b941ea8ca9 Mon Sep 17 00:00:00 2001 From: deborahjalfont <80630578+deborahjalfont@users.noreply.github.com> Date: Wed, 9 Jul 2025 08:52:43 +0300 Subject: [PATCH 2/6] fix checkout from unstable as the github event name is schedule during nightly and not workflow_call (#17) Co-authored-by: Deborah Jalfon --- .github/workflows/build-binary-dists.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-binary-dists.yml b/.github/workflows/build-binary-dists.yml index aee03dd..7eb2997 100644 --- a/.github/workflows/build-binary-dists.yml +++ b/.github/workflows/build-binary-dists.yml @@ -30,7 +30,7 @@ jobs: with: # Use unstable branch when called via workflow_call (from nightly scheduler) # Use current branch when triggered by PR (for testing) - ref: ${{ github.event_name == 'workflow_call' && 'unstable' || github.ref }} + ref: ${{ github.event_name == 'push' && github.ref || 'unstable' }} - name: Install build dependencies run: | From e1f6ae9d8095bae886ad03acc077f54583930b20 Mon Sep 17 00:00:00 2001 From: Alexander Dobrzhansky Date: Mon, 28 Jul 2025 13:02:09 +0200 Subject: [PATCH 3/6] Update README.md --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd61646..0e53d2a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## Redis Community Edition - Install using Homebrew Cask +## Redis Open Source - Install using Homebrew Cask -To install the latest version of Redis Community Edition using Homebrew Cask, please use the following command: +To install the latest version of Redis Open Source using Homebrew Cask, please use the following command: ```bash brew tap redis/redis @@ -14,6 +14,10 @@ brew tap redis/redis brew install --cask redis-rc ``` +#### Note: Configuration File Conflicts +If you previously installed Redis using the standard Homebrew formula `brew install redis` and later removed it, the configuration file may still remain at `$(brew --prefix)/etc/redis.conf`. When installing Redis via the cask method `brew install --cask redis`, this existing configuration file will not be automatically replaced. +To avoid potential conflicts or unexpected behavior, ensure you remove any leftover configuration files from previous Redis installations before installing the cask version + ## Supported Operating Systems Redis officially tests the latest version of this distribution against the following OSes: @@ -30,6 +34,14 @@ After installation, you can start Redis in the background using the following co redis-server $(brew --prefix)/etc/redis.conf ``` + + +To stop the service: + +```bash +redis-cli shutdown +``` + To stop the service: ```bash From 99fd71c73c6f743ebb896b88649c3c4b69a8838b Mon Sep 17 00:00:00 2001 From: Mike Golant Date: Mon, 28 Jul 2025 17:48:28 +0300 Subject: [PATCH 4/6] Use cask instalation for unstable (#19) --- .github/workflows/test.yml | 43 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20b7442..378bb94 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,31 +35,34 @@ jobs: echo "Installing runtime dependencies from cask file: $DEPS" brew install $DEPS - - name: Extract and setup Redis + - name: Setup local cask for testing run: | - unzip unsigned-redis-ce-unstable-*.zip - echo "REDIS_HOME=$(pwd)" >> $GITHUB_ENV - echo "$(pwd)/bin" >> $GITHUB_PATH - chmod +x bin/redis-* + # Create temporary cask file that points to local artifact + ARTIFACT_FILE=$(ls unsigned-redis-ce-unstable-*.zip) + ARTIFACT_PATH="file://$(pwd)/$ARTIFACT_FILE" + + # Modify existing cask to point to local artifact + sed -i "" "s|https://packages.redis.io/homebrew/redis-ce-.*\.zip|$ARTIFACT_PATH|g" Casks/redis.rb + + # Remove sha256 validation since we're using local file + sed -i "" '/sha256 arm:/d' Casks/redis.rb + sed -i "" '/intel:/d' Casks/redis.rb + + # Add current directory as tap + brew tap redis/redis-unstable . + + - name: Install Redis CE via cask + run: | + brew install --cask redis/redis-unstable/redis --debug --verbose + ls -al $(brew --prefix)/etc/redis.conf + ls -al $(brew --prefix)/lib/redis/modules + ls -al $(brew --prefix)/bin/redis* - name: Test Redis Installation run: | redis-server --version - - # Load modules manually since we're using a custom build without pre-configured redis.conf - # (unlike the official cask which has modules pre-configured in the config file) - redis-server --port 6379 --daemonize yes --logfile redis-server.log \ - --loadmodule "$REDIS_HOME/lib/redis/modules/redisbloom.so" \ - --loadmodule "$REDIS_HOME/lib/redis/modules/redisearch.so" \ - --loadmodule "$REDIS_HOME/lib/redis/modules/redistimeseries.so" \ - --loadmodule "$REDIS_HOME/lib/redis/modules/rejson.so" - - # Wait for Redis to start (same pattern as public repo) - for i in {1..30}; do - redis-cli ping && break || echo "Waiting for Redis... $i" && sleep 1 - done - - # Verify Redis is running and get info (same as public repo) + redis-server $(brew --prefix)/etc/redis.conf --logfile redis-server.log & + for i in {1..30}; do redis-cli ping && break || echo "Waiting for Redis... $i" && sleep 1; done redis-cli info server || { echo "Cannot get server info"; cat redis-server.log; exit 1; } redis-cli module list From 98ba6e0dfd19995d96bfb374875a6486111552ce Mon Sep 17 00:00:00 2001 From: deborahjalfont <80630578+deborahjalfont@users.noreply.github.com> Date: Tue, 29 Jul 2025 12:56:23 +0300 Subject: [PATCH 5/6] add set -e to scripts in order to fail whenever any command fails (#20) Co-authored-by: Deborah Jalfon --- scripts/build.sh | 2 ++ scripts/install_deps.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/scripts/build.sh b/scripts/build.sh index a74c584..fd60421 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,7 @@ #!/bin/sh +set -e + export HOMEBREW_PREFIX="$(brew --prefix)" export BUILD_WITH_MODULES=yes export MODULE_VERSION=master diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index 8cf6659..9a22732 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -1,5 +1,7 @@ #!/bin/sh +set -e + export HOMEBREW_NO_AUTO_UPDATE=1 brew update brew install coreutils From 9ebfd6b1c80b4a567d621362d93795fc97abc2d0 Mon Sep 17 00:00:00 2001 From: hilabarkai <87666787+hilabarkai@users.noreply.github.com> Date: Wed, 30 Jul 2025 14:24:55 +0300 Subject: [PATCH 6/6] Fix link issue (#21) Co-authored-by: hila.barkai --- scripts/install_deps.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index 9a22732..199b208 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -12,7 +12,14 @@ brew install gnu-sed brew install automake brew install libtool +# Ensure Homebrew's cmake does not interfere +brew uninstall --ignore-dependencies cmake || true + +# Clean up any stale CMake symlinks rm -f /usr/local/bin/cmake +rm -f /usr/local/bin/ctest +rm -f /usr/local/bin/cpack + CMAKE_VERSION=3.31.6 mkdir ~/Downloads/CMake curl --location --retry 3 "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-macos-universal.dmg" --output ~/Downloads/CMake/cmake-macos.dmg