Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 47 additions & 11 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,23 +163,59 @@ For details on the Doxygen configuration and CI pipeline, see the

### Bump the pinned Rust submodule

Update to the commit from the Rust SDK release with the newest publication
time (including prereleases, excluding drafts):

```bash
./scripts/update-rust-sdk.sh
```

The script requires an authenticated GitHub CLI (`gh auth login`, or `GH_TOKEN`)
when `--hash` is omitted. To select a specific commit without `gh`, pass its full
or abbreviated hash:

```bash
cd client-sdk-cpp
git fetch origin
git switch -c try-rust-main origin/main
./scripts/update-rust-sdk.sh --hash 1a477bc
```

# Sync submodule URLs and check out what origin/main pins (recursively):
git submodule sync --recursive
git submodule update --init --recursive --checkout
The script checks out the selected Rust commit and synchronizes its nested
submodules. It leaves the parent index untouched; review and stage the gitlink
when ready. `--hash` also permits unreleased commits for local development; CI
requires a published release for the pinned Rust commit.

# If the nested submodule under yuv-sys didn't materialize, force it:
git -C client-sdk-rust/yuv-sys submodule sync --recursive
git -C client-sdk-rust/yuv-sys submodule update --init --recursive --checkout
Review the selected commits before committing the gitlink update:

# Sanity check:
git submodule status --recursive
```bash
git diff --submodule=log -- client-sdk-rust
git add -- client-sdk-rust

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL git add -- <submodule> is proper

```

### Bump the pinned C++ example collection

Update to the most recent commit on the `main` branch of the examples
repository:

```bash
./scripts/update-cpp-example-collection.sh
```

To select a specific commit, pass its full or abbreviated hash:

```bash
./scripts/update-cpp-example-collection.sh --hash 7e76bea
```

Review and stage the examples gitlink when ready:

```bash
git diff --submodule=log -- cpp-example-collection
git add -- cpp-example-collection
```

Both updaters run from any working directory, initialize the selected submodule
if necessary, detach its checkout at the selected commit, and synchronize nested
submodules using checkout mode.

### If `yuv-sys` fails to build

