#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "$script_dir/../.." && pwd)" version_file="${VNIDROP_VERSION_FILE:-$repo_root/version.properties}" fail() { printf '%s\n' "$*" >&2 exit 1 } read_property() { local key=$1 local matches matches="$(sed -n "s/^${key}=//p" "$version_file")" [[ -n "$matches" ]] || fail "Missing $key in $version_file" [[ $(printf '%s\n' "$matches" | wc -l | tr -d ' ') == 1 ]] || fail "Duplicate $key in $version_file" printf '%s' "$matches" } validate_canonical_integer() { local name=$1 local value=$2 local minimum=$3 local maximum=$4 [[ $value =~ ^(0|[1-9][0-9]*)$ ]] || fail "$name must be a canonical non-negative integer" (( 10#$value >= minimum && 10#$value <= maximum )) || fail "$name must be between $minimum and $maximum" } product_version="$(read_property PRODUCT_VERSION)" release_channel="$(read_property RELEASE_CHANNEL)" windows_version_epoch="$(read_property WINDOWS_VERSION_EPOCH)" build_time_utc="${VNIDROP_BUILD_TIME_UTC:-$(date -u +%Y%m%d%H%M%S)}" [[ $product_version =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] || fail "PRODUCT_VERSION must use canonical MAJOR.MINOR.PATCH integers" IFS=. read -r product_major product_minor product_patch <<< "$product_version" validate_canonical_integer "PRODUCT_VERSION major" "$product_major" 0 2099 validate_canonical_integer "PRODUCT_VERSION minor" "$product_minor" 0 999 validate_canonical_integer "PRODUCT_VERSION patch" "$product_patch" 0 999 [[ $release_channel =~ ^[a-z][a-z0-9-]*$ ]] || fail "RELEASE_CHANNEL must start with a lowercase letter and contain only lowercase letters, digits, and hyphens" validate_canonical_integer "WINDOWS_VERSION_EPOCH" "$windows_version_epoch" 1 65535 [[ $build_time_utc =~ ^[0-9]{14}$ ]] || fail "VNIDROP_BUILD_TIME_UTC must use YYYYMMDDHHMMSS" android_version_code=$(( (10#$product_major * 1000000) + (10#$product_minor * 1000) + 10#$product_patch )) (( android_version_code >= 1 && android_version_code <= 2100000000 )) || fail "Derived Android version code must be between 1 and 2100000000" build_month="${build_time_utc:4:2}" build_day="${build_time_utc:6:2}" build_hour="${build_time_utc:8:2}" build_minute="${build_time_utc:10:2}" build_second="${build_time_utc:12:2}" build_year="${build_time_utc:0:4}" (( 10#$build_year >= 1 )) || fail "VNIDROP_BUILD_TIME_UTC contains an invalid year" (( 10#$build_month >= 1 && 10#$build_month <= 12 )) || fail "VNIDROP_BUILD_TIME_UTC contains an invalid month" case $((10#$build_month)) in 2) max_build_day=28 if (( 10#$build_year % 400 == 0 || (10#$build_year % 4 == 0 && 10#$build_year % 100 != 0) )); then max_build_day=29 fi ;; 4|6|9|11) max_build_day=30 ;; *) max_build_day=31 ;; esac (( 10#$build_day >= 1 && 10#$build_day <= max_build_day )) || fail "VNIDROP_BUILD_TIME_UTC contains an invalid day" (( 10#$build_hour <= 23 && 10#$build_minute <= 59 && 10#$build_second <= 59 )) || fail "VNIDROP_BUILD_TIME_UTC contains an invalid time" apple_build_number="${build_time_utc:0:8}.${build_time_utc:8:4}.${build_time_utc:12:2}" windows_major=$((10#$product_major + 10#$windows_version_epoch)) (( windows_major <= 65535 )) || fail "Derived Windows package major exceeds 65535" windows_package_version="$windows_major.$product_minor.$product_patch.0" verify_tag() { local tag=${1:-${GITHUB_REF_NAME:-}} if [[ ${GITHUB_REF_TYPE:-} == tag || -n ${1:-} ]]; then [[ $tag == "v$product_version" ]] || fail "Release tag must be v$product_version, got ${tag:-}" fi } case "${1:-verify}" in product) printf '%s\n' "$product_version" ;; channel) printf '%s\n' "$release_channel" ;; android-code) printf '%s\n' "$android_version_code" ;; apple-store-build) printf '%s\n' "$apple_build_number" ;; apple-direct-build) printf '%s\n' "$apple_build_number" ;; windows-package) printf '%s\n' "$windows_package_version" ;; verify) verify_tag printf 'VniDrop %s (%s), Android %s, Apple Store %s, Apple Direct %s, MSIX %s\n' \ "$product_version" "$release_channel" "$android_version_code" \ "$apple_build_number" "$apple_build_number" "$windows_package_version" ;; verify-tag) verify_tag "${2:-}" ;; *) fail "Usage: $0 {product|channel|android-code|apple-store-build|apple-direct-build|windows-package|verify|verify-tag [tag]}" ;; esac