mirror of
https://github.com/redis/redis.git
synced 2026-07-11 11:05:39 -04:00
Some checks are pending
CI / test-ubuntu-latest (push) Waiting to run
CI / test-sanitizer-address (push) Waiting to run
CI / build-debian-old (push) Waiting to run
CI / build-macos-latest (push) Waiting to run
CI / build-32bit (push) Waiting to run
CI / build-libc-malloc (push) Waiting to run
CI / build-centos-jemalloc (push) Waiting to run
CI / build-old-chain-jemalloc (push) Waiting to run
Codecov / code-coverage (push) Waiting to run
External Server Tests / test-external-standalone (push) Waiting to run
External Server Tests / test-external-cluster (push) Waiting to run
External Server Tests / test-external-nodebug (push) Waiting to run
Spellcheck / Spellcheck (push) Waiting to run
## Summary Redis core and the external modules (Search, JSON, Bloom, TimeSeries) are currently built and released through separate flows, forcing anyone assembling a full distribution to juggle multiple repos, refs, build commands, and config files. This PR collapses that into one Redis-owned workflow: ```sh make modules-update # clone/refresh modules from modules/modules.yaml make bootstrap # install per-module build/test deps make build # build Redis core + selected modules make run # start redis-server with modules loaded make test all # run module test suites make tarball TAG=... # build a reproducible source bundle ``` ## What This Adds **1. Manifest-driven modules** — `modules/modules.yaml` is the single source of truth for bundled modules. Each entry pins `repo`/`ref` and defines its build artifact and runtime `loadmodule` path. Refs resolve dynamically (tag → branch → SHA, else fail). Current pins: RedisBloom `v8.9.81`, RediSearch `v8.9.82`, RedisJSON `v8.9.81`, RedisTimeSeries `v8.9.82`. **2. Central manifest parser** — `scripts/lib/manifest.sh` is the only YAML reader, usable both as a shell library and a CLI helper (via `modules/manifest.mk`). **3. Per-module stub Makefiles removed** — The `modules/redis*/Makefile` stubs are deleted; their data moves to `modules.yaml` and shared behavior to `modules/common.mk`. ## Make Workflow The root `Makefile` is now a thin dispatch layer over scripts in `scripts/`: | Target | Script | Purpose | |---|---|---| | `make build [args]` | `scripts/build.sh` | Build Redis core plus selected modules | | `make bootstrap [args]` | `scripts/bootstrap.sh` | Install per-module build/test prerequisites | | `make setup [args]` | `scripts/setup.sh` | Run module update plus bootstrap | | `make run [args]` | `scripts/run.sh` | Start Redis with selected modules loaded | | `make test [args]` | `scripts/test.sh` | Run Redis or module tests | | `make clean [args]` | `scripts/clean.sh` | Clean Redis and/or module outputs | | `make deploy [args]` | `scripts/deploy.sh` | Install Redis and module artifacts | | `make modules-update [args]` | `scripts/modules-update.sh` | Clone/refresh module sources from the manifest | | `make modules-shallow [args]` | `scripts/modules-shallow.sh` | Re-clone selected modules with shallow history | | `make sync-redis-conf [args]` | `scripts/sync-redis-conf.sh` | Regenerate managed module config | | `make tarball TAG=...` | `scripts/tarball.sh` | Create a reproducible Redis + modules source tarball | All accept module selectors: ```sh make build all # core + all modules make build redisjson # core + one module make run none # core only, no modules make test redisearch TEST='some:test:name' ``` ## Runtime Configuration Removes the hand-maintained `redis-full.conf` (which could drift from upstream). Config is now generated: `sync-redis-conf.sh` produces a managed Modules block appended to verbatim `redis.conf`, with `loadmodule` lines (active when built or `ASSUME_BUILT=1`) plus each module's `module.conf`. The generated file is git-ignored. ## Docker & Release - **`docker/Dockerfile.noble`** — Ubuntu 24.04 build env for core + modules (amd64/arm64). - **`scripts/tarball.sh`** — reproducible source bundle: archives core at `TAG`, clones modules at pinned refs, strips `.git`/build artifacts, generates config, and produces a deterministic gzip. `utils/releasetools/01_create_tarball.sh` now delegates to it. - **`post-release-automation.yml`** — builds the bundle on published releases, uploads it as artifact + release asset, and reports SHA256. ## Docs `modules/MODULES.md` (operator guide), `modules/README.md`, and `README.md` cover the manifest schema, Make targets, tarball flow, Docker env, and troubleshooting. ## Compatibility Notes - `BUILD_WITH_MODULES=yes` is replaced by `make build [redis|core|none|all|<module>...]`. - `redis-full.conf` is now generated and git-ignored. - Module clones live under `modules/<name>/src/` (git-ignored). - `vector-sets` is omitted — it already lives in-tree. - RediSearch builds with `LTO=1 REDISEARCH_GENERATE_HEADERS=0 INLINE_LSE_ATOMICS=0`. --------- Co-authored-by: debing.sun <debing.sun@redis.com>
166 lines
6.3 KiB
Bash
Executable file
166 lines
6.3 KiB
Bash
Executable file
#!/bin/sh
|
|
# modules-update.sh — clone or refresh modules per modules.yaml.
|
|
#
|
|
# Usage: scripts/modules-update.sh [<name> ...|all|.|'*']
|
|
# (no args = all modules in modules.yaml)
|
|
#
|
|
# Env: MODULES_UPDATE_SHALLOW=1 clone with --depth 1
|
|
# MAKE make binary (defaults to `make`)
|
|
|
|
set -eu
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)" || exit 1
|
|
. "$SCRIPT_DIR/lib/manifest.sh"
|
|
cd "$REPO_ROOT"
|
|
|
|
MAKE_BIN="${MAKE:-make}"
|
|
|
|
available="$(manifest_modules | manifest_join_words)"
|
|
requested="$*"
|
|
if [ -z "$requested" ]; then
|
|
echo "==> No module specified — defaulting to all ($available)"
|
|
requested="$available"
|
|
fi
|
|
for r in $requested; do
|
|
case "$r" in all|.|'*') requested="$available"; break ;; esac
|
|
done
|
|
|
|
# `none` — clone/refresh nothing; just regenerate redis-full.conf with no
|
|
# modules, reverting the loadmodule lines / emptying the Modules section (same
|
|
# contract as `make sync-redis-conf none`).
|
|
for r in $requested; do
|
|
case "$r" in none)
|
|
echo "==> 'none' requested — skipping clone; reverting redis-full.conf module section"
|
|
"$MAKE_BIN" --no-print-directory sync-redis-conf MODULES=none
|
|
exit 0 ;;
|
|
esac
|
|
done
|
|
|
|
depth_args=""
|
|
if [ "${MODULES_UPDATE_SHALLOW:-}" = "1" ]; then
|
|
echo "==> MODULES_UPDATE_SHALLOW=1: cloning with --depth 1"
|
|
depth_args="--depth 1"
|
|
fi
|
|
|
|
for name in $requested; do
|
|
case " $available " in *" $name "*) ;; *)
|
|
echo "ERROR: unknown module '$name' (not listed in modules.yaml)"
|
|
echo "Available modules: $available"
|
|
exit 1 ;;
|
|
esac
|
|
|
|
repo="$(manifest_field "$name" repo)"
|
|
ref="$(manifest_ref "$name")"
|
|
kind="$(manifest_ref_kind "$name")"
|
|
dest="modules/$name/src"
|
|
|
|
if [ -z "$repo" ]; then
|
|
echo "ERROR: 'repo' is not set for '$name' in modules.yaml"; exit 1
|
|
fi
|
|
if [ -z "$ref" ]; then
|
|
echo "ERROR: '$name' must set a 'ref' in modules.yaml"; exit 1
|
|
fi
|
|
if [ -z "$kind" ]; then
|
|
echo "ERROR: ref '$ref' for '$name' is neither a tag nor a branch on $repo, and is not a hex commit SHA"; exit 1
|
|
fi
|
|
|
|
if [ ! -d "$dest/.git" ]; then
|
|
rm -rf "$dest"
|
|
case "$kind" in
|
|
tag|branch)
|
|
echo "==> Cloning $name @ $kind $ref from $repo into $dest"
|
|
git clone --recursive $depth_args --branch "$ref" "$repo" "$dest"
|
|
;;
|
|
commit)
|
|
echo "==> Cloning $name @ commit $ref from $repo into $dest"
|
|
git init -q "$dest"
|
|
git -C "$dest" remote add origin "$repo"
|
|
if [ -n "$depth_args" ]; then
|
|
git -C "$dest" fetch $depth_args origin "$ref" 2>/dev/null \
|
|
|| { echo " (shallow SHA fetch not supported by server, doing full fetch)"; \
|
|
git -C "$dest" fetch origin; }
|
|
else
|
|
git -C "$dest" fetch origin
|
|
fi
|
|
git -C "$dest" checkout -q --detach "$ref"
|
|
git -C "$dest" submodule update --init --recursive $depth_args
|
|
;;
|
|
esac
|
|
else
|
|
case "$kind" in
|
|
commit)
|
|
current="$(git -C "$dest" rev-parse HEAD)" || {
|
|
echo "ERROR: git rev-parse HEAD failed in $dest" >&2
|
|
exit 1
|
|
}
|
|
if [ -z "$current" ]; then
|
|
echo "ERROR: empty HEAD in $dest" >&2
|
|
exit 1
|
|
fi
|
|
if [ "$current" = "$ref" ] || [ "${current#$ref}" != "$current" ]; then
|
|
echo "==> $name already at commit $ref"
|
|
else
|
|
echo "==> Moving $name to commit $ref"
|
|
if [ -n "$depth_args" ]; then
|
|
git -C "$dest" fetch $depth_args origin "$ref" 2>/dev/null \
|
|
|| { echo " (shallow SHA fetch not supported by server, doing full fetch)"; \
|
|
git -C "$dest" fetch origin; }
|
|
else
|
|
git -C "$dest" fetch origin "$ref" 2>/dev/null \
|
|
|| git -C "$dest" fetch origin
|
|
fi
|
|
git -C "$dest" checkout -f --detach "$ref"
|
|
fi
|
|
;;
|
|
tag|branch)
|
|
echo "==> Ensuring $name is at $kind $ref"
|
|
git -C "$dest" fetch $depth_args origin "$ref" 2>/dev/null \
|
|
|| git -C "$dest" fetch $depth_args origin "refs/tags/$ref:refs/tags/$ref" 2>/dev/null \
|
|
|| git -C "$dest" fetch origin
|
|
current="$(git -C "$dest" rev-parse HEAD)" || {
|
|
echo "ERROR: git rev-parse HEAD failed in $dest" >&2
|
|
exit 1
|
|
}
|
|
# Peel to '^{commit}' so this compares correctly for annotated tags
|
|
# too — FETCH_HEAD for an annotated tag is the tag *object* SHA, not
|
|
# the commit SHA that HEAD (after a normal checkout) actually is;
|
|
# comparing the raw SHAs would never match and the fast path below
|
|
# would silently never trigger for that ref kind.
|
|
target="$(git -C "$dest" rev-parse -q --verify 'FETCH_HEAD^{commit}' 2>/dev/null || true)"
|
|
if [ -n "$target" ] && [ "$current" = "$target" ]; then
|
|
echo "==> $name already at $kind $ref"
|
|
else
|
|
echo "==> Moving $name to $kind $ref"
|
|
# Check out the resolved commit SHA, not "$ref" by name — a plain
|
|
# `git fetch` never updates dest's own local tag/branch ref, so
|
|
# checking out "$ref" here would silently re-select a STALE local
|
|
# ref if one already exists under that name (e.g. a branch's old
|
|
# tip, or a tag force-moved upstream to a new commit) instead of
|
|
# the just-fetched target.
|
|
git -C "$dest" checkout -f "$target" 2>/dev/null \
|
|
|| git -C "$dest" reset --hard FETCH_HEAD
|
|
fi
|
|
;;
|
|
esac
|
|
echo "==> Re-syncing submodules for $name"
|
|
git -C "$dest" submodule sync --recursive
|
|
git -C "$dest" submodule update --init --recursive $depth_args
|
|
fi
|
|
touch "$dest/.prepared"
|
|
done
|
|
|
|
echo
|
|
echo "==> Modules updated: $requested"
|
|
echo " Next: run 'make bootstrap [<name> ...]' to install per-module build/test deps."
|
|
|
|
echo "==> Refreshing redis-full.conf via sync-redis-conf"
|
|
# Sync exactly the requested modules — a `make modules-update redistimeseries`
|
|
# refreshes that module's loadmodule line/block in redis-full.conf. Each
|
|
# module's active/missing state is independently derived from .so presence on
|
|
# disk unless ASSUME_BUILT is set.
|
|
#
|
|
# ASSUME_BUILT=1: emit an active `loadmodule` line for each requested module
|
|
# even though this script only clones source and never builds — so a
|
|
# `make modules-update redistimeseries` leaves redis-full.conf ready to load
|
|
# the module once it's built, instead of a commented "not built" placeholder.
|
|
"$MAKE_BIN" --no-print-directory sync-redis-conf MODULES="$requested" ASSUME_BUILT=1
|