Auto-commit after successful build: update app gameplay/UI, improve build setup
Changed files:\nCrossCompileGitForAndroid.sh SetupBuildEnvironment.sh app/build.gradle.kts app/src/main/assets/native-git/arm64-v8a/git app/src/main/java/com/kawomi/githugandroid/GitRuntime.kt
This commit is contained in:
99
CrossCompileGitForAndroid.sh
Normal file
99
CrossCompileGitForAndroid.sh
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$SCRIPT_DIR"
|
||||||
|
SDK_DIR="$PROJECT_DIR/android-sdk"
|
||||||
|
NDK_DIR="$SDK_DIR/ndk/27.2.12479018"
|
||||||
|
TOOLBIN="$NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
||||||
|
TMP_DIR="$PROJECT_DIR/.tmp-android-build"
|
||||||
|
GIT_SRC_DIR="$TMP_DIR/git-src"
|
||||||
|
ASSET_DIR="$PROJECT_DIR/app/src/main/assets/native-git/arm64-v8a"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '\n[%s] %s\n' "cross-compile" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_path() {
|
||||||
|
if [ ! -e "$1" ]; then
|
||||||
|
echo "Required path not found: $1" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_tool() {
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
echo "Missing required tool: $1" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_tool git
|
||||||
|
require_tool make
|
||||||
|
require_tool perl
|
||||||
|
require_tool clang
|
||||||
|
require_tool pkg-config
|
||||||
|
require_tool readelf
|
||||||
|
|
||||||
|
require_path "$NDK_DIR"
|
||||||
|
require_path "$TOOLBIN/aarch64-linux-android24-clang"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
export PATH="$TOOLBIN:$PATH"
|
||||||
|
|
||||||
|
log "Building native Git for Android arm64-v8a"
|
||||||
|
cd "$GIT_SRC_DIR"
|
||||||
|
make clean >/dev/null 2>&1 || true
|
||||||
|
make -j4 \
|
||||||
|
uname_S=Android \
|
||||||
|
uname_O=Android \
|
||||||
|
NO_PTHREADS=YesPlease \
|
||||||
|
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_LIBGEN_H=YesPlease \
|
||||||
|
NO_REGEX=NeedsStartEnd \
|
||||||
|
HAVE_ALLOCA_H=YesPlease \
|
||||||
|
HAVE_PATHS_H=YesPlease \
|
||||||
|
HAVE_DEV_TTY=YesPlease \
|
||||||
|
HAVE_CLOCK_GETTIME=YesPlease \
|
||||||
|
HAVE_CLOCK_MONOTONIC=YesPlease \
|
||||||
|
HAVE_GETDELIM=YesPlease \
|
||||||
|
FREAD_READS_DIRECTORIES=UnfortunatelyYes \
|
||||||
|
CSPRNG_METHOD= \
|
||||||
|
CC=aarch64-linux-android24-clang \
|
||||||
|
AR=llvm-ar \
|
||||||
|
RANLIB=llvm-ranlib \
|
||||||
|
STRIP=llvm-strip \
|
||||||
|
git
|
||||||
|
|
||||||
|
log "Validating the produced binary"
|
||||||
|
file git
|
||||||
|
readelf -h git | sed -n '1,20p'
|
||||||
|
readelf -d git | sed -n '1,40p'
|
||||||
|
|
||||||
|
mkdir -p "$ASSET_DIR"
|
||||||
|
llvm-strip -s git -o "$ASSET_DIR/git"
|
||||||
|
chmod 755 "$ASSET_DIR/git"
|
||||||
|
|
||||||
|
log "Bundled stripped binary at: $ASSET_DIR/git"
|
||||||
|
ls -lh "$ASSET_DIR/git"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -16,6 +16,10 @@ LOCAL_PROPERTIES_PATH="$PROJECT_DIR/local.properties"
|
|||||||
ANDROID_CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
|
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"
|
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"
|
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"
|
||||||
STATE_TTL_SECONDS=86400
|
STATE_TTL_SECONDS=86400
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
@@ -242,7 +246,9 @@ ensure_sdk_packages() {
|
|||||||
if have_recent_success_marker \
|
if have_recent_success_marker \
|
||||||
&& [ -d "$SDK_DIR/platform-tools" ] \
|
&& [ -d "$SDK_DIR/platform-tools" ] \
|
||||||
&& [ -d "$SDK_DIR/platforms/android-34" ] \
|
&& [ -d "$SDK_DIR/platforms/android-34" ] \
|
||||||
&& [ -d "$SDK_DIR/build-tools/34.0.0" ]; then
|
&& [ -d "$SDK_DIR/build-tools/34.0.0" ] \
|
||||||
|
&& [ -d "$ANDROID_NDK_DIR" ] \
|
||||||
|
&& [ -d "$ANDROID_CMAKE_DIR" ]; then
|
||||||
log "Skipping SDK verification/install because all components were confirmed within the last 24 hours"
|
log "Skipping SDK verification/install because all components were confirmed within the last 24 hours"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -263,7 +269,9 @@ ensure_sdk_packages() {
|
|||||||
"$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \
|
"$CMDLINE_TOOLS_LATEST_DIR/bin/sdkmanager" --sdk_root="$SDK_DIR" \
|
||||||
"platform-tools" \
|
"platform-tools" \
|
||||||
"platforms;android-34" \
|
"platforms;android-34" \
|
||||||
"build-tools;34.0.0"
|
"build-tools;34.0.0" \
|
||||||
|
"$ANDROID_NDK_PACKAGE" \
|
||||||
|
"$ANDROID_CMAKE_PACKAGE"
|
||||||
|
|
||||||
mark_successful_check
|
mark_successful_check
|
||||||
}
|
}
|
||||||
@@ -286,6 +294,12 @@ main() {
|
|||||||
require_tool curl
|
require_tool curl
|
||||||
require_tool unzip
|
require_tool unzip
|
||||||
require_tool tar
|
require_tool tar
|
||||||
|
require_tool git
|
||||||
|
require_tool perl
|
||||||
|
require_tool make
|
||||||
|
require_tool clang
|
||||||
|
require_tool pkg-config
|
||||||
|
require_tool readelf
|
||||||
|
|
||||||
ensure_dir "$TMP_DIR"
|
ensure_dir "$TMP_DIR"
|
||||||
ensure_dir "$SDK_DIR"
|
ensure_dir "$SDK_DIR"
|
||||||
@@ -301,6 +315,9 @@ main() {
|
|||||||
log "Project dir: $PROJECT_DIR"
|
log "Project dir: $PROJECT_DIR"
|
||||||
log "JDK dir: $JDK_DIR"
|
log "JDK dir: $JDK_DIR"
|
||||||
log "SDK dir: $SDK_DIR"
|
log "SDK dir: $SDK_DIR"
|
||||||
|
log "NDK dir: $ANDROID_NDK_DIR"
|
||||||
|
log "CMake dir: $ANDROID_CMAKE_DIR"
|
||||||
|
log "To cross-compile Git for Android arm64-v8a: bash ./CrossCompileGitForAndroid.sh"
|
||||||
log "To build without a background Gradle daemon: ./gradlew --no-daemon assembleDebug"
|
log "To build without a background Gradle daemon: ./gradlew --no-daemon assembleDebug"
|
||||||
log "To setup and build in one step: bash ./SetupBuildEnvironment.sh --build"
|
log "To setup and build in one step: bash ./SetupBuildEnvironment.sh --build"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "com.kawomi.githugandroid"
|
applicationId = "com.kawomi.githugandroid"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 9
|
versionCode = 10
|
||||||
versionName = "0.1.8"
|
versionName = "0.1.9"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|||||||
BIN
app/src/main/assets/native-git/arm64-v8a/git
Executable file
BIN
app/src/main/assets/native-git/arm64-v8a/git
Executable file
Binary file not shown.
@@ -1,21 +1,23 @@
|
|||||||
package com.kawomi.githugandroid
|
package com.kawomi.githugandroid
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class GitRepositoryRuntime(private val context: Context) {
|
class GitRepositoryRuntime(private val context: Context) {
|
||||||
private val sandboxesRoot = File(context.filesDir, "githug-sandboxes")
|
private val sandboxesRoot = File(context.filesDir, "githug-sandboxes")
|
||||||
|
private val extractedGitDir = File(context.filesDir, "native-git/bin")
|
||||||
|
|
||||||
fun startupBanner(): String {
|
fun startupBanner(): String {
|
||||||
return if (nativeGitBinary() != null) {
|
return if (ensureNativeGitBinary() != null) {
|
||||||
"Welcome to GitHug Android. Native Git prototype ready."
|
"Welcome to GitHug Android. Native Git prototype ready."
|
||||||
} else {
|
} else {
|
||||||
"Welcome to GitHug Android. Native Git prototype scaffolded; using in-memory fallback until a bundled Git binary is available."
|
"Welcome to GitHug Android. Native Git binary not bundled for this ABI yet; using in-memory fallback."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun prepareLevel(level: Level): RepoState {
|
fun prepareLevel(level: Level): RepoState {
|
||||||
val nativeGit = nativeGitBinary()
|
val nativeGit = ensureNativeGitBinary()
|
||||||
if (nativeGit == null) {
|
if (nativeGit == null) {
|
||||||
return level.setup()
|
return level.setup()
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,7 @@ class GitRepositoryRuntime(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun execute(level: Level, currentRepo: RepoState, command: String): Pair<RepoState, List<String>> {
|
fun execute(level: Level, currentRepo: RepoState, command: String): Pair<RepoState, List<String>> {
|
||||||
val nativeGit = nativeGitBinary()
|
val nativeGit = ensureNativeGitBinary()
|
||||||
if (nativeGit == null) {
|
if (nativeGit == null) {
|
||||||
return GitSandboxEngine.execute(currentRepo, command)
|
return GitSandboxEngine.execute(currentRepo, command)
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,8 @@ class GitRepositoryRuntime(private val context: Context) {
|
|||||||
return buildList {
|
return buildList {
|
||||||
addAll(GitSandboxEngine.commandReferenceLines())
|
addAll(GitSandboxEngine.commandReferenceLines())
|
||||||
add("Native Git prototype:")
|
add("Native Git prototype:")
|
||||||
add(" bundled binary path: files/native-git/bin/git")
|
add(" extracted binary path: files/native-git/bin/git")
|
||||||
|
add(" selected ABI: ${Build.SUPPORTED_ABIS.firstOrNull() ?: "unknown"}")
|
||||||
add(" helper commands: ls, pwd, cat, touch, mkdir, rm, echo")
|
add(" helper commands: ls, pwd, cat, touch, mkdir, rm, echo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +132,7 @@ class GitRepositoryRuntime(private val context: Context) {
|
|||||||
|
|
||||||
private fun inspectSandbox(level: Level): RepoState {
|
private fun inspectSandbox(level: Level): RepoState {
|
||||||
val sandbox = sandboxDir(level)
|
val sandbox = sandboxDir(level)
|
||||||
val nativeGit = nativeGitBinary()
|
val nativeGit = ensureNativeGitBinary()
|
||||||
val filesOnDisk = sandbox.listFiles()
|
val filesOnDisk = sandbox.listFiles()
|
||||||
?.filter { it.isFile && it.name != ".git" }
|
?.filter { it.isFile && it.name != ".git" }
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
@@ -177,12 +180,27 @@ class GitRepositoryRuntime(private val context: Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nativeGitBinary(): File? {
|
private fun ensureNativeGitBinary(): File? {
|
||||||
val candidates = listOf(
|
val extracted = File(extractedGitDir, "git")
|
||||||
File(context.filesDir, "native-git/bin/git"),
|
if (extracted.exists() && extracted.canExecute()) {
|
||||||
File(context.filesDir, "git/bin/git"),
|
return extracted
|
||||||
)
|
}
|
||||||
return candidates.firstOrNull { it.exists() && it.canExecute() }
|
|
||||||
|
val abi = Build.SUPPORTED_ABIS.firstOrNull() ?: return null
|
||||||
|
val assetPath = "native-git/$abi/git"
|
||||||
|
|
||||||
|
return try {
|
||||||
|
extractedGitDir.mkdirs()
|
||||||
|
context.assets.open(assetPath).use { input ->
|
||||||
|
extracted.outputStream().use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extracted.setExecutable(true)
|
||||||
|
extracted.takeIf { it.canExecute() }
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sandboxDir(level: Level): File = File(sandboxesRoot, level.id)
|
private fun sandboxDir(level: Level): File = File(sandboxesRoot, level.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user