660 lines
18 KiB
Bash
Executable File
660 lines
18 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$SCRIPT_DIR"
|
|
TMP_DIR="$PROJECT_DIR/.tmp-android-build"
|
|
SDK_DIR="$PROJECT_DIR/android-sdk"
|
|
JDK_DIR="$PROJECT_DIR/jdk"
|
|
GRADLE_USER_HOME_DIR="$PROJECT_DIR/.gradle-user-home"
|
|
STATE_FILE="$PROJECT_DIR/.android-project-tooling.state"
|
|
LEGACY_STATE_FILE="$PROJECT_DIR/.setup-build-environment.state"
|
|
COMMIT_SUMMARY_FILE="$PROJECT_DIR/commit-summary.txt"
|
|
UPLOAD_SCRIPT="$PROJECT_DIR/upload2DL.sh"
|
|
CMDLINE_TOOLS_DIR="$SDK_DIR/cmdline-tools"
|
|
CMDLINE_TOOLS_LATEST_DIR="$CMDLINE_TOOLS_DIR/latest"
|
|
WRAPPER_JAR_PATH="$PROJECT_DIR/gradle/wrapper/gradle-wrapper.jar"
|
|
LOCAL_PROPERTIES_PATH="$PROJECT_DIR/local.properties"
|
|
HOST_GIT_BINARY="$PROJECT_DIR/build/host-git/libgit.so"
|
|
GIT_SRC_DIR="$TMP_DIR/git-src"
|
|
HOST_GIT_DIR="$PROJECT_DIR/build/host-git"
|
|
HOST_GIT_STAMP="$HOST_GIT_DIR/.source-fingerprint"
|
|
ANDROID_JNI_DIR="$PROJECT_DIR/app/src/main/jniLibs"
|
|
ANDROID_ASSET_MANPAGE_DIR="$PROJECT_DIR/app/src/main/assets/manpages"
|
|
ANDROID_API=24
|
|
|
|
ANDROID_CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
|
|
GRADLE_DIST_URL="https://services.gradle.org/distributions/gradle-8.7-bin.zip"
|
|
JDK_DIST_URL="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jdk/hotspot/normal/eclipse"
|
|
ANDROID_NDK_PACKAGE="ndk;27.2.12479018"
|
|
ANDROID_CMAKE_PACKAGE="cmake;3.22.1"
|
|
ANDROID_NDK_DIR="$SDK_DIR/ndk/27.2.12479018"
|
|
ANDROID_CMAKE_DIR="$SDK_DIR/cmake/3.22.1"
|
|
ANDROID_TOOLBIN="$ANDROID_NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
|
STATE_TTL_SECONDS=86400
|
|
|
|
log() {
|
|
printf '\n[%s] %s\n' "tooling" "$1"
|
|
}
|
|
|
|
require_tool() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "Missing required tool: $1" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
ensure_dir() {
|
|
mkdir -p "$1"
|
|
}
|
|
|
|
current_epoch() {
|
|
date +%s
|
|
}
|
|
|
|
have_recent_success_marker() {
|
|
local marker_file="$STATE_FILE"
|
|
if [ ! -f "$marker_file" ] && [ -f "$LEGACY_STATE_FILE" ]; then
|
|
marker_file="$LEGACY_STATE_FILE"
|
|
fi
|
|
|
|
if [ ! -f "$marker_file" ]; then
|
|
return 1
|
|
fi
|
|
|
|
local recorded_epoch
|
|
recorded_epoch="$(cat "$marker_file" 2>/dev/null || true)"
|
|
if ! printf '%s' "$recorded_epoch" | grep -Eq '^[0-9]+$'; then
|
|
return 1
|
|
fi
|
|
|
|
local now
|
|
now="$(current_epoch)"
|
|
[ $((now - recorded_epoch)) -lt "$STATE_TTL_SECONDS" ]
|
|
}
|
|
|
|
mark_successful_check() {
|
|
current_epoch > "$STATE_FILE"
|
|
}
|
|
|
|
required_sdk_packages_present() {
|
|
[ -d "$SDK_DIR/platform-tools" ] \
|
|
&& [ -d "$SDK_DIR/platforms/android-35" ] \
|
|
&& [ -d "$SDK_DIR/build-tools/35.0.0" ] \
|
|
&& [ -d "$ANDROID_NDK_DIR" ] \
|
|
&& [ -d "$ANDROID_CMAKE_DIR" ]
|
|
}
|
|
|
|
auto_commit_if_needed() {
|
|
if ! command -v git >/dev/null 2>&1; then
|
|
log "Git is not available; skipping automatic commit"
|
|
return
|
|
fi
|
|
|
|
if ! git -C "$PROJECT_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
log "Project is not inside a git work tree; skipping automatic commit"
|
|
return
|
|
fi
|
|
|
|
git -C "$PROJECT_DIR" add -A
|
|
|
|
# Defense in depth: never allow signing material or local signing config to be
|
|
# included in the automatic commit, even if a file was force-added manually.
|
|
git -C "$PROJECT_DIR" reset -q HEAD -- \
|
|
keystore.properties \
|
|
commit-summary.txt \
|
|
upload2DL.sh \
|
|
'*.keystore' \
|
|
'*.jks' 2>/dev/null || true
|
|
|
|
if git -C "$PROJECT_DIR" diff --cached --quiet; then
|
|
log "No source changes to commit after successful build"
|
|
return
|
|
fi
|
|
|
|
log "Creating git commit for the latest successful build"
|
|
if [ -s "$COMMIT_SUMMARY_FILE" ] && grep -q '[^[:space:]]' "$COMMIT_SUMMARY_FILE"; then
|
|
git -C "$PROJECT_DIR" commit -F "$COMMIT_SUMMARY_FILE"
|
|
else
|
|
git -C "$PROJECT_DIR" commit -m "Misc Changes"
|
|
fi
|
|
: > "$COMMIT_SUMMARY_FILE"
|
|
git push
|
|
}
|
|
|
|
download_if_missing() {
|
|
local url="$1"
|
|
local output="$2"
|
|
if [ -f "$output" ]; then
|
|
log "Using existing download: ${output#$PROJECT_DIR/}"
|
|
else
|
|
log "Downloading $(basename "$output")"
|
|
curl -L "$url" -o "$output"
|
|
fi
|
|
}
|
|
|
|
ensure_cmdline_tools() {
|
|
if [ -x "$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" ]; then
|
|
log "Android command-line tools already present"
|
|
return
|
|
fi
|
|
|
|
ensure_dir "$CMDLINE_TOOLS_DIR"
|
|
ensure_dir "$TMP_DIR"
|
|
local zip_path="$TMP_DIR/commandlinetools.zip"
|
|
download_if_missing "$ANDROID_CMDLINE_TOOLS_URL" "$zip_path"
|
|
|
|
log "Extracting Android command-line tools"
|
|
rm -rf "$CMDLINE_TOOLS_LATEST_DIR"
|
|
unzip -q -o "$zip_path" -d "$CMDLINE_TOOLS_DIR"
|
|
if [ -d "$CMDLINE_TOOLS_DIR/cmdline-tools" ]; then
|
|
mv "$CMDLINE_TOOLS_DIR/cmdline-tools" "$CMDLINE_TOOLS_LATEST_DIR"
|
|
fi
|
|
}
|
|
|
|
ensure_wrapper_jar() {
|
|
if [ -f "$WRAPPER_JAR_PATH" ]; then
|
|
log "Gradle wrapper jar already present"
|
|
return
|
|
fi
|
|
|
|
ensure_dir "$TMP_DIR"
|
|
local zip_path="$TMP_DIR/gradle-8.7-bin.zip"
|
|
local gradle_extract_dir="$TMP_DIR/gradle-8.7"
|
|
local plugin_wrapper_jar="$gradle_extract_dir/lib/plugins/gradle-wrapper-8.7.jar"
|
|
download_if_missing "$GRADLE_DIST_URL" "$zip_path"
|
|
|
|
log "Extracting Gradle wrapper jar"
|
|
rm -rf "$gradle_extract_dir"
|
|
unzip -q -o "$zip_path" -d "$TMP_DIR"
|
|
python - <<PY
|
|
import zipfile
|
|
src = r'''$plugin_wrapper_jar'''
|
|
dst = r'''$WRAPPER_JAR_PATH'''
|
|
with zipfile.ZipFile(src) as zf:
|
|
data = zf.read('gradle-wrapper.jar')
|
|
with open(dst, 'wb') as f:
|
|
f.write(data)
|
|
PY
|
|
}
|
|
|
|
ensure_jdk17() {
|
|
if [ -x "$JDK_DIR/bin/java" ]; then
|
|
log "Project-local JDK already present"
|
|
return
|
|
fi
|
|
|
|
ensure_dir "$TMP_DIR"
|
|
local archive_path="$TMP_DIR/jdk17.tar.gz"
|
|
local extract_dir="$TMP_DIR/jdk17-extract"
|
|
rm -f "$archive_path"
|
|
download_if_missing "$JDK_DIST_URL" "$archive_path"
|
|
|
|
log "Extracting project-local JDK"
|
|
rm -rf "$extract_dir" "$JDK_DIR"
|
|
mkdir -p "$extract_dir"
|
|
if ! file "$archive_path" | grep -qiE 'gzip compressed|tar archive'; then
|
|
echo "Downloaded JDK archive is not a valid tar.gz: $archive_path" >&2
|
|
exit 1
|
|
fi
|
|
tar -xzf "$archive_path" -C "$extract_dir"
|
|
local extracted_root
|
|
extracted_root="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
|
|
if [ -z "$extracted_root" ]; then
|
|
echo "Unable to locate extracted JDK directory" >&2
|
|
exit 1
|
|
fi
|
|
mv "$extracted_root" "$JDK_DIR"
|
|
}
|
|
|
|
setup_java_env() {
|
|
export JAVA_HOME="$JDK_DIR"
|
|
export PATH="$JAVA_HOME/bin:$PATH"
|
|
}
|
|
|
|
write_local_properties() {
|
|
log "Writing local.properties"
|
|
cat > "$LOCAL_PROPERTIES_PATH" <<EOF_INNER
|
|
sdk.dir=$SDK_DIR
|
|
EOF_INNER
|
|
}
|
|
|
|
bump_android_version() {
|
|
local gradle_file="$PROJECT_DIR/app/build.gradle.kts"
|
|
if [ ! -f "$gradle_file" ]; then
|
|
log "No app/build.gradle.kts found; skipping version bump"
|
|
return
|
|
fi
|
|
|
|
log "Bumping Android app version before build"
|
|
python - <<PY
|
|
from pathlib import Path
|
|
import re
|
|
|
|
path = Path(r'''$gradle_file''')
|
|
text = path.read_text()
|
|
|
|
version_code_match = re.search(r'versionCode\s*=\s*(\d+)', text)
|
|
version_name_match = re.search(r'versionName\s*=\s*"(\d+)\.(\d+)\.(\d+)"', text)
|
|
|
|
if not version_code_match or not version_name_match:
|
|
raise SystemExit('Could not find versionCode/versionName in app/build.gradle.kts')
|
|
|
|
current_code = int(version_code_match.group(1))
|
|
major, minor, patch = map(int, version_name_match.groups())
|
|
|
|
new_code = current_code + 1
|
|
new_name = f'{major}.{minor}.{patch + 1}'
|
|
|
|
text = re.sub(r'versionCode\s*=\s*\d+', f'versionCode = {new_code}', text, count=1)
|
|
text = re.sub(r'versionName\s*=\s*"\d+\.\d+\.\d+"', f'versionName = "{new_name}"', text, count=1)
|
|
|
|
path.write_text(text)
|
|
print(f'Updated versionCode to {new_code} and versionName to {new_name}')
|
|
PY
|
|
}
|
|
|
|
android_version_code() {
|
|
local gradle_file="$PROJECT_DIR/app/build.gradle.kts"
|
|
python - <<PY
|
|
from pathlib import Path
|
|
import re
|
|
|
|
path = Path(r'''$gradle_file''')
|
|
text = path.read_text()
|
|
match = re.search(r'versionCode\s*=\s*(\d+)', text)
|
|
if not match:
|
|
raise SystemExit('Could not find versionCode in app/build.gradle.kts')
|
|
print(match.group(1))
|
|
PY
|
|
}
|
|
|
|
upload_build_artifact_if_possible() {
|
|
local artifact_path="$1"
|
|
|
|
if [ ! -f "$artifact_path" ]; then
|
|
echo "Upload artifact not found: $artifact_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$UPLOAD_SCRIPT" ]; then
|
|
log "No upload2DL.sh found; skipping artifact upload"
|
|
return
|
|
fi
|
|
|
|
log "Uploading $(basename "$artifact_path") with upload2DL.sh"
|
|
bash "$UPLOAD_SCRIPT" "$artifact_path"
|
|
}
|
|
|
|
setup_env() {
|
|
setup_java_env
|
|
export ANDROID_HOME="$SDK_DIR"
|
|
export ANDROID_SDK_ROOT="$SDK_DIR"
|
|
export GRADLE_USER_HOME="$GRADLE_USER_HOME_DIR"
|
|
}
|
|
|
|
require_path() {
|
|
if [ ! -e "$1" ]; then
|
|
echo "Required path not found: $1" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
ensure_git_source() {
|
|
mkdir -p "$TMP_DIR"
|
|
if [ ! -d "$GIT_SRC_DIR/.git" ]; then
|
|
log "Cloning Git source"
|
|
git clone --depth 1 https://github.com/git/git.git "$GIT_SRC_DIR"
|
|
else
|
|
log "Using existing Git source checkout"
|
|
fi
|
|
}
|
|
|
|
common_git_make_args() {
|
|
printf '%s\n' \
|
|
NO_OPENSSL=YesPlease \
|
|
NO_CURL=YesPlease \
|
|
NO_EXPAT=YesPlease \
|
|
NO_GETTEXT=YesPlease \
|
|
NO_TCLTK=YesPlease \
|
|
NO_PERL=YesPlease \
|
|
NO_PYTHON=YesPlease \
|
|
NO_INSTALL_HARDLINKS=YesPlease \
|
|
NO_ICONV=YesPlease \
|
|
NO_REGEX=NeedsStartEnd \
|
|
HAVE_ALLOCA_H=YesPlease \
|
|
HAVE_PATHS_H=YesPlease \
|
|
HAVE_CLOCK_GETTIME=YesPlease \
|
|
HAVE_CLOCK_MONOTONIC=YesPlease \
|
|
HAVE_GETDELIM=YesPlease \
|
|
FREAD_READS_DIRECTORIES=UnfortunatelyYes \
|
|
CSPRNG_METHOD=
|
|
}
|
|
|
|
bundle_git_manpages() {
|
|
require_path "$GIT_SRC_DIR/Documentation"
|
|
|
|
log "Bundling full Git manpage sources"
|
|
mkdir -p "$ANDROID_ASSET_MANPAGE_DIR"
|
|
find "$ANDROID_ASSET_MANPAGE_DIR" -type f -name '*.txt' -delete
|
|
while IFS= read -r manpage_source; do
|
|
local manpage_name
|
|
manpage_name="$(basename "$manpage_source")"
|
|
cp "$manpage_source" "$ANDROID_ASSET_MANPAGE_DIR/${manpage_name%.*}.txt"
|
|
done < <(find "$GIT_SRC_DIR/Documentation" -maxdepth 1 -type f \( -name 'git*.txt' -o -name 'git*.adoc' -o -name 'gitignore.txt' -o -name 'gitignore.adoc' \))
|
|
}
|
|
|
|
git_source_fingerprint() {
|
|
ensure_git_source
|
|
|
|
local head
|
|
local tracked_changes
|
|
head="$(git -C "$GIT_SRC_DIR" rev-parse HEAD)"
|
|
tracked_changes="$(git -C "$GIT_SRC_DIR" diff --binary HEAD -- | git hash-object --stdin)"
|
|
printf '%s:%s\n' "$head" "$tracked_changes"
|
|
}
|
|
|
|
target_is_current() {
|
|
local output="$1"
|
|
local stamp="$2"
|
|
local fingerprint="$3"
|
|
|
|
[ -x "$output" ] \
|
|
&& [ -f "$stamp" ] \
|
|
&& [ "$(cat "$stamp" 2>/dev/null || true)" = "$fingerprint" ]
|
|
}
|
|
|
|
mark_target_current() {
|
|
local stamp="$1"
|
|
local fingerprint="$2"
|
|
|
|
mkdir -p "$(dirname "$stamp")"
|
|
printf '%s\n' "$fingerprint" > "$stamp"
|
|
}
|
|
|
|
build_host_git() {
|
|
ensure_git_source
|
|
bundle_git_manpages
|
|
|
|
local fingerprint
|
|
fingerprint="$(git_source_fingerprint):host"
|
|
if target_is_current "$HOST_GIT_BINARY" "$HOST_GIT_STAMP" "$fingerprint"; then
|
|
log "Host Git binary is current; skipping rebuild"
|
|
"$HOST_GIT_BINARY" --version
|
|
return
|
|
fi
|
|
|
|
log "Building Git for development host"
|
|
cd "$GIT_SRC_DIR"
|
|
make clean >/dev/null 2>&1 || true
|
|
mapfile -t make_args < <(common_git_make_args)
|
|
make -j"$(nproc 2>/dev/null || printf 4)" "${make_args[@]}" git
|
|
|
|
mkdir -p "$HOST_GIT_DIR"
|
|
cp git "$HOST_GIT_BINARY"
|
|
chmod 755 "$HOST_GIT_BINARY"
|
|
mark_target_current "$HOST_GIT_STAMP" "$fingerprint"
|
|
|
|
log "Host test Git binary: $HOST_GIT_BINARY"
|
|
"$HOST_GIT_BINARY" --version
|
|
cd "$PROJECT_DIR"
|
|
}
|
|
|
|
build_android_git_for_abi() {
|
|
local abi="$1"
|
|
local cc="$2"
|
|
local output_dir="$ANDROID_JNI_DIR/$abi"
|
|
local output_binary="$output_dir/libgit.so"
|
|
local stamp="$output_dir/.source-fingerprint"
|
|
local fingerprint="$3:android:$abi:$cc:$ANDROID_API"
|
|
|
|
require_path "$ANDROID_TOOLBIN/$cc"
|
|
|
|
if target_is_current "$output_binary" "$stamp" "$fingerprint"; then
|
|
log "Android $abi Git binary is current; skipping rebuild"
|
|
ls -lh "$output_binary"
|
|
return
|
|
fi
|
|
|
|
log "Building Git for Android $abi"
|
|
cd "$GIT_SRC_DIR"
|
|
make clean >/dev/null 2>&1 || true
|
|
mapfile -t make_args < <(common_git_make_args)
|
|
make -j"$(nproc 2>/dev/null || printf 4)" \
|
|
uname_S=Android \
|
|
uname_O=Android \
|
|
NO_PTHREADS=YesPlease \
|
|
NO_LIBGEN_H=YesPlease \
|
|
HAVE_DEV_TTY=YesPlease \
|
|
CC="$cc" \
|
|
AR=llvm-ar \
|
|
RANLIB=llvm-ranlib \
|
|
STRIP=llvm-strip \
|
|
"${make_args[@]}" \
|
|
git
|
|
|
|
log "Validating Android $abi binary"
|
|
file git
|
|
readelf -h git | sed -n '1,12p'
|
|
|
|
mkdir -p "$output_dir"
|
|
llvm-strip -s git -o "$output_binary"
|
|
chmod 755 "$output_binary"
|
|
mark_target_current "$stamp" "$fingerprint"
|
|
ls -lh "$output_binary"
|
|
cd "$PROJECT_DIR"
|
|
}
|
|
|
|
build_android_git() {
|
|
ensure_git_source
|
|
bundle_git_manpages
|
|
require_path "$ANDROID_NDK_DIR"
|
|
export PATH="$ANDROID_TOOLBIN:$PATH"
|
|
|
|
local fingerprint
|
|
fingerprint="$(git_source_fingerprint)"
|
|
|
|
build_android_git_for_abi "arm64-v8a" "aarch64-linux-android${ANDROID_API}-clang" "$fingerprint"
|
|
build_android_git_for_abi "armeabi-v7a" "armv7a-linux-androideabi${ANDROID_API}-clang" "$fingerprint"
|
|
build_android_git_for_abi "x86" "i686-linux-android${ANDROID_API}-clang" "$fingerprint"
|
|
build_android_git_for_abi "x86_64" "x86_64-linux-android${ANDROID_API}-clang" "$fingerprint"
|
|
}
|
|
|
|
build_all_git_targets() {
|
|
build_host_git
|
|
build_android_git
|
|
}
|
|
|
|
ensure_sdk_packages() {
|
|
setup_env
|
|
|
|
if required_sdk_packages_present; then
|
|
if have_recent_success_marker; then
|
|
log "Skipping SDK verification/install because all components were confirmed within the last 24 hours"
|
|
else
|
|
log "Required SDK packages are already installed locally"
|
|
mark_successful_check
|
|
fi
|
|
return
|
|
fi
|
|
|
|
if have_recent_success_marker; then
|
|
log "Skipping SDK verification/install because all components were confirmed within the last 24 hours"
|
|
return
|
|
fi
|
|
|
|
log "Accepting Android SDK licenses"
|
|
set +e
|
|
set +o pipefail
|
|
yes | "$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" --licenses >/dev/null
|
|
local license_status=$?
|
|
set -o pipefail
|
|
set -e
|
|
if [ "$license_status" -ne 0 ]; then
|
|
echo "sdkmanager --licenses failed with exit code $license_status" >&2
|
|
exit "$license_status"
|
|
fi
|
|
|
|
log "Installing required Android SDK packages"
|
|
"$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \
|
|
"platform-tools" \
|
|
"platforms;android-35" \
|
|
"build-tools;35.0.0" \
|
|
"$ANDROID_NDK_PACKAGE" \
|
|
"$ANDROID_CMAKE_PACKAGE"
|
|
|
|
mark_successful_check
|
|
}
|
|
|
|
maybe_run_operation() {
|
|
local mode="${1:-}"
|
|
local gradle_task=""
|
|
local artifact_label=""
|
|
local artifact_source=""
|
|
local artifact_target=""
|
|
local should_bump_version="false"
|
|
local should_auto_commit="false"
|
|
local should_compile_host_git="false"
|
|
local should_bundle_manpages="false"
|
|
|
|
case "$mode" in
|
|
--build)
|
|
gradle_task="assembleDebug"
|
|
artifact_label="debug APK"
|
|
artifact_source="$PROJECT_DIR/app/build/outputs/apk/debug/app-debug.apk"
|
|
artifact_target="$PROJECT_DIR/app/build/outputs/apk/debug/githug-android-debug.apk"
|
|
should_bump_version="true"
|
|
should_auto_commit="true"
|
|
should_bundle_manpages="true"
|
|
;;
|
|
--build-release-aab)
|
|
gradle_task="bundleRelease"
|
|
artifact_label="release AAB"
|
|
artifact_source="$PROJECT_DIR/app/build/outputs/bundle/release/app-release.aab"
|
|
artifact_target="$PROJECT_DIR/app/build/outputs/bundle/release/githug-android-release.aab"
|
|
should_bump_version="true"
|
|
should_auto_commit="true"
|
|
should_bundle_manpages="true"
|
|
;;
|
|
--test)
|
|
gradle_task="testDebugUnitTest"
|
|
artifact_label="debug unit tests"
|
|
should_compile_host_git="true"
|
|
;;
|
|
--compile-git)
|
|
build_all_git_targets
|
|
return
|
|
;;
|
|
*)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
setup_env
|
|
if [ "$should_bump_version" = "true" ]; then
|
|
bump_android_version
|
|
fi
|
|
if [ -n "$artifact_source" ]; then
|
|
local version_code
|
|
version_code="$(android_version_code)"
|
|
case "$mode" in
|
|
--build)
|
|
artifact_target="$PROJECT_DIR/app/build/outputs/apk/debug/githug-android-debug-v${version_code}.apk"
|
|
;;
|
|
--build-release-aab)
|
|
artifact_target="$PROJECT_DIR/app/build/outputs/bundle/release/githug-android-release-v${version_code}.aab"
|
|
;;
|
|
esac
|
|
fi
|
|
if [ "$should_compile_host_git" = "true" ]; then
|
|
build_host_git
|
|
export GITHUG_TEST_GIT_BINARY="$HOST_GIT_BINARY"
|
|
fi
|
|
if [ "$should_bundle_manpages" = "true" ]; then
|
|
ensure_git_source
|
|
bundle_git_manpages
|
|
fi
|
|
|
|
log "Running $artifact_label with --no-daemon"
|
|
"$PROJECT_DIR/gradlew" --no-daemon "$gradle_task"
|
|
|
|
if [ -n "$artifact_source" ] && [ -f "$artifact_source" ]; then
|
|
log "Renaming $(basename "$artifact_source") to $(basename "$artifact_target")"
|
|
mv -f "$artifact_source" "$artifact_target"
|
|
upload_build_artifact_if_possible "$artifact_target"
|
|
elif [ -n "$artifact_source" ]; then
|
|
log "Expected build output not found for rename: ${artifact_source#$PROJECT_DIR/}"
|
|
fi
|
|
|
|
if [ "$should_auto_commit" = "true" ]; then
|
|
auto_commit_if_needed
|
|
fi
|
|
|
|
log "Stopping any Gradle daemons just in case"
|
|
"$PROJECT_DIR/gradlew" --stop >/dev/null 2>&1 || true
|
|
}
|
|
|
|
print_usage() {
|
|
cat <<EOF_USAGE
|
|
Usage: bash ./AndroidProjectTooling.sh [--build | --build-release-aab | --test | --compile-git]
|
|
|
|
--build Set up the environment and build the debug APK
|
|
--build-release-aab Set up the environment and build a release Android App Bundle (AAB)
|
|
--test Set up the environment, compile host Git, and run the debug JVM unit tests with it
|
|
--compile-git Compile Git for the development host and all Android target ABIs
|
|
EOF_USAGE
|
|
}
|
|
|
|
validate_args() {
|
|
case "${1:-}" in
|
|
""|--build|--build-release-aab|--test|--compile-git)
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
print_usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main() {
|
|
validate_args "${1:-}"
|
|
|
|
require_tool curl
|
|
require_tool unzip
|
|
require_tool tar
|
|
require_tool git
|
|
require_tool perl
|
|
require_tool make
|
|
require_tool clang
|
|
require_tool pkg-config
|
|
require_tool readelf
|
|
require_tool file
|
|
|
|
ensure_dir "$TMP_DIR"
|
|
ensure_dir "$SDK_DIR"
|
|
ensure_dir "$GRADLE_USER_HOME_DIR"
|
|
|
|
ensure_jdk17
|
|
ensure_cmdline_tools
|
|
ensure_wrapper_jar
|
|
write_local_properties
|
|
ensure_sdk_packages
|
|
maybe_run_operation "${1:-}"
|
|
|
|
log "Environment ready"
|
|
log "Project dir: $PROJECT_DIR"
|
|
log "JDK dir: $JDK_DIR"
|
|
log "SDK dir: $SDK_DIR"
|
|
log "NDK dir: $ANDROID_NDK_DIR"
|
|
log "CMake dir: $ANDROID_CMAKE_DIR"
|
|
log "To compile Git for host and Android ABIs: bash ./AndroidProjectTooling.sh --compile-git"
|
|
log "To build without a background Gradle daemon: ./gradlew --no-daemon assembleDebug"
|
|
log "To set up and build in one step: bash ./AndroidProjectTooling.sh --build"
|
|
log "To set up and build a release AAB in one step: bash ./AndroidProjectTooling.sh --build-release-aab"
|
|
log "To set up and run unit tests with compiled host Git: bash ./AndroidProjectTooling.sh --test"
|
|
}
|
|
|
|
main "$@"
|