| #!/bin/bash |
| set -e |
| |
| declare -A REPOS=( |
| ["getting-started"]="https://fuchsia.googlesource.com/sdk-samples/getting-started" |
| ["drivers"]="https://fuchsia.googlesource.com/sdk-samples/drivers" |
| ["fortune-teller"]="https://fuchsia.googlesource.com/sdk-samples/fortune-teller" |
| ) |
| |
| usage() { |
| echo "Verify and update dependencies on Fuchsia SDK repositories." |
| echo |
| echo "Usage: $0 [--dry-run|-n] [--no-tests|-nt] [--debug] [REPO [REPO ...]]" |
| echo " --dry-run | -n Do not push roller CLs to Gerrit" |
| echo " --debug Turns Bash tracing on (set -x)" |
| echo " --no-tests | -nt Skip locally running tests on CLs before sending to Gerrit" |
| echo " REPO full git URL of a repo or shortname for known repos." |
| echo |
| echo "example:" |
| echo |
| echo " $0 -n -nt" |
| echo " Generates roller CLs for all known repos, but do not test and do not submit them" |
| echo |
| echo " $0 drivers" |
| echo " Generates roller CL for the driver repo if necessary." |
| echo |
| echo "If there is an open roller CL (hashtag:roller) for the given repository," |
| echo "this tool reuses it and submits a new patchset. Otherwise it will" |
| echo "create a new CL. The CL still needs to be reviewed and merged on Gerrit." |
| } |
| |
| main() { |
| if ! command -v 'cipd' >/dev/null; then |
| echo >&2 "Cannot find the cipd tool, please add it to PATH" |
| exit 1 |
| fi |
| |
| if ! command -v 'bazel' >/dev/null; then |
| echo >&2 "Cannot find the bazel tool, please add it to PATH" |
| exit 1 |
| fi |
| |
| if ! command -v 'gob-curl' >/dev/null; then |
| echo >&2 "Cannot find the gob-curl tool, please add it to PATH" |
| exit 1 |
| fi |
| |
| dry_run=0 # false |
| run_tests=1 # true |
| debug=0 |
| |
| repos=() |
| while [[ $# -gt 0 ]]; do |
| if [[ $1 == -* ]]; then |
| case "$1" in |
| --dry-run|-n) |
| dry_run=1 |
| ;; |
| --no-tests|-nt) |
| run_tests=0 |
| ;; |
| --debug) |
| set -x |
| ;; |
| -h|--help) |
| usage |
| exit 0 |
| ;; |
| *) |
| echo >&2 "Invalid syntax." |
| usage |
| exit 1 |
| esac |
| shift |
| continue |
| fi |
| if [[ $1 =~ https:\/\/|git:\/\/ ]]; then |
| repos+=( "$1" ) |
| else |
| if [[ -n "${REPOS[$1]}" ]]; then |
| repos+=( "${REPOS[$1]}" ) |
| else |
| echo >&2 "Invalid repo: $1" |
| exit 1 |
| fi |
| fi |
| shift |
| done |
| if [[ ${#repos[@]} -eq 0 ]]; then |
| repos+=( "${REPOS[@]}" ) |
| fi |
| |
| for repo in "${repos[@]}"; do |
| update_repo "$repo" |
| done |
| } |
| |
| get_latest() { |
| os="$1" |
| arch="$2" |
| sdk_t="$3" |
| cipd describe fuchsia/sdk/${sdk_t}/${os}-${arch} -version latest | |
| sed -n 's/ *version:\(.*\)/\1/p' |
| } |
| |
| get_latest_sdk_integration_version() { |
| branch="$1" |
| git ls-remote \ |
| https://fuchsia.googlesource.com/sdk-integration "$branch" \ |
| | cut -f 1 |
| } |
| |
| get_smaller_version() { |
| local smaller=$1 |
| shift |
| local all_same=1 |
| while [[ $# -gt 0 ]]; do |
| if [[ $smaller > $1 ]]; then |
| smaller=$1 |
| all_same=0 |
| fi |
| shift |
| done |
| if [[ $all_same -eq 0 ]]; then |
| echo " Warning: latest versions differ for different os/arch, using the older: $smaller" >&2 |
| fi |
| echo $smaller |
| } |
| |
| update_sdk_integration() { |
| repo="$1" |
| w="$2" |
| current="$(sed -n \ |
| -e '/^ *name *= *"rules_fuchsia" *, *$/,/^ *) *$/!b' \ |
| -e 's/^ *commit *= *"\(.*\)".*/\1/p' "$w")" |
| |
| if [[ -z "$current" ]]; then |
| # repo does not use versioned sdk-integration references in WORKSPACE |
| return 1 |
| fi |
| |
| branch="$(sed -n \ |
| -e '/^ *name *= *"rules_fuchsia" *, *$/,/^ *) *$/!b' \ |
| -e 's/.* branch *= *"\(.*\)".*/\1/p' "$w")" |
| if [[ -z "$branch" ]]; then |
| branch="main" |
| fi |
| |
| new_version="$(get_latest_sdk_integration_version "$branch")" |
| |
| if [[ "$new_version" != "$current" ]]; then |
| echo " SDK integration version (${current}) is old. Latest is ${new_version}." |
| update_sdk_integration_version $w $new_version |
| return 0 |
| fi |
| return 1 |
| } |
| |
| update_fuchsia_sdk() { |
| repo="$1" |
| w="$2" |
| current="$(sed -n \ |
| -e '/^ *fuchsia_sdk_repository *($/,/^ *) *$/!b' \ |
| -e 's/^ *cipd_tag *= *"version:\(.*\)".*/\1/p' "$w")" |
| |
| has_experimental=0 |
| if [[ -n "$(get_current_sha256 $w linux_experimental)" ]]; then |
| has_experimental=1 |
| fi |
| versions=( "$(get_latest linux amd64 core)" "$(get_latest mac amd64 core)" ) |
| if [[ $has_experimental -eq 1 ]]; then |
| versions+=( "$(get_latest linux amd64 experimental)" "$(get_latest mac amd64 experimental)" ) |
| fi |
| |
| new_version="$(get_smaller_version "${versions[@]}")" |
| |
| if [[ "$new_version" != "$current" ]]; then |
| echo " core SDK version (${current}) is old. Latest is ${new_version}." |
| update_current_version $w $new_version |
| update_current_sha256 $w linux $(get_sha256 linux amd64 core $new_version) |
| update_current_sha256 $w mac $(get_sha256 mac amd64 core $new_version) |
| # if repo uses experimental |
| if [[ $has_experimental -eq 1 ]]; then |
| update_current_sha256 $w linux_experimental $(get_sha256 linux amd64 experimental $new_version) |
| update_current_sha256 $w mac_experimental $(get_sha256 mac amd64 experimental $new_version) |
| fi |
| return 0 |
| fi |
| return 1 |
| } |
| |
| update_submodules() { |
| if [[ -n "$(git submodule update --remote)" ]]; then |
| return 1 |
| fi |
| return 0 |
| } |
| |
| |
| get_current_sha256() { |
| w="$1" |
| key="$2" |
| sed -n -e '/^ *fuchsia_sdk_repository *( *$/,/^ *) *$/!b' \ |
| -e '/^ *sha256 *= *{ *$/,/^ *} *, *$/!b' \ |
| -e 's/^ *"'${key}'" *: *"\(.*\)".*/\1/p' \ |
| "$w" |
| } |
| |
| update_sdk_integration_version() { |
| w="$1" |
| newversion="$2" |
| sed -i'' -e '/^ *name *= *"rules_fuchsia" *, *$/,/^ *) *$/!b' \ |
| -e 's/^\( *commit *= *"\)\(.*\)\(".*\)/\1'${newversion}'\3/' \ |
| "$w" |
| } |
| |
| update_current_version() { |
| w="$1" |
| newversion="$2" |
| sed -i'' -e '/^ *fuchsia_sdk_repository *( *$/,/^ *) *$/!b' \ |
| -e 's/^\( *cipd_tag *= *"version:\)\(.*\)\(".*\)/\1'${newversion}'\3/' \ |
| "$w" |
| } |
| |
| update_current_sha256() { |
| w="$1" |
| key="$2" |
| newsha="$3" |
| sed -i'' -e '/^ *fuchsia_sdk_repository *( *$/,/^ *) *$/!b' \ |
| -e '/^ *sha256 *= *{ *$/,/^ *} *, *$/!b' \ |
| -e 's/^\( *"'${key}'" *: *"\)\(.*\)\(".*\)/\1'${newsha}'\3/' \ |
| "$w" |
| } |
| |
| get_sha256() { |
| os="$1" |
| arch="$2" |
| sdk_t="$3" |
| version="$4" |
| # this is a hack, but I couldn't figure out another way to get the SHA256 from |
| # cipd |
| local url="https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/${sdk_t}/${os}-${arch}/+/version:${version}" |
| |
| curl -s "$url" | sed -n 's|.*https://storage.googleapis.com/chrome-infra-packages/store/SHA256/\([0-9a-f]*\).*|\1|p' |
| } |
| |
| get_existing_roller_cl() { |
| repo=$1 |
| if [[ "$repo" =~ https://fuchsia.googlesource.com/ ]]; then |
| project="${repo##https://fuchsia.googlesource.com/}" |
| gob-curl -q \ |
| "https://fuchsia-review.git.corp.google.com/a/changes/?q=project:${project}+status:open+hashtag:roller&n=1" \ |
| 2>/dev/null | \ |
| sed -n 's/.*"change_id":"\([^"]*\)".*/\1/p' |
| fi |
| } |
| |
| update_repo() { |
| local repo="$1" |
| local d="$(mktemp -d)" |
| cd "$d" |
| echo "Checking $repo..." |
| git clone -q --recursive "$repo" |
| trap "echo \"Temporary directory preserved in $d\"" EXIT |
| cd "$(basename $repo)" |
| local updated=0 |
| if [[ ! -f "WORKSPACE.bazel" ]]; then |
| echo >&2 "Error, repo does not contain WORKSPACE.bazel: $repo" |
| return 1 |
| fi |
| if grep -q "fuchsia_sdk_repository" "WORKSPACE.bazel"; then |
| update_fuchsia_sdk "$repo" "WORKSPACE.bazel" && updated=1 |
| update_sdk_integration "$repo" "WORKSPACE.bazel" && updated=1 |
| fi |
| |
| update_submodules && updated=1 |
| |
| if [[ $updated -eq 1 ]]; then |
| if [[ $run_tests -eq 1 ]]; then |
| echo " Testing before updating..." |
| # test the change |
| if [[ -x scripts/run_tests.sh ]]; then |
| scripts/run_tests.sh |
| elif [[ -x scripts/smoke_test.sh ]]; then |
| scripts/smoke_test.sh |
| elif [[ -x scripts/build.sh ]]; then |
| scripts/build.sh |
| elif [[ -f src/BUILD.bazel ]] && grep "samples_repository" src/BUILD.bazel; then |
| bazel build --config=fuchsia_x64 src:samples_repository |
| else |
| echo "Don't know how to test repo $repo. Ignoring it." |
| fi |
| else |
| echo " Skipping tests because flag -nt/--no-tests is used" |
| fi |
| |
| existing_cl="$(get_existing_roller_cl $repo)" |
| if [[ -n "$existing_cl" ]]; then |
| echo " Warning: reusing existing Change-ID $existing_cl" >&2 |
| existing_cl="Change-Id: $existing_cl" |
| fi |
| |
| # install commit hook that creates the change-id: |
| f=`git rev-parse --git-dir`/hooks/commit-msg |
| mkdir -p $(dirname $f) |
| curl -s -Lo $f https://gerrit-review.googlesource.com/tools/hooks/commit-msg |
| chmod +x $f |
| |
| git commit -m "[version roller] Update dependencies" \ |
| -m "SDK version updated from $current to $new_version" \ |
| -m "$existing_cl" \ |
| $w |
| |
| if [[ $dry_run -eq 1 ]]; then |
| echo |
| echo " DRY-RUN: this is what we would have pushed:" >&2 |
| echo |
| git show |
| else |
| git push origin HEAD:refs/for/main -o t=roller |
| cd .. |
| rm -rf $d |
| fi |
| trap EXIT |
| fi |
| } |
| |
| main "$@" |
| |