diff --git a/.github/workflows/attach_debug_apks_to_release.yml b/.github/workflows/attach_debug_apks_to_release.yml index c27cbf23e9..5c95e788ba 100644 --- a/.github/workflows/attach_debug_apks_to_release.yml +++ b/.github/workflows/attach_debug_apks_to_release.yml @@ -8,8 +8,13 @@ on: jobs: attach-apks: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + package_variant: [ apt-android-7, apt-android-5 ] env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: - name: Clone repository uses: actions/checkout@v2 @@ -18,6 +23,8 @@ jobs: - name: Build and attach APKs to release shell: bash {0} + env: + PACKAGE_VARIANT: ${{ matrix.package_variant }} run: | exit_on_error() { echo "$1" @@ -34,13 +41,14 @@ jobs: fi APK_DIR_PATH="./app/build/outputs/apk/debug" - APK_VERSION_TAG="$RELEASE_VERSION_NAME+github-debug" + APK_VERSION_TAG="$RELEASE_VERSION_NAME+${{ env.PACKAGE_VARIANT }}-github-debug" APK_BASENAME_PREFIX="termux-app_$APK_VERSION_TAG" - echo "Building APKs for '$RELEASE_VERSION_NAME' release" + echo "Building APKs for 'APK_VERSION_TAG' release" export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle + export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}" # Used by app/build.gradle if ! ./gradlew assembleDebug; then - exit_on_error "Build failed for '$RELEASE_VERSION_NAME' release." + exit_on_error "Build failed for '$APK_VERSION_TAG' release." fi echo "Validating APKs" @@ -58,8 +66,8 @@ jobs: "${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \ "${APK_BASENAME_PREFIX}_x86_64.apk" \ "${APK_BASENAME_PREFIX}_x86.apk" \ - > sha256sums); then - exit_on_error "Generate sha25sums failed for '$RELEASE_VERSION_NAME' release." + > "${APK_BASENAME_PREFIX}_sha256sums"); then + exit_on_error "Generate sha25sums failed for '$APK_VERSION_TAG' release." fi echo "Attaching APKs to github release" @@ -70,7 +78,7 @@ jobs: -a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \ -a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86_64.apk" \ -a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86.apk" \ - -a "$APK_DIR_PATH/sha256sums" \ + -a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_sha256sums" \ "$RELEASE_VERSION_NAME"; then - exit_on_error "Attach APKs to release failed for '$RELEASE_VERSION_NAME' release." + exit_on_error "Attach APKs to release failed for '$APK_VERSION_TAG' release." fi diff --git a/.github/workflows/debug_build.yml b/.github/workflows/debug_build.yml index 2e81829374..efd08e8de7 100644 --- a/.github/workflows/debug_build.yml +++ b/.github/workflows/debug_build.yml @@ -11,12 +11,19 @@ on: jobs: build: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + package_variant: [ apt-android-7, apt-android-5 ] + steps: - name: Clone repository uses: actions/checkout@v2 - name: Build APKs shell: bash {0} + env: + PACKAGE_VARIANT: ${{ matrix.package_variant }} run: | exit_on_error() { echo "$1"; exit 1; } @@ -35,7 +42,7 @@ jobs: fi APK_DIR_PATH="./app/build/outputs/apk/debug" - APK_VERSION_TAG="$RELEASE_VERSION_NAME-github-debug" # Note the "-", GITHUB_SHA will already have "+" before it + APK_VERSION_TAG="$RELEASE_VERSION_NAME-${{ env.PACKAGE_VARIANT }}-github-debug" # Note the "-", GITHUB_SHA will already have "+" before it APK_BASENAME_PREFIX="termux-app_$APK_VERSION_TAG" # Used by attachment steps later @@ -43,11 +50,12 @@ jobs: echo "APK_VERSION_TAG=$APK_VERSION_TAG" >> $GITHUB_ENV echo "APK_BASENAME_PREFIX=$APK_BASENAME_PREFIX" >> $GITHUB_ENV - echo "Building APKs for '$RELEASE_VERSION_NAME' build" + echo "Building APKs for 'APK_VERSION_TAG' build" export TERMUX_APP_VERSION_NAME="${RELEASE_VERSION_NAME/v/}" # Used by app/build.gradle export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle + export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}" # Used by app/build.gradle if ! ./gradlew assembleDebug; then - exit_on_error "Build failed for '$RELEASE_VERSION_NAME' build." + exit_on_error "Build failed for '$APK_VERSION_TAG' build." fi echo "Validating APKs" @@ -65,8 +73,8 @@ jobs: "${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \ "${APK_BASENAME_PREFIX}_x86_64.apk" \ "${APK_BASENAME_PREFIX}_x86.apk" \ - > sha256sums); then - exit_on_error "Generate sha25sums failed for '$RELEASE_VERSION_NAME' release." + > "${APK_BASENAME_PREFIX}_sha256sums"); then + exit_on_error "Generate sha25sums failed for '$APK_VERSION_TAG' release." fi - name: Attach universal APK file @@ -112,7 +120,7 @@ jobs: - name: Attach sha256sums file uses: actions/upload-artifact@v2 with: - name: sha256sums + name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums path: | - ${{ env.APK_DIR_PATH }}/sha256sums + ${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}_sha256sums ${{ env.APK_DIR_PATH }}/output-metadata.json diff --git a/app/build.gradle b/app/build.gradle index a4fe8b3153..628dae01f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,16 @@ plugins { id "com.android.application" } +ext { + // The packageVariant defines the bootstrap variant that will be included in the app APK. + // This must be supported by com.termux.shared.termux.TermuxBootstrap.PackageVariant or app will + // crash at startup. + // Bootstrap of a different variant must not be manually installed by the user after app installation + // by replacing $PREFIX since app code is dependant on the variant used to build the APK. + // Currently supported values are: [ "apt-android-7" ] + packageVariant = System.getenv("TERMUX_PACKAGE_VARIANT") ?: "apt-android-7" // Default: "apt-android-7" +} + android { compileSdkVersion project.properties.compileSdkVersion.toInteger() ndkVersion = System.getenv("JITPACK_NDK_VERSION") ?: project.properties.ndkVersion @@ -37,6 +47,8 @@ android { if (appVersionName) versionName = appVersionName validateVersionName(versionName) + buildConfigField "String", "TERMUX_PACKAGE_VARIANT", "\"" + project.ext.packageVariant + "\"" // Used by TermuxApplication class + manifestPlaceholders.TERMUX_PACKAGE_NAME = "com.termux" manifestPlaceholders.TERMUX_APP_NAME = "Termux" manifestPlaceholders.TERMUX_API_APP_NAME = "Termux:API" @@ -115,10 +127,10 @@ android { variant.outputs.all { output -> if (variant.buildType.name == "debug") { def abi = output.getFilter(com.android.build.OutputFile.ABI) - outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : "debug") + "_" + (abi ? abi : "universal") + ".apk") + outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : project.ext.packageVariant + "-" + "debug") + "_" + (abi ? abi : "universal") + ".apk") } else if (variant.buildType.name == "release") { def abi = output.getFilter(com.android.build.OutputFile.ABI) - outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : "release") + "_" + (abi ? abi : "universal") + ".apk") + outputFileName = new File("termux-app_" + (apkVersionTag ? apkVersionTag : project.ext.packageVariant + "-" + "release") + "_" + (abi ? abi : "universal") + ".apk") } } } @@ -161,7 +173,7 @@ def downloadBootstrap(String arch, String expectedChecksum, String version) { if (checksum == expectedChecksum) { return } else { - logger.quiet("Deleting old local file with wrong hash: " + localUrl) + logger.quiet("Deleting old local file with wrong hash: " + localUrl + ": expected: " + expectedChecksum + ", actual: " + checksum) file.delete() } } @@ -196,11 +208,16 @@ clean { task downloadBootstraps() { doLast { - def version = "2022.04.22-r1" - downloadBootstrap("aarch64", "ec8a6043644594fc24681cffaf9c7b32f5bc68df7491c5df9a060e40e1934c70", version) - downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version) - downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version) - downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version) + def packageVariant = project.ext.packageVariant + if (packageVariant == "apt-android-7") { + def version = "2022.04.22-r1" + "+" + packageVariant + downloadBootstrap("aarch64", "ec8a6043644594fc24681cffaf9c7b32f5bc68df7491c5df9a060e40e1934c70", version) + downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version) + downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version) + downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version) + } else { + throw new GradleException("Unsupported TERMUX_PACKAGE_VARIANT \"" + packageVariant + "\"") + } } } diff --git a/app/src/main/java/com/termux/app/TermuxApplication.java b/app/src/main/java/com/termux/app/TermuxApplication.java index 78a4bf520b..1d7925f78a 100644 --- a/app/src/main/java/com/termux/app/TermuxApplication.java +++ b/app/src/main/java/com/termux/app/TermuxApplication.java @@ -3,8 +3,10 @@ import android.app.Application; import android.content.Context; +import com.termux.BuildConfig; import com.termux.shared.errors.Error; import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxBootstrap; import com.termux.shared.termux.TermuxConstants; import com.termux.shared.termux.crash.TermuxCrashUtils; import com.termux.shared.termux.file.TermuxFileUtils; @@ -30,6 +32,9 @@ public void onCreate() { Logger.logDebug("Starting Application"); + // Set TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER and TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT + TermuxBootstrap.setTermuxPackageManagerAndVariant(BuildConfig.TERMUX_PACKAGE_VARIANT); + // Init app wide SharedProperties loaded from termux.properties TermuxAppSharedProperties properties = TermuxAppSharedProperties.init(context); diff --git a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java index 47e7debf44..1a3a8c3d8c 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -23,6 +23,7 @@ import com.termux.shared.interact.MessageDialogUtils; import com.termux.shared.interact.ShareUtils; import com.termux.shared.shell.ShellUtils; +import com.termux.shared.termux.TermuxBootstrap; import com.termux.shared.termux.terminal.TermuxTerminalViewClientBase; import com.termux.shared.termux.extrakeys.SpecialButton; import com.termux.shared.android.AndroidUtils; @@ -756,9 +757,11 @@ public void run() { reportString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(mActivity)); - String termuxAptInfo = TermuxUtils.geAPTInfoMarkdownString(mActivity); - if (termuxAptInfo != null) - reportString.append("\n\n").append(termuxAptInfo); + if (TermuxBootstrap.isAppPackageManagerAPT()) { + String termuxAptInfo = TermuxUtils.geAPTInfoMarkdownString(mActivity); + if (termuxAptInfo != null) + reportString.append("\n\n").append(termuxAptInfo); + } if (addTermuxDebugInfo) { String termuxDebugInfo = TermuxUtils.getTermuxDebugMarkdownString(mActivity); diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java new file mode 100644 index 0000000000..7480dcff85 --- /dev/null +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java @@ -0,0 +1,174 @@ +package com.termux.shared.termux; + +import androidx.annotation.Nullable; + +import com.termux.shared.logger.Logger; + +public class TermuxBootstrap { + + private static final String LOG_TAG = "TermuxBootstrap"; + + /** The {@link PackageManager} for the bootstrap in the app APK added in app/build.gradle. */ + public static PackageManager TERMUX_APP_PACKAGE_MANAGER; + + /** The {@link PackageVariant} for the bootstrap in the app APK added in app/build.gradle. */ + public static PackageVariant TERMUX_APP_PACKAGE_VARIANT; + + /** Set name as app wide night mode value. */ + public static void setTermuxPackageManagerAndVariant(@Nullable String packageVariantName) { + TERMUX_APP_PACKAGE_VARIANT = PackageVariant.variantOf(packageVariantName); + if (TERMUX_APP_PACKAGE_VARIANT == null) { + throw new RuntimeException("Unsupported TERMUX_APP_PACKAGE_VARIANT \"" + packageVariantName + "\""); + } + + Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_VARIANT to \"" + TERMUX_APP_PACKAGE_VARIANT + "\""); + + // Set packageManagerName to substring before first dash "-" in packageVariantName + int index = packageVariantName.indexOf('-'); + String packageManagerName = (index == -1) ? null : packageVariantName.substring(0, index); + TERMUX_APP_PACKAGE_MANAGER = PackageManager.managerOf(packageManagerName); + if (TERMUX_APP_PACKAGE_MANAGER == null) { + throw new RuntimeException("Unsupported TERMUX_APP_PACKAGE_MANAGER \"" + packageManagerName + "\" with variant \"" + packageVariantName + "\""); + } + + Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_MANAGER to \"" + TERMUX_APP_PACKAGE_MANAGER + "\""); + } + + + + /** Is {@link PackageManager#APT} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */ + public static boolean isAppPackageManagerAPT() { + return PackageManager.APT.equals(TERMUX_APP_PACKAGE_MANAGER); + } + + ///** Is {@link PackageManager#TAPM} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */ + //public static boolean isAppPackageManagerTAPM() { + // return PackageManager.TAPM.equals(TERMUX_APP_PACKAGE_MANAGER); + //} + + ///** Is {@link PackageManager#PACMAN} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */ + //public static boolean isAppPackageManagerPACMAN() { + // return PackageManager.PACMAN.equals(TERMUX_APP_PACKAGE_MANAGER); + //} + + + + /** Is {@link PackageVariant#APT_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ + public static boolean isAppPackageVariantAPTAndroid7() { + return PackageVariant.APT_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT); + } + + ///** Is {@link PackageVariant#APT_ANDROID_5} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ + //public static boolean isAppPackageVariantAPTAndroid5() { + // return PackageVariant.APT_ANDROID_5.equals(TERMUX_APP_PACKAGE_VARIANT); + //} + + ///** Is {@link PackageVariant#TAPM_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ + //public static boolean isAppPackageVariantTAPMAndroid7() { + // return PackageVariant.TAPM_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT); + //} + + ///** Is {@link PackageVariant#PACMAN_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ + //public static boolean isAppPackageVariantTPACMANAndroid7() { + // return PackageVariant.PACMAN_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT); + //} + + + + /** Termux package manager. */ + public enum PackageManager { + + /** + * Advanced Package Tool (APT) for managing debian deb package files. + * https://wiki.debian.org/Apt + * https://wiki.debian.org/deb + */ + APT("apt"); + + ///** + // * Termux Android Package Manager (TAPM) for managing termux apk package files. + // * https://en.wikipedia.org/wiki/Apk_(file_format) + // */ + //TAPM("tapm"); + + ///** + // * Package Manager (PACMAN) for managing arch linux pkg.tar package files. + // * https://wiki.archlinux.org/title/pacman + // * https://en.wikipedia.org/wiki/Arch_Linux#Pacman + // */ + //PACMAN("pacman"); + + private final String name; + + PackageManager(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean equalsManager(String manager) { + return manager != null && manager.equals(this.name); + } + + /** Get {@link PackageManager} for {@code name} if found, otherwise {@code null}. */ + @Nullable + public static PackageManager managerOf(String name) { + if (name == null || name.isEmpty()) return null; + for (PackageManager v : PackageManager.values()) { + if (v.name.equals(name)) { + return v; + } + } + return null; + } + + } + + + + /** Termux package variant. The substring before first dash "-" must match one of the {@link PackageManager}. */ + public enum PackageVariant { + + /** {@link PackageManager#APT} variant for Android 7+. */ + APT_ANDROID_7("apt-android-7"); + + ///** {@link PackageManager#APT} variant for Android 5+. */ + //APT_ANDROID_5("apt-android-5"); + + ///** {@link PackageManager#TAPM} variant for Android 7+. */ + //TAPM_ANDROID_7("tapm-android-7"); + + ///** {@link PackageManager#PACMAN} variant for Android 7+. */ + //PACMAN_ANDROID_7("pacman-android-7"); + + private final String name; + + PackageVariant(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean equalsVariant(String variant) { + return variant != null && variant.equals(this.name); + } + + /** Get {@link PackageVariant} for {@code name} if found, otherwise {@code null}. */ + @Nullable + public static PackageVariant variantOf(String name) { + if (name == null || name.isEmpty()) return null; + for (PackageVariant v : PackageVariant.values()) { + if (v.name.equals(name)) { + return v; + } + } + return null; + } + + } + +} diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java index 333dc0fe3e..b5fdf91217 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java @@ -397,6 +397,11 @@ public static String getAppInfoMarkdownStringInner(@NonNull final Context contex markdownString.append((AndroidUtils.getAppInfoMarkdownString(context))); + if (context.getPackageName().equals(TermuxConstants.TERMUX_PACKAGE_NAME)) { + AndroidUtils.appendPropertyToMarkdown(markdownString, "TERMUX_APP_PACKAGE_MANAGER", TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER); + AndroidUtils.appendPropertyToMarkdown(markdownString, "TERMUX_APP_PACKAGE_VARIANT", TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT); + } + Error error; error = TermuxFileUtils.isTermuxFilesDirectoryAccessible(context, true, true); if (error != null) { diff --git a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java index 8ac6d2586f..d20208b54f 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java @@ -6,6 +6,7 @@ import com.termux.shared.errors.Error; import com.termux.shared.file.filesystem.FileTypes; +import com.termux.shared.termux.TermuxBootstrap; import com.termux.shared.termux.TermuxConstants; import com.termux.shared.file.FileUtils; import com.termux.shared.logger.Logger; @@ -61,6 +62,10 @@ public static String[] buildEnvironment(Context currentPackageContext, boolean i environment.add("TERMUX_APP_PID=" + TERMUX_APP_PID); if (TERMUX_APK_RELEASE != null) environment.add("TERMUX_APK_RELEASE=" + TERMUX_APK_RELEASE); + if (TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER != null) + environment.add("TERMUX_APP_PACKAGE_MANAGER=" + TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER.getName()); + if (TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT != null) + environment.add("TERMUX_APP_PACKAGE_VARIANT=" + TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName()); if (TERMUX_APP_AM_SOCKET_SERVER_ENABLED != null) environment.add("TERMUX_APP_AM_SOCKET_SERVER_ENABLED=" + TERMUX_APP_AM_SOCKET_SERVER_ENABLED);