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
2 changes: 1 addition & 1 deletion client-sdk-rust
45 changes: 35 additions & 10 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,48 @@ For details on the Doxygen configuration and CI pipeline, see the

### Bump the pinned Rust submodule

Update to the commit from the most recent published Rust SDK release:

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

The script requires the GitHub CLI (`gh`). To select a specific commit, pass
its full or abbreviated hash:
Comment on lines +149 to +150

# Sync submodule URLs and check out what origin/main pins (recursively):
git submodule sync --recursive
git submodule update --init --recursive --checkout
```bash
./scripts/update-rust-sdk.sh --hash 1a477bc
```

# 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
The script updates the `client-sdk-rust` gitlink and synchronizes its nested
submodules. It stops without changing the checkout if the Rust submodule has
tracked changes.

# Sanity check:
Review the selected commits before committing the gitlink update:

```bash
git submodule status --recursive
```

### 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
```

The script updates the `cpp-example-collection` gitlink and synchronizes its
nested submodules. It stops without changing the checkout if the examples
submodule has tracked changes.

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

```bash
Expand Down
148 changes: 148 additions & 0 deletions scripts/update-cpp-example-collection.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/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_dir="${repo_root}/cpp-example-collection"
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

if ! command -v git >/dev/null 2>&1; then
echo "ERROR: git not found in PATH" >&2
exit 1
fi

if ! git -C "$repo_root" rev-parse --show-toplevel >/dev/null 2>&1; then
echo "ERROR: ${repo_root} is not a Git worktree" >&2
exit 1
fi

if [[ ! -e "${examples_dir}/.git" ]]; then
echo "==> Initializing cpp-example-collection"
git -C "$repo_root" submodule update --init cpp-example-collection
fi

if ! git -C "$examples_dir" diff --quiet ||
! git -C "$examples_dir" diff --cached --quiet; then
echo "ERROR: cpp-example-collection has tracked changes; commit or stash them first" >&2
exit 1
fi

fetch_ref="$requested_hash"

if [[ "$hash_provided" == false ]]; then
echo "==> Finding the most recent cpp-example-collection commit"
branch_ref="refs/heads/${default_branch}"
remote_ref="$(git ls-remote "$examples_remote" "$branch_ref")"
read -r requested_hash resolved_ref <<<"$remote_ref"
if [[ -z "$requested_hash" || "$resolved_ref" != "$branch_ref" ]]; then
echo "ERROR: branch '${default_branch}' was not found in ${examples_repo}" >&2
exit 1
fi
fetch_ref="$branch_ref"
echo "==> Latest ${default_branch} commit: ${requested_hash}"
else
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
echo "==> Requested examples commit: ${requested_hash}"
fi

