From 9b17344bc58272f248a2f419ef2cb1359bde6510 Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 12:24:13 +0200 Subject: [PATCH 1/6] env: add better diagnose option via `is_managable/0` for when `sdkmanager` is broken or missing --- .github/workflows/matrix_ci.yml | 6 +-- android/env/env.v | 63 ++++++++++++++++++---- cli/cli.v | 1 + cli/doctor.v | 28 ++++------ cli/options.v | 1 + tests/at-runtime/emulator/emulator_test.vv | 2 +- 6 files changed, 70 insertions(+), 31 deletions(-) diff --git a/.github/workflows/matrix_ci.yml b/.github/workflows/matrix_ci.yml index 00429b4..ca1bb2a 100644 --- a/.github/workflows/matrix_ci.yml +++ b/.github/workflows/matrix_ci.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] + os: [ubuntu-24.04] java-version: [11,15,20] android-api: [31, 33] fail-fast: false @@ -101,7 +101,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] + os: [ubuntu-24.04] java-version: [11, 15, 20] android-api: [31, 33] fail-fast: false @@ -166,7 +166,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] + os: [ubuntu-24.04] java-version: [8] # 9, 10 is in a bad state currently android-api: [31, 33] fail-fast: false diff --git a/android/env/env.v b/android/env/env.v index fa2ab8a..55f1099 100644 --- a/android/env/env.v +++ b/android/env/env.v @@ -24,6 +24,7 @@ pub const accepted_components = ['auto', 'cmdline-tools', 'platform-tools', 'ndk // build-tools - Version where apksigner is included from @[deprecated: 'use get_default_components() instead'] +@[deprecated_after: '2027-01-01'] pub const default_components = { 'cmdline-tools': { 'name': 'cmdline-tools' @@ -154,6 +155,9 @@ pub fn (io &InstallOptions) verbose(verbosity_level int, msg string) { } } +// managable returns `true` if the host system's SDK can be managed by `vab`. +@[deprecated: 'use "is_managable() or { false }" instead'] +@[deprecated_after: '2027-07-20'] pub fn managable() bool { sdk_is_writable := os.is_writable(sdk.root()) // sdkmanager checks @@ -199,7 +203,55 @@ pub fn managable() bool { return sdk_is_writable && has_sdkmanager && sdkmanger_works } +// is_managable returns `true` if the host system's SDK can be managed by `vab`, an error with +// details is returned otherwise. +pub fn is_managable() !bool { + if !os.is_writable(sdk.root()) { + return error('No permission to write in Android SDK root. Please install manually or ensure write access to "${sdk.root()}".') + } + + // sdkmanager checks + sdkm := sdkmanager() + if sdkm == '' { + return error('An executable `sdkmanager` seems to be missing.') + } + // We have detected `sdkmanager` - but does it work with the Java version? *sigh* + // Android development will let us find out I guess: + cmd := [ + sdkm, + '--list', + ] + mut cmd_res := util.run(cmd) + if cmd_res.exit_code > 0 { + // Failed let's try a workaround from stackoverflow: + // https://stackoverflow.com/a/51644855/1904615 + if 'windows' == os.user_os() { + util.run([ + 'set JAVA_OPTS=-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee', + ]) + util.run([ + 'set JAVA_OPTS=-XX:+IgnoreUnrecognizedVMOptions --add-modules java.xml.bind', + ]) + } else { + util.run([ + "export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee'", + ]) + util.run([ + "export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.xml.bind'", + ]) + } + // Let try again + cmd_res = util.run(cmd) + if cmd_res.exit_code != 0 { + return error('The detected `sdkmanager` seems outdated or incompatible with the Java version used. Manual intervention is needed.\nPath: "${sdkmanager()}"\nVersion: ${sdkmanager_version()}\nOutput: ${cmd_res.output}') + } + // Give up trying to fix this horrible eco-system + } + return true +} + @[deprecated: 'use install_components instead'] +@[deprecated_after: '2027-01-01'] pub fn install(components string, verbosity int) int { mut iopts := []InstallOptions{} mut ensure_sdk := true @@ -500,16 +552,9 @@ pub fn install_components(arguments []string, verbosity int) ! { fn install_opt(opt InstallOptions) !bool { loose := opt.dep == .bundletool || opt.dep == .aapt2 - if !loose && !managable() { - if !os.is_writable(sdk.root()) { - return error(@MOD + '.' + @FN + ' ' + - 'No permission to write in Android SDK root. Please install manually or ensure write access to "${sdk.root()}".') - } else { - return error(@MOD + '.' + @FN + ' ' + - 'The `sdkmanager` seems outdated or incompatible with the Java version used". Please fix your setup manually.\nPath: "${sdkmanager()}"\nVersion: ${sdkmanager_version()}') - } + if !loose { + is_managable()! } - // Accept all SDK licenses $if windows { os.mkdir_all(work_path) or {} diff --git a/cli/cli.v b/cli/cli.v index 1ab59c8..360d12f 100644 --- a/cli/cli.v +++ b/cli/cli.v @@ -111,6 +111,7 @@ pub fn input_from_args(arguments []string) (string, []string) { // args_to_options returns an `Option` merged from (CLI/Shell) `arguments` using `defaults` as // values where no value can be obtained from `arguments`. @[deprecated: 'use options_from_arguments and run_vab_sub_command instead'] +@[deprecated_after: '2027-01-01'] pub fn args_to_options(arguments []string, defaults Options) !(Options, &flag.FlagParser) { mut args := arguments.clone() diff --git a/cli/doctor.v b/cli/doctor.v index 35ea4c0..0230499 100644 --- a/cli/doctor.v +++ b/cli/doctor.v @@ -14,7 +14,16 @@ import vab.android.env // diagnosticing the work environment. pub fn doctor(opt Options) { sdkm := env.sdkmanager() - env_managable := env.managable() + env_managable := env.is_managable() or { + util.vab_notice('${err.msg()}', + details: 'For `${exe_short_name}` to control it\'s own dependencies, please update `sdkmanager` found in: +"${sdkm}" +or use a Java version that is compatible with your `sdkmanager`. +You can set the `SDKMANAGER` env variable or try your luck with `${exe_short_name} install auto`. +See https://stackoverflow.com/a/61176718/1904615 for more help.\n' + ) + false + } env_vars := os.environ() // Validate Android `sdkmanager` tool @@ -31,23 +40,6 @@ pub fn doctor(opt Options) { See https://stackoverflow.com/a/61176718/1904615 for more help.\n' } util.vab_notice('No "sdkmanager" could be detected.', details) - } else { - if !env_managable { - sdk_is_writable := os.is_writable(sdk.root()) - if !sdk_is_writable { - util.vab_notice('The SDK at "${sdk.root()}" is not writable.', - details: "`${exe_short_name}` is not able to control the SDK and it's dependencies." - ) - } else { - util.vab_notice('The detected `sdkmanager` seems outdated or incompatible with the Java version used.', - details: 'For `${exe_short_name}` to control it\'s own dependencies, please update `sdkmanager` found in: -"${sdkm}" -or use a Java version that is compatible with your `sdkmanager`. -You can set the `SDKMANAGER` env variable or try your luck with `${exe_short_name} install auto`. -See https://stackoverflow.com/a/61176718/1904615 for more help.\n' - ) - } - } } avdmanager := env.avdmanager() diff --git a/cli/options.v b/cli/options.v index 19e0da5..d9df70b 100644 --- a/cli/options.v +++ b/cli/options.v @@ -428,6 +428,7 @@ fn (mut o Options) merge_additional_args(default_additional_args []string) { // extend_from_dot_vab will merge the `Options` with any content // found in any `.vab` config files. @[deprecated: 'use options_from_dot_vab instead'] +@[deprecated_after: '2027-01-01'] pub fn (mut opt Options) extend_from_dot_vab() { // Look up values in input .vab file next to input if no flags or defaults was set dot_vab_file := dot_vab_path(opt.input) diff --git a/tests/at-runtime/emulator/emulator_test.vv b/tests/at-runtime/emulator/emulator_test.vv index c2b36c1..a4e57a5 100644 --- a/tests/at-runtime/emulator/emulator_test.vv +++ b/tests/at-runtime/emulator/emulator_test.vv @@ -26,7 +26,7 @@ const test_v_examples = [ 'gg/worker_thread.v', ] -const env_is_managable = env.managable() +const env_is_managable = env.is_managable() or { false } const is_ci = os.getenv('CI') != '' From c3e10d4326e0a258b7a584a892a88ea5c2774fb1 Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 12:35:34 +0200 Subject: [PATCH 2/6] ci: try fix `sdkmanager` mayhem attempt #1 --- .github/workflows/matrix_ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/matrix_ci.yml b/.github/workflows/matrix_ci.yml index ca1bb2a..22d05ad 100644 --- a/.github/workflows/matrix_ci.yml +++ b/.github/workflows/matrix_ci.yml @@ -23,7 +23,7 @@ jobs: fail-fast: false timeout-minutes: 20 env: - VAB_FLAGS: -v 3 --build-tools 29.0.0 + VAB_FLAGS: -v 3 steps: - uses: actions/setup-java@v4 with: @@ -67,9 +67,6 @@ jobs: vab install bundletool vab install aapt2 - - name: Run vab install build-tools - run: vab install "build-tools;29.0.0" - - name: Run vab doctor2 run: vab doctor @@ -107,7 +104,7 @@ jobs: fail-fast: false timeout-minutes: 20 env: - VAB_FLAGS: -v 3 -gc none --build-tools 29.0.0 + VAB_FLAGS: -v 3 -gc none steps: - uses: actions/setup-java@v4 with: From 7c838bb9bc2c1cb5aa3c0d977bd91e42dd9ff15a Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 12:56:23 +0200 Subject: [PATCH 3/6] ci: try fix `sdkmanager` mayhem attempt #2 --- .github/workflows/matrix_ci.yml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/matrix_ci.yml b/.github/workflows/matrix_ci.yml index 22d05ad..acfd12e 100644 --- a/.github/workflows/matrix_ci.yml +++ b/.github/workflows/matrix_ci.yml @@ -23,7 +23,7 @@ jobs: fail-fast: false timeout-minutes: 20 env: - VAB_FLAGS: -v 3 + VAB_FLAGS: -v 3 --build-tools 29.0.0 steps: - uses: actions/setup-java@v4 with: @@ -55,7 +55,20 @@ jobs: - name: Run vab --help run: vab --help - - name: Run vab doctor + - name: Run 'vab doctor' before install + run: vab doctor + + # It is a sisyphus task to get all combinations of the preinstalled SDK / tools and Java working + # so we simply destroy the env and use our own base-setup via 'vab install auto'... + - name: Setup predictable Android environment + run: | + sudo rm -fr /usr/local/lib/android # location of pre-installed SDK on Ubuntu + unset ANDROID_SDK_ROOT # These are set in the CI by default + unset ANDROID_HOME + unset ANDROID_NDK_ROOT + vab install auto + + - name: Run 'vab doctor' after install run: vab doctor - name: Run tests @@ -67,12 +80,14 @@ jobs: vab install bundletool vab install aapt2 - - name: Run vab doctor2 + - name: Run vab install build-tools + run: vab install "build-tools;29.0.0" + + - name: Run 'vab doctor' after build-tools install run: vab doctor - name: Build examples as APK + AAB (Java ${{ matrix.java-version }}) ${{ matrix.android-api }} run: | - declare -a v_examples=('flappylearning' '2048' 'fireworks' 'tetris' 'sokol/particles' 'sokol/drawing.v' 'sokol/freetype_raven.v' 'gg/polygons.v' 'gg/raven_text_rendering.v' 'gg/rectangles.v' 'gg/stars.v' 'gg/worker_thread.v') for example in "${v_examples[@]}"; do @@ -169,7 +184,7 @@ jobs: fail-fast: false timeout-minutes: 20 env: - VAB_FLAGS: -v 3 --build-tools 29.0.0 + VAB_FLAGS: -v 3 steps: - uses: actions/setup-java@v4 with: @@ -205,7 +220,7 @@ jobs: run: | sudo rm -fr /usr/local/lib/android - - name: Run 'vab doctor' + - name: Run 'vab doctor' before install run: vab doctor - name: Run 'vab install auto' @@ -215,7 +230,7 @@ jobs: unset ANDROID_NDK_ROOT vab install auto - - name: Run vab doctor + - name: Run 'vab doctor' after install run: vab doctor - name: Run tests From d9cb8ff2919dad85d775253604395f0118fa38fe Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 13:13:55 +0200 Subject: [PATCH 4/6] ci: clean up --- .github/workflows/matrix_ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/matrix_ci.yml b/.github/workflows/matrix_ci.yml index acfd12e..cc46855 100644 --- a/.github/workflows/matrix_ci.yml +++ b/.github/workflows/matrix_ci.yml @@ -58,8 +58,8 @@ jobs: - name: Run 'vab doctor' before install run: vab doctor - # It is a sisyphus task to get all combinations of the preinstalled SDK / tools and Java working - # so we simply destroy the env and use our own base-setup via 'vab install auto'... + # It is a sisyphus task to get all combinations of the pre-installed SDK / tools and Java working + # so we simply remove the system install and use our own minimal base-setup via 'vab install auto'... - name: Setup predictable Android environment run: | sudo rm -fr /usr/local/lib/android # location of pre-installed SDK on Ubuntu From 75c257c3f4b24e7ad44b58d954f9f69ffef5a58e Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 13:21:51 +0200 Subject: [PATCH 5/6] env: fix spelling mistake --- android/env/env.v | 8 ++++---- cli/doctor.v | 2 +- tests/at-runtime/emulator/emulator_test.vv | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/env/env.v b/android/env/env.v index 55f1099..62a804d 100644 --- a/android/env/env.v +++ b/android/env/env.v @@ -156,7 +156,7 @@ pub fn (io &InstallOptions) verbose(verbosity_level int, msg string) { } // managable returns `true` if the host system's SDK can be managed by `vab`. -@[deprecated: 'use "is_managable() or { false }" instead'] +@[deprecated: 'use "is_manageable() or { false }" instead'] @[deprecated_after: '2027-07-20'] pub fn managable() bool { sdk_is_writable := os.is_writable(sdk.root()) @@ -203,9 +203,9 @@ pub fn managable() bool { return sdk_is_writable && has_sdkmanager && sdkmanger_works } -// is_managable returns `true` if the host system's SDK can be managed by `vab`, an error with +// is_manageable returns `true` if the host system's SDK can be managed by `vab`, an error with // details is returned otherwise. -pub fn is_managable() !bool { +pub fn is_manageable() !bool { if !os.is_writable(sdk.root()) { return error('No permission to write in Android SDK root. Please install manually or ensure write access to "${sdk.root()}".') } @@ -553,7 +553,7 @@ fn install_opt(opt InstallOptions) !bool { loose := opt.dep == .bundletool || opt.dep == .aapt2 if !loose { - is_managable()! + is_manageable()! } // Accept all SDK licenses $if windows { diff --git a/cli/doctor.v b/cli/doctor.v index 0230499..1b60aca 100644 --- a/cli/doctor.v +++ b/cli/doctor.v @@ -14,7 +14,7 @@ import vab.android.env // diagnosticing the work environment. pub fn doctor(opt Options) { sdkm := env.sdkmanager() - env_managable := env.is_managable() or { + env_managable := env.is_manageable() or { util.vab_notice('${err.msg()}', details: 'For `${exe_short_name}` to control it\'s own dependencies, please update `sdkmanager` found in: "${sdkm}" diff --git a/tests/at-runtime/emulator/emulator_test.vv b/tests/at-runtime/emulator/emulator_test.vv index a4e57a5..0772c71 100644 --- a/tests/at-runtime/emulator/emulator_test.vv +++ b/tests/at-runtime/emulator/emulator_test.vv @@ -26,7 +26,7 @@ const test_v_examples = [ 'gg/worker_thread.v', ] -const env_is_managable = env.is_managable() or { false } +const env_is_manageable = env.is_manageable() or { false } const is_ci = os.getenv('CI') != '' @@ -77,7 +77,7 @@ fn ensure_env() { os.unsetenv('ANDROID_SERIAL') if !env.has_emulator() { - assert env_is_managable == true, 'These tests requires a *writable* SDK' + assert env_is_manageable == true, 'These tests requires a *writable* SDK' eprintln('No emulator detected. Installing...') install_emulator_res := run([vab_exe, 'install', 'emulator']) if install_emulator_res.exit_code != 0 { From fa35615f608cdd21086f2b9aebf083febf247879 Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 20 Jul 2025 13:53:49 +0200 Subject: [PATCH 6/6] docs: uppercase "Sisyphus" --- .github/workflows/matrix_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/matrix_ci.yml b/.github/workflows/matrix_ci.yml index cc46855..ca32246 100644 --- a/.github/workflows/matrix_ci.yml +++ b/.github/workflows/matrix_ci.yml @@ -58,7 +58,7 @@ jobs: - name: Run 'vab doctor' before install run: vab doctor - # It is a sisyphus task to get all combinations of the pre-installed SDK / tools and Java working + # It is a Sisyphus task to get all combinations of the pre-installed SDK / tools and Java working # so we simply remove the system install and use our own minimal base-setup via 'vab install auto'... - name: Setup predictable Android environment run: |