```bash
Expand Down
88 changes: 88 additions & 0 deletions scripts/update-cpp-example-collection.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
#
# Copyright 2026 LiveKit
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
repo_root="$(cd "${script_dir}/.." && pwd -P)"
examples_repo="livekit-examples/cpp-example-collection"
examples_remote="https://github.com/${examples_repo}.git"
default_branch="main"

usage() {
cat <<'EOF'
Usage: ./scripts/update-cpp-example-collection.sh [--hash HASH]

Update the cpp-example-collection submodule used by the C++ SDK.

Options:
--hash HASH
Use the specified examples commit. You can use a short or full SHA-1
hash.
-h, --help
Show this help and exit.

When --hash is omitted, the script uses the most recent commit on the main
branch of livekit-examples/cpp-example-collection.
EOF
}

requested_hash=""
hash_provided=false

while (($#)); do
case "$1" in
--hash)
shift
if (($# == 0)); then
echo "ERROR: --hash requires a value" >&2
exit 2
fi
requested_hash="$1"
hash_provided=true
shift
;;
--hash=*)
requested_hash="${1#--hash=}"
hash_provided=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "ERROR: unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done

if [[ "$hash_provided" == true && ! "$requested_hash" =~ ^[0-9a-fA-F]{7,40}$ ]]; then
echo "ERROR: --hash must be a 7- to 40-character hexadecimal Git SHA-1 hash" >&2
exit 2
fi

# Shared checkout logic keeps the two dependency updaters consistent.
source "${script_dir}/update-submodule-common.sh"
check_update_prerequisites

fetch_ref=""
if [[ "$hash_provided" == false ]]; then
fetch_ref="refs/heads/${default_branch}"
fi
update_submodule cpp-example-collection "$examples_remote" "$fetch_ref"
107 changes: 107 additions & 0 deletions scripts/update-rust-sdk.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/usr/bin/env bash
#
# Copyright 2026 LiveKit
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
repo_root="$(cd "${script_dir}/.." && pwd -P)"
rust_repo="livekit/client-sdk-rust"
rust_remote="https://github.com/${rust_repo}.git"

usage() {
cat <<'EOF'
Usage: ./scripts/update-rust-sdk.sh [--hash HASH]

Update the client-sdk-rust submodule used by the C++ SDK.

Options:
--hash HASH
Use the specified Rust SDK commit. You can use a short or full SHA-1
hash.
-h, --help
Show this help and exit.

When --hash is omitted, the script uses the commit tagged by the most recently
published, non-draft GitHub release (including prereleases) in
livekit/client-sdk-rust (requires gh).
EOF
}

requested_hash=""
hash_provided=false

while (($#)); do
case "$1" in
--hash)
shift
if (($# == 0)); then
echo "ERROR: --hash requires a value" >&2
exit 2
fi
requested_hash="$1"
hash_provided=true
shift
;;
--hash=*)
requested_hash="${1#--hash=}"
hash_provided=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "ERROR: unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done

if [[ "$hash_provided" == true && ! "$requested_hash" =~ ^[0-9a-fA-F]{7,40}$ ]]; then
echo "ERROR: --hash must be a 7- to 40-character hexadecimal Git SHA-1 hash" >&2
exit 2
fi

# Shared checkout logic keeps the two dependency updaters consistent.
source "${script_dir}/update-submodule-common.sh"
check_update_prerequisites

if [[ "$hash_provided" == false ]]; then
if ! command -v gh >/dev/null 2>&1; then
echo "ERROR: gh not found in PATH; install GitHub CLI or provide --hash" >&2
exit 1
fi
echo "==> Finding the most recently published Rust SDK release"
# Sort across every page by publication time, including prereleases. API
# list order and GitHub's designated "latest" release are different concepts.
release_tag="$(gh api --hostname github.com --paginate --slurp \
"repos/${rust_repo}/releases?per_page=100" \
--jq '[.[][] | select(.draft == false and .published_at != null)] |
sort_by(.published_at, .id) | last | .tag_name // empty')"
if [[ -z "$release_tag" ]]; then
echo "ERROR: no published release found for ${rust_repo}" >&2
exit 1
fi
git check-ref-format "refs/tags/${release_tag}" >/dev/null
fetch_ref="refs/tags/${release_tag}"
echo "==> Selected release: ${release_tag}"
else
fetch_ref=""
fi

update_submodule client-sdk-rust "$rust_remote" "$fetch_ref"
99 changes: 99 additions & 0 deletions scripts/update-submodule-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env bash
#
# Copyright 2026 LiveKit
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Internal helpers sourced by update-rust-sdk.sh and
# update-cpp-example-collection.sh. Requires Bash 3.2 or newer.

check_update_prerequisites() {
if ! command -v git >/dev/null 2>&1; then
echo "ERROR: git not found in PATH" >&2
exit 1
fi
local top_level
top_level="$(git -C "$repo_root" rev-parse --show-toplevel)"
if [[ "$(cd "$top_level" && pwd -P)" != "$repo_root" ]]; then
echo "ERROR: ${repo_root} is not the SDK Git worktree root" >&2
exit 1
fi
}

require_clean_submodule() {
local directory="$1"
local changes
# Explicitly override submodule.*.ignore and diff.ignoreSubmodules. This
# includes nested HEAD changes, staged edits, and untracked files.
changes="$(git -C "$directory" status --porcelain --untracked-files=all \
--ignore-submodules=none)"
if [[ -n "$changes" ]]; then
echo "ERROR: ${directory} has local changes (possibly in nested submodules)." >&2
echo "Commit, stash, or move them before updating:" >&2
printf '%s\n' "$changes" >&2
exit 1
fi
}

update_submodule() {
local name="$1" remote="$2" fetch_ref="$3"
local directory="${repo_root}/${name}"
local resolved_hash current_hash
local fetch_options=(--no-tags)

if [[ -e "${directory}/.git" ]]; then
require_clean_submodule "$directory"
else
echo "==> Initializing ${name}"
git -C "$repo_root" submodule update --init --checkout -- "$name"
require_clean_submodule "$directory"
fi

echo "==> Fetching ${name} from ${remote}"
# Use the same authoritative repository for resolution and fetching, even
# when a developer's origin points to a fork. Leave their remotes unchanged.
if [[ "$hash_provided" == false ]]; then
git -C "$directory" fetch --quiet --no-tags "$remote" "$fetch_ref"
resolved_hash="$(git -C "$directory" rev-parse --verify 'FETCH_HEAD^{commit}')"
else
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
if [[ ${#requested_hash} -lt 40 ]] ||
! git -C "$directory" fetch --quiet --no-tags "$remote" "$requested_hash"; then
# Abbreviated hashes cannot be fetched directly. Fetch all branch/tag
# objects without updating local branches or overwriting local tags.
if [[ "$(git -C "$directory" rev-parse --is-shallow-repository)" == true ]]; then
fetch_options+=(--unshallow)
fi
git -C "$directory" fetch --quiet "${fetch_options[@]}" "$remote" \
'+refs/heads/*:refs/sdk-update/heads/*' '+refs/tags/*:refs/sdk-update/tags/*'
fi
if ! resolved_hash="$(git -C "$directory" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)" ||
[[ "$resolved_hash" != "$requested_hash"* ]]; then
echo "ERROR: '${requested_hash}' does not unambiguously identify a ${name} commit" >&2
exit 1
fi
fi

current_hash="$(git -C "$directory" rev-parse HEAD)"
echo "==> Selected ${name}: ${current_hash} -> ${resolved_hash}"
# Failures here can leave a partial update. Do not attempt a destructive
# rollback; show the developer exactly what needs inspection and retrying.
trap 'echo "ERROR: Update incomplete. Inspect git status and git submodule status --recursive; fix the error and rerun the updater. No changes were staged or committed." >&2' ERR
git -C "$directory" checkout --quiet --no-overwrite-ignore --detach "$resolved_hash"
git -C "$directory" submodule sync --recursive
git -C "$directory" submodule update --init --recursive --checkout
trap - ERR

echo "==> Done. Review with: git diff --submodule=log -- ${name}"
echo "==> Stage when ready: git add -- ${name}"
}
Loading