echo "==> Fetching cpp-example-collection"
if [[ "$hash_provided" == false ]]; then
git -C "$examples_dir" fetch --quiet origin "$fetch_ref"
elif [[ ${#requested_hash} -eq 40 ]]; then
if ! git -C "$examples_dir" fetch --quiet origin "$fetch_ref"; then
git -C "$examples_dir" fetch --quiet origin
fi
else
git -C "$examples_dir" fetch --quiet origin
fi

if ! resolved_hash="$(git -C "$examples_dir" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)"; then
echo "ERROR: '${requested_hash}' does not resolve to a cpp-example-collection commit" >&2
exit 1
fi

current_hash="$(git -C "$examples_dir" rev-parse HEAD)"
if [[ "$current_hash" == "$resolved_hash" ]]; then
echo "==> cpp-example-collection is already at ${resolved_hash}"
else
git -C "$examples_dir" checkout --quiet --detach "$resolved_hash"
echo "==> Updated cpp-example-collection: ${current_hash} -> ${resolved_hash}"
fi

echo "==> Synchronizing nested example submodules"
git -C "$examples_dir" submodule sync --recursive
git -C "$examples_dir" submodule update --init --recursive

echo "==> Done. Review and commit the cpp-example-collection gitlink change."
174 changes: 174 additions & 0 deletions scripts/update-rust-sdk.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/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_dir="${repo_root}/client-sdk-rust"
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 recent
published, non-draft GitHub release in livekit/client-sdk-rust.
Comment on lines +38 to +39
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

if ! command -v git >/dev/null 2>&1; then
echo "ERROR: git not found in PATH" >&2
exit 1
fi

if ! git -C "$repo_root" rev-parse --show-toplevel >/dev/null 2>&1; then
echo "ERROR: ${repo_root} is not a Git worktree" >&2
exit 1
fi

if [[ ! -e "${rust_dir}/.git" ]]; then
echo "==> Initializing client-sdk-rust"
git -C "$repo_root" submodule update --init client-sdk-rust
fi

if ! git -C "$rust_dir" diff --quiet ||
! git -C "$rust_dir" diff --cached --quiet; then
echo "ERROR: client-sdk-rust has tracked changes; commit or stash them first" >&2
exit 1
fi

fetch_ref="$requested_hash"
release_tag=""

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 recent published Rust SDK release"
release_tags="$(
gh api --paginate "repos/${rust_repo}/releases?per_page=100" \
--jq '.[] | select(.draft == false) | .tag_name'
)"
release_tag="${release_tags%%$'\n'*}"
Comment on lines +111 to +115

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Newest publication can be skipped

When creation and publication order differ, release_tags selects the API's first non-draft release. It can pin an older publication.

Prompt for agents
The default update path in scripts/update-rust-sdk.sh assumes the first non-draft item returned by GitHub is the most recently published release. GitHub's release listing order is not publication-time order, so a release published later from an older-created commit can be skipped. Collect all non-draft releases with their published_at timestamps, select the maximum publication timestamp, then use that release's tag. Preserve pagination and fail clearly when no published release exists.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

if [[ -z "$release_tag" ]]; then
echo "ERROR: no published release found for ${rust_repo}" >&2
exit 1
fi

tag_refs="$(
git ls-remote "$rust_remote" \
"refs/tags/${release_tag}" "refs/tags/${release_tag}^{}"
)"
while read -r tag_hash tag_ref; do
if [[ "$tag_ref" == "refs/tags/${release_tag}^{}" ]]; then
requested_hash="$tag_hash"
break
fi
if [[ "$tag_ref" == "refs/tags/${release_tag}" ]]; then
requested_hash="$tag_hash"
fi
done <<<"$tag_refs"

if [[ -z "$requested_hash" ]]; then
echo "ERROR: release tag '${release_tag}' was not found in ${rust_repo}" >&2
exit 1
fi
fetch_ref="refs/tags/${release_tag}"
echo "==> Latest release: ${release_tag} (${requested_hash})"
else
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
echo "==> Requested Rust SDK commit: ${requested_hash}"
fi

echo "==> Fetching client-sdk-rust"
if [[ "$hash_provided" == false ]]; then
git -C "$rust_dir" fetch --quiet origin "$fetch_ref"
elif [[ ${#requested_hash} -eq 40 ]]; then
if ! git -C "$rust_dir" fetch --quiet origin "$fetch_ref"; then
git -C "$rust_dir" fetch --quiet origin
fi
else
git -C "$rust_dir" fetch --quiet origin
fi
Comment on lines +146 to +155

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Customized remotes block updates

When a submodule's origin targets a fork, fetch searches that fork for the canonical commit. Both update commands then fail.

Prompt for agents
scripts/update-rust-sdk.sh discovers releases from rust_remote but fetches from the mutable origin remote. scripts/update-cpp-example-collection.sh has the same mismatch with examples_remote. A user-configured fork or mirror can therefore lack the commit selected from the canonical repository. Make discovery and fetching use the same canonical source while retaining support for abbreviated hashes, which requires fetching enough canonical refs for disambiguation.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


if ! resolved_hash="$(git -C "$rust_dir" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)"; then
echo "ERROR: '${requested_hash}' does not resolve to a client-sdk-rust commit" >&2
exit 1
fi

current_hash="$(git -C "$rust_dir" rev-parse HEAD)"
if [[ "$current_hash" == "$resolved_hash" ]]; then
echo "==> client-sdk-rust is already at ${resolved_hash}"
else
git -C "$rust_dir" checkout --quiet --detach "$resolved_hash"
echo "==> Updated client-sdk-rust: ${current_hash} -> ${resolved_hash}"
fi

echo "==> Synchronizing nested Rust SDK submodules"
git -C "$rust_dir" submodule sync --recursive
git -C "$rust_dir" submodule update --init --recursive

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Nested submodules remain on wrong commits

With a local rebase, merge, or none update mode, submodule update does not check out the pinned commit. The script reports success while builds use different Rust dependencies.

Suggested change
git -C "$rust_dir" submodule update --init --recursive
git -C "$rust_dir" submodule update --init --recursive --checkout
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


echo "==> Done. Review and commit the client-sdk-rust gitlink change."
Loading