mirror of
https://github.com/reactivecircus/android-emulator-runner.git
synced 2026-09-04 19:29:31 +00:00
Compare commits
29 Commits
v2.27.0
...
yc/m1-runner
| Author | SHA1 | Date | |
|---|---|---|---|
| 437356159b | |||
| fa92a0ff54 | |||
| bc2cd2aaea | |||
| 61a61f94a9 | |||
| 426fbd2820 | |||
| e1bd48ca1d | |||
| 1e33853aad | |||
| c479bb6c0f | |||
| 677db68893 | |||
| f9c2835191 | |||
| 1036f55734 | |||
| 5a481d20f1 | |||
| f72f505164 | |||
| fabc29122a | |||
| 2cfd145246 | |||
| e1bdfefaa7 | |||
| b35b1c6e69 | |||
| acd15a6841 | |||
| a2c97ef57f | |||
| 8c71f5ed72 | |||
| 743ec40c5b | |||
| bad4154821 | |||
| bdaf04916f | |||
| 8e947e5bd6 | |||
| e1248ae048 | |||
| 8d5c4be650 | |||
| ce60a72e42 | |||
| 3c9349d876 | |||
| 949d52fd17 |
+19
-12
@@ -18,15 +18,11 @@ jobs:
|
|||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
api-level: [16, 23, 29]
|
api-level: [23, 29]
|
||||||
target: [default, google_apis]
|
target: [default, google_apis]
|
||||||
arch: [x86]
|
arch: [x86]
|
||||||
exclude:
|
exclude:
|
||||||
- os: ubuntu-latest
|
|
||||||
api-level: 23
|
|
||||||
- os: ubuntu-latest
|
|
||||||
api-level: 29
|
|
||||||
- target: google_apis
|
- target: google_apis
|
||||||
api-level: 16
|
api-level: 16
|
||||||
- target: google_apis
|
- target: google_apis
|
||||||
@@ -34,17 +30,21 @@ jobs:
|
|||||||
- target: google_apis
|
- target: google_apis
|
||||||
api-level: 29
|
api-level: 29
|
||||||
include:
|
include:
|
||||||
- os: macos-latest
|
- os: ubuntu-latest
|
||||||
api-level: 24
|
api-level: 24
|
||||||
target: playstore
|
target: playstore
|
||||||
arch: x86
|
arch: x86
|
||||||
- os: macos-latest
|
- os: ubuntu-latest
|
||||||
api-level: 30
|
api-level: 30
|
||||||
target: aosp_atd
|
target: aosp_atd
|
||||||
arch: x86
|
arch: x86
|
||||||
- os: macos-11
|
- os: macos-14
|
||||||
api-level: 31
|
api-level: 31
|
||||||
target: google_apis
|
target: google_apis
|
||||||
|
arch: arm64-v8a
|
||||||
|
- os: ubuntu-latest
|
||||||
|
api-level: 34
|
||||||
|
target: aosp_atd
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -61,11 +61,11 @@ jobs:
|
|||||||
npm run lint
|
npm run lint
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
- name: Java 15
|
- uses: actions/setup-java@v3
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: 15
|
java-version: 21
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
id: avd-cache
|
id: avd-cache
|
||||||
with:
|
with:
|
||||||
@@ -81,6 +81,13 @@ jobs:
|
|||||||
build-root-directory: test-fixture
|
build-root-directory: test-fixture
|
||||||
arguments: assembleAndroidTest
|
arguments: assembleAndroidTest
|
||||||
|
|
||||||
|
- name: enable KVM for linux runners
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: run emulator to generate snapshot for caching
|
- name: run emulator to generate snapshot for caching
|
||||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
os:
|
os:
|
||||||
description: 'OS'
|
description: 'OS'
|
||||||
required: true
|
required: true
|
||||||
default: 'macos-latest'
|
default: 'ubuntu-latest'
|
||||||
api-level:
|
api-level:
|
||||||
description: 'API level of the platform and system image'
|
description: 'API level of the platform and system image'
|
||||||
required: true
|
required: true
|
||||||
@@ -51,17 +51,21 @@ jobs:
|
|||||||
npm run lint
|
npm run lint
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
- name: Java 15
|
- uses: actions/setup-java@v3
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: 15
|
java-version: 21
|
||||||
- uses: actions/cache@v3
|
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
gradle-home-cache-cleanup: true
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
- name: enable KVM for linux runners
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: run action
|
- name: run action
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v2.30.1
|
||||||
|
|
||||||
|
* Run action on Node 20. - [#371](https://github.com/ReactiveCircus/android-emulator-runner/pull/371)
|
||||||
|
|
||||||
|
## v2.30.0
|
||||||
|
|
||||||
|
* Update to Node 20. - [#369](https://github.com/ReactiveCircus/android-emulator-runner/pull/369)
|
||||||
|
|
||||||
|
## v2.29.0
|
||||||
|
|
||||||
|
* Fixed emulator download URL. - [#343](https://github.com/ReactiveCircus/android-emulator-runner/pull/343)
|
||||||
|
* Upgrade to latest npm dependencies. - [#347](https://github.com/ReactiveCircus/android-emulator-runner/pull/347) [#355](https://github.com/ReactiveCircus/android-emulator-runner/pull/355)
|
||||||
|
* Update SDK command-line tools to `11.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
|
||||||
|
* Update SDK build tools to `34.0.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
|
||||||
|
|
||||||
|
## v2.28.0
|
||||||
|
|
||||||
|
* Add `emulator-boot-timeout` to support configuring maximum time waiting for emulator boot. - [#326](https://github.com/ReactiveCircus/android-emulator-runner/pull/326)
|
||||||
|
* Support non-integer `api-level`. - [#317](https://github.com/ReactiveCircus/android-emulator-runner/pull/317)
|
||||||
|
* Replace deprecated `ANDROID_SDK_ROOT` with `ANDROID_HOME`. - [304](https://github.com/ReactiveCircus/android-emulator-runner/pull/304)
|
||||||
|
* Update SDK command-line tools to `9.0`. - [#331](https://github.com/ReactiveCircus/android-emulator-runner/pull/331)
|
||||||
|
* Update SDK build tools to `33.0.2`. - [#331](https://github.com/ReactiveCircus/android-emulator-runner/pull/331)
|
||||||
|
|
||||||
## v2.27.0
|
## v2.27.0
|
||||||
|
|
||||||
* Added `pre-emulator-launch-script` to support running script after creating the AVD and before launching the emulator. - [#247](https://github.com/ReactiveCircus/android-emulator-runner/pull/247) @nilsreichardt.
|
* Added `pre-emulator-launch-script` to support running script after creating the AVD and before launching the emulator. - [#247](https://github.com/ReactiveCircus/android-emulator-runner/pull/247) @nilsreichardt.
|
||||||
|
|||||||
@@ -4,19 +4,29 @@
|
|||||||
<a href="https://github.com/ReactiveCircus/android-emulator-runner"><img alt="GitHub Actions status" src="https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg"></a>
|
<a href="https://github.com/ReactiveCircus/android-emulator-runner"><img alt="GitHub Actions status" src="https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on macOS virtual machines.
|
A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on Linux and macOS virtual machines.
|
||||||
|
|
||||||
The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators can be fast, but rely on two forms of hardware acceleration to reach their peak potential: [Graphics Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-graphics), e.g. `emulator -gpu host` and [Virtual Machine(VM) Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-vm), e.g. `emulator -accel on`. **Note:** GPU and VM Acceleration are two different and non-mutually exclusive forms of Hardware Acceleration.
|
The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators can be fast, but rely on two forms of hardware acceleration to reach their peak potential: [Graphics Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-graphics), e.g. `emulator -gpu host` and [Virtual Machine(VM) Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-vm), e.g. `emulator -accel on`. **Note:** GPU and VM Acceleration are two different and non-mutually exclusive forms of Hardware Acceleration.
|
||||||
|
|
||||||
This presents a challenge when running emulators on CI especially when running emulators within a docker container, because **Nested Virtualization** must be supported by the host VM which isn't the case for most cloud-based CI providers due to infrastructural limits. If you want to learn more about Emulators on CI, here's an article [Yang](https://github.com/ychescale9) wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).
|
This presents a challenge when running emulators on CI especially when running emulators within a docker container, because **Nested Virtualization** must be supported by the host VM which isn't the case for most cloud-based CI providers due to infrastructural limits. If you want to learn more about Emulators on CI, here's an article [Yang](https://github.com/ychescale9) wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).
|
||||||
|
|
||||||
## HAXM support on Github's MacOS Runners
|
## Running hardware accelerated emulators on Linux runners
|
||||||
|
|
||||||
The 10.x **macOS** VM provided by **GitHub Actions** had **HAXM** [pre-installed](https://github.com/actions/runner-images/blob/main/images/macos/macos-10.15-Readme.md). However, Github's [macOS-11](https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md) and [macOS-12](https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md) VMs **no longer** come pre-installed with HAXM. See [here](https://github.com/actions/runner-images/issues/183#issuecomment-610723516) and [here](https://github.com/actions/runner-images/issues/6388) for more info.
|
GitHub's [larger Linux runners support running hardware accelerated emulators](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/) which is [free for public GitHub repos](https://github.blog/2024-01-17-github-hosted-runners-double-the-power-for-open-source/). It is now recommended to use the **Ubuntu** (`ubuntu-latest`) runners which are 2-3 times faster than the **macOS** ones which are also a lot more expensive. Remember to enable KVM in your workflow before running this action:
|
||||||
|
|
||||||
**To run with HAXM on the macOS-11 and macOS-12 agents, you must install HAXM before starting your emulator**. See: [this snippet](https://gist.github.com/mrk-han/a0a11ed9bed966bb8b775ff55f2a87e9) for more info. This will enable VM acceleration, but as of right now running with GPU acceleration, e.g. `emulator -gpu host` is not possible with Github's standard runners.
|
```
|
||||||
|
- name: Enable KVM group perms
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
```
|
||||||
|
|
||||||
For Linux, Nested virtualization is possible on a self-hosted or 3rd party runner, but the VM will need to be hosted on a compatible machine that allows you to [enable KVM](https://developer.android.com/studio/run/emulator-acceleration#vm-linux), or is already configured with - for example the AWS EC2 Bare Metal instances. **The Github-hosted Linux runners are not currently KVM compatible.**
|
## A note on VM Acceleration and why we don't need HAXM anymore
|
||||||
|
|
||||||
|
According to [this documentation](https://developer.android.com/studio/run/emulator-acceleration#vm-mac), "on Mac OS X v10.10 Yosemite and higher, the Android Emulator uses the built-in [Hypervisor.Framework](https://developer.apple.com/documentation/hypervisor) by default, and falls back to using Intel HAXM if Hypervisor.Framework fails to initialize." This means that **HAXM is only needed to achieve VM Acceleration if this default Hypervisor is not available on macOS machines.**
|
||||||
|
|
||||||
|
**Note**: Manually enabling and downloading HAXM is not recommended because it is redundant and not needed (see above), and for users of macOS 10.13 High Sierra and higher: macOS 10.13 [disables installation of kernel extensions by default](https://developer.apple.com/library/archive/technotes/tn2459/_index.html#//apple_ref/doc/uid/DTS40017658). Because Intel HAXM is a kernel extension, we would need to manually enable its installation on the base runner VM. Furthermore, manually trying to install HAXM on a Github Runner [brings up a popup](https://github.com/ReactiveCircus/android-emulator-runner/discussions/286#discussioncomment-4026120) which further hinders tests from running.
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
@@ -36,11 +46,17 @@ A workflow that uses **android-emulator-runner** to run your instrumented tests
|
|||||||
```yml
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: macos-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
@@ -53,7 +69,7 @@ We can also leverage GitHub Actions's build matrix to test across multiple confi
|
|||||||
```yml
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: macos-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
api-level: [21, 23, 29]
|
api-level: [21, 23, 29]
|
||||||
@@ -62,6 +78,12 @@ jobs:
|
|||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
@@ -77,11 +99,17 @@ If you need specific versions of **NDK** and **CMake** installed:
|
|||||||
```yml
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: macos-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
@@ -101,7 +129,7 @@ We can significantly reduce emulator startup time by setting up AVD snapshot cac
|
|||||||
```yml
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: macos-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
api-level: [21, 23, 29]
|
api-level: [21, 23, 29]
|
||||||
@@ -109,6 +137,12 @@ jobs:
|
|||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Enable KVM
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
- name: Gradle cache
|
- name: Gradle cache
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/gradle-build-action@v2
|
||||||
|
|
||||||
@@ -156,6 +190,7 @@ jobs:
|
|||||||
| `disk-size` | Optional | N/A | Disk size, or partition size to use for this AVD. Either in bytes or KB, MB or GB, when denoted with K, M or G. - e.g. `2048M` |
|
| `disk-size` | Optional | N/A | Disk size, or partition size to use for this AVD. Either in bytes or KB, MB or GB, when denoted with K, M or G. - e.g. `2048M` |
|
||||||
| `avd-name` | Optional | `test` | Custom AVD name used for creating the Android Virtual Device. |
|
| `avd-name` | Optional | `test` | Custom AVD name used for creating the Android Virtual Device. |
|
||||||
| `force-avd-creation` | Optional | `true` | Whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`. |
|
| `force-avd-creation` | Optional | `true` | Whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`. |
|
||||||
|
| `emulator-boot-timeout` | Optional | `600` | Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes. |
|
||||||
| `emulator-options` | Optional | See below | Command-line options used when launching the emulator (replacing all default options) - e.g. `-no-window -no-snapshot -camera-back emulated`. |
|
| `emulator-options` | Optional | See below | Command-line options used when launching the emulator (replacing all default options) - e.g. `-no-window -no-snapshot -camera-back emulated`. |
|
||||||
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
|
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
|
||||||
| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
|
| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
|
||||||
@@ -171,12 +206,6 @@ jobs:
|
|||||||
|
|
||||||
Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`.
|
Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`.
|
||||||
|
|
||||||
## Can I use this action on Github Hosted Linux VMs?
|
|
||||||
|
|
||||||
The short answer is yes but on Github-hosted Linux runners it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS, because of the current lack of hardware acceleration support. You can get it running much faster on self-hosted Linux runners but only if the underlying instances support KVM (which most don't). Things might be better on the newer Larger runners but they are still in Beta. It is possible to use this Action with hardware accelerated Linux VMs hosted by a third-party runner provider.
|
|
||||||
|
|
||||||
For a longer answer please refer to [this issue](https://github.com/ReactiveCircus/android-emulator-runner/issues/46).
|
|
||||||
|
|
||||||
## Who is using Android Emulator Runner?
|
## Who is using Android Emulator Runner?
|
||||||
|
|
||||||
These are some of the open-source projects using (or used) **Android Emulator Runner**:
|
These are some of the open-source projects using (or used) **Android Emulator Runner**:
|
||||||
@@ -210,5 +239,8 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
|
|||||||
- [dotanuki-labs/norris](https://github.com/dotanuki-labs/norris/blob/master/.github/workflows/main.yml)
|
- [dotanuki-labs/norris](https://github.com/dotanuki-labs/norris/blob/master/.github/workflows/main.yml)
|
||||||
- [tinylog-org/tinylog](https://github.com/tinylog-org/tinylog/blob/v3.0/.github/workflows/build.yaml)
|
- [tinylog-org/tinylog](https://github.com/tinylog-org/tinylog/blob/v3.0/.github/workflows/build.yaml)
|
||||||
- [hzi-braunschweig/SORMAS-Project](https://github.com/hzi-braunschweig/SORMAS-Project/blob/development/.github/workflows/sormas_app_ci.yml)
|
- [hzi-braunschweig/SORMAS-Project](https://github.com/hzi-braunschweig/SORMAS-Project/blob/development/.github/workflows/sormas_app_ci.yml)
|
||||||
|
- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)
|
||||||
|
- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)
|
||||||
|
- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)
|
||||||
|
|
||||||
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
|
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ describe('api-level validator tests', () => {
|
|||||||
validator.checkApiLevel('29');
|
validator.checkApiLevel('29');
|
||||||
};
|
};
|
||||||
expect(func2).not.toThrow();
|
expect(func2).not.toThrow();
|
||||||
|
const func3 = () => {
|
||||||
|
validator.checkApiLevel('UpsideDownCake-ext5');
|
||||||
|
};
|
||||||
|
expect(func3).not.toThrow();
|
||||||
|
const func4 = () => {
|
||||||
|
validator.checkApiLevel('TiramisuPrivacySandbox');
|
||||||
|
};
|
||||||
|
expect(func4).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ inputs:
|
|||||||
type: string
|
type: string
|
||||||
force-avd-creation:
|
force-avd-creation:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
emulator-boot-timeout:
|
||||||
|
type: integer
|
||||||
emulator-options:
|
emulator-options:
|
||||||
type: string
|
type: string
|
||||||
disable-animations:
|
disable-animations:
|
||||||
|
|||||||
+5
-2
@@ -1,5 +1,5 @@
|
|||||||
name: 'Android Emulator Runner'
|
name: 'Android Emulator Runner'
|
||||||
description: 'Installs, configures and starts an Android Emulator directly on macOS virtual machines.'
|
description: 'Installs, configures and starts an Android Emulator directly on hardware-accelerated runners.'
|
||||||
author: 'Reactive Circus'
|
author: 'Reactive Circus'
|
||||||
branding:
|
branding:
|
||||||
icon: 'smartphone'
|
icon: 'smartphone'
|
||||||
@@ -33,6 +33,9 @@ inputs:
|
|||||||
force-avd-creation:
|
force-avd-creation:
|
||||||
description: 'whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`'
|
description: 'whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
|
emulator-boot-timeout:
|
||||||
|
description: 'Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes'
|
||||||
|
default: '600'
|
||||||
emulator-options:
|
emulator-options:
|
||||||
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
|
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
|
||||||
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
||||||
@@ -65,5 +68,5 @@ inputs:
|
|||||||
pre-emulator-launch-script:
|
pre-emulator-launch-script:
|
||||||
description: 'custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh`'
|
description: 'custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh`'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'lib/main.js'
|
main: 'lib/main.js'
|
||||||
|
|||||||
@@ -35,11 +35,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
exports.killEmulator = exports.launchEmulator = void 0;
|
exports.killEmulator = exports.launchEmulator = void 0;
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
|
||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* Creates and launches a new AVD instance with the specified configurations.
|
||||||
*/
|
*/
|
||||||
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
|
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Launch Emulator`);
|
console.log(`::group::Launch Emulator`);
|
||||||
@@ -73,7 +72,7 @@ function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSiz
|
|||||||
}
|
}
|
||||||
// start emulator
|
// start emulator
|
||||||
console.log('Starting emulator.');
|
console.log('Starting emulator.');
|
||||||
yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
yield exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||||
listeners: {
|
listeners: {
|
||||||
stderr: (data) => {
|
stderr: (data) => {
|
||||||
if (data.toString().includes('invalid command-line parameter')) {
|
if (data.toString().includes('invalid command-line parameter')) {
|
||||||
@@ -83,7 +82,7 @@ function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSiz
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
// wait for emulator to complete booting
|
// wait for emulator to complete booting
|
||||||
yield waitForDevice();
|
yield waitForDevice(emulatorBootTimeout);
|
||||||
yield exec.exec(`adb shell input keyevent 82`);
|
yield exec.exec(`adb shell input keyevent 82`);
|
||||||
if (disableAnimations) {
|
if (disableAnimations) {
|
||||||
console.log('Disabling animations.');
|
console.log('Disabling animations.');
|
||||||
@@ -125,12 +124,12 @@ exports.killEmulator = killEmulator;
|
|||||||
/**
|
/**
|
||||||
* Wait for emulator to boot.
|
* Wait for emulator to boot.
|
||||||
*/
|
*/
|
||||||
function waitForDevice() {
|
function waitForDevice(emulatorBootTimeout) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let booted = false;
|
let booted = false;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const retryInterval = 2; // retry every 2 seconds
|
const retryInterval = 2; // retry every 2 seconds
|
||||||
const maxAttempts = EMULATOR_BOOT_TIMEOUT_SECONDS / 2;
|
const maxAttempts = emulatorBootTimeout / 2;
|
||||||
while (!booted) {
|
while (!booted) {
|
||||||
try {
|
try {
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'go
|
|||||||
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
||||||
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
|
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
|
||||||
function checkApiLevel(apiLevel) {
|
function checkApiLevel(apiLevel) {
|
||||||
|
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox')
|
||||||
|
return;
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -61,9 +61,8 @@ function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// API level of the platform and system image
|
// API level of the platform and system image
|
||||||
const apiLevelInput = core.getInput('api-level', { required: true });
|
const apiLevel = core.getInput('api-level', { required: true });
|
||||||
(0, input_validator_1.checkApiLevel)(apiLevelInput);
|
(0, input_validator_1.checkApiLevel)(apiLevel);
|
||||||
const apiLevel = Number(apiLevelInput);
|
|
||||||
console.log(`API level: ${apiLevel}`);
|
console.log(`API level: ${apiLevel}`);
|
||||||
// target of the system image
|
// target of the system image
|
||||||
const targetInput = core.getInput('target');
|
const targetInput = core.getInput('target');
|
||||||
@@ -100,6 +99,9 @@ function run() {
|
|||||||
(0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput);
|
(0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput);
|
||||||
const forceAvdCreation = forceAvdCreationInput === 'true';
|
const forceAvdCreation = forceAvdCreationInput === 'true';
|
||||||
console.log(`force avd creation: ${forceAvdCreation}`);
|
console.log(`force avd creation: ${forceAvdCreation}`);
|
||||||
|
// Emulator boot timeout seconds
|
||||||
|
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||||
|
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||||
// emulator options
|
// emulator options
|
||||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||||
console.log(`emulator options: ${emulatorOptions}`);
|
console.log(`emulator options: ${emulatorOptions}`);
|
||||||
@@ -191,7 +193,7 @@ function run() {
|
|||||||
console.log(`::endgroup::`);
|
console.log(`::endgroup::`);
|
||||||
}
|
}
|
||||||
// launch an emulator
|
// launch an emulator
|
||||||
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
|
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
|
||||||
// execute the custom script
|
// execute the custom script
|
||||||
try {
|
try {
|
||||||
// move to custom working directory if set
|
// move to custom working directory if set
|
||||||
|
|||||||
+26
-9
@@ -38,9 +38,10 @@ const exec = __importStar(require("@actions/exec"));
|
|||||||
const io = __importStar(require("@actions/io"));
|
const io = __importStar(require("@actions/io"));
|
||||||
const tc = __importStar(require("@actions/tool-cache"));
|
const tc = __importStar(require("@actions/tool-cache"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const BUILD_TOOLS_VERSION = '33.0.0';
|
const BUILD_TOOLS_VERSION = '34.0.0';
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-8512546_latest.zip';
|
// SDK command-line tools 11.0
|
||||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip';
|
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
||||||
|
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
||||||
/**
|
/**
|
||||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||||
* and the system image for the chosen API level, CPU arch, and target.
|
* and the system image for the chosen API level, CPU arch, and target.
|
||||||
@@ -50,10 +51,11 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
|
|||||||
try {
|
try {
|
||||||
console.log(`::group::Install Android SDK`);
|
console.log(`::group::Install Android SDK`);
|
||||||
const isOnMac = process.platform === 'darwin';
|
const isOnMac = process.platform === 'darwin';
|
||||||
|
const isArm = process.arch === 'arm64';
|
||||||
if (!isOnMac) {
|
if (!isOnMac) {
|
||||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||||
}
|
}
|
||||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
console.log('Installing new cmdline-tools.');
|
console.log('Installing new cmdline-tools.');
|
||||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||||
@@ -62,21 +64,36 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
|
|||||||
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||||
}
|
}
|
||||||
// add paths for commandline-tools and platform-tools
|
// add paths for commandline-tools and platform-tools
|
||||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||||
// set standard AVD path
|
// set standard AVD path
|
||||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||||
// accept all Android SDK licenses
|
// accept all Android SDK licenses
|
||||||
yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
|
yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
|
||||||
console.log('Installing latest build tools, platform tools, and platform.');
|
console.log('Installing latest build tools, platform tools, and platform.');
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
|
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
||||||
console.log('Installing latest emulator.');
|
console.log('Installing latest emulator.');
|
||||||
yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||||
if (emulatorBuild) {
|
if (emulatorBuild) {
|
||||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||||
// TODO find out the correct download URLs for all build ids
|
// TODO find out the correct download URLs for all build ids
|
||||||
const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`;
|
var downloadUrlSuffix;
|
||||||
|
const majorBuildVersion = Number(emulatorBuild);
|
||||||
|
if (majorBuildVersion >= 8000000) {
|
||||||
|
if (isArm) {
|
||||||
|
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (majorBuildVersion >= 7000000) {
|
||||||
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
downloadUrlSuffix = `-${emulatorBuild}`;
|
||||||
|
}
|
||||||
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
||||||
yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||||
yield io.rmRF('emulator.zip');
|
yield io.rmRF('emulator.zip');
|
||||||
}
|
}
|
||||||
console.log('Installing system images.');
|
console.log('Installing system images.');
|
||||||
|
|||||||
Generated
+2938
-1852
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -2,7 +2,7 @@
|
|||||||
"name": "android-emulator-runner",
|
"name": "android-emulator-runner",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "A GitHub Action for installing, configuring and running Android Emulators on macOS virtual machines.",
|
"description": "A GitHub Action for installing, configuring and running Android Emulators on hardware-accelerated runners.",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
"node",
|
"node",
|
||||||
"setup"
|
"setup"
|
||||||
],
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
"author": "Reactive Circus",
|
"author": "Reactive Circus",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -29,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.2.0",
|
"@types/jest": "^29.2.0",
|
||||||
"@types/node": "^16.18.2",
|
"@types/node": "^20.11.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||||
"@typescript-eslint/parser": "^5.41.0",
|
"@typescript-eslint/parser": "^5.41.0",
|
||||||
"eslint": "^8.26.0",
|
"eslint": "^8.26.0",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and launches a new AVD instance with the specified configurations.
|
* Creates and launches a new AVD instance with the specified configurations.
|
||||||
*/
|
*/
|
||||||
export async function launchEmulator(
|
export async function launchEmulator(
|
||||||
apiLevel: number,
|
apiLevel: string,
|
||||||
target: string,
|
target: string,
|
||||||
arch: string,
|
arch: string,
|
||||||
profile: string,
|
profile: string,
|
||||||
@@ -18,6 +16,7 @@ export async function launchEmulator(
|
|||||||
diskSize: string,
|
diskSize: string,
|
||||||
avdName: string,
|
avdName: string,
|
||||||
forceAvdCreation: boolean,
|
forceAvdCreation: boolean,
|
||||||
|
emulatorBootTimeout: number,
|
||||||
emulatorOptions: string,
|
emulatorOptions: string,
|
||||||
disableAnimations: boolean,
|
disableAnimations: boolean,
|
||||||
disableSpellChecker: boolean,
|
disableSpellChecker: boolean,
|
||||||
@@ -66,7 +65,7 @@ export async function launchEmulator(
|
|||||||
// start emulator
|
// start emulator
|
||||||
console.log('Starting emulator.');
|
console.log('Starting emulator.');
|
||||||
|
|
||||||
await exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||||
listeners: {
|
listeners: {
|
||||||
stderr: (data: Buffer) => {
|
stderr: (data: Buffer) => {
|
||||||
if (data.toString().includes('invalid command-line parameter')) {
|
if (data.toString().includes('invalid command-line parameter')) {
|
||||||
@@ -77,7 +76,7 @@ export async function launchEmulator(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// wait for emulator to complete booting
|
// wait for emulator to complete booting
|
||||||
await waitForDevice();
|
await waitForDevice(emulatorBootTimeout);
|
||||||
await exec.exec(`adb shell input keyevent 82`);
|
await exec.exec(`adb shell input keyevent 82`);
|
||||||
|
|
||||||
if (disableAnimations) {
|
if (disableAnimations) {
|
||||||
@@ -114,11 +113,11 @@ export async function killEmulator(): Promise<void> {
|
|||||||
/**
|
/**
|
||||||
* Wait for emulator to boot.
|
* Wait for emulator to boot.
|
||||||
*/
|
*/
|
||||||
async function waitForDevice(): Promise<void> {
|
async function waitForDevice(emulatorBootTimeout: number): Promise<void> {
|
||||||
let booted = false;
|
let booted = false;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const retryInterval = 2; // retry every 2 seconds
|
const retryInterval = 2; // retry every 2 seconds
|
||||||
const maxAttempts = EMULATOR_BOOT_TIMEOUT_SECONDS / 2;
|
const maxAttempts = emulatorBootTimeout / 2;
|
||||||
while (!booted) {
|
while (!booted) {
|
||||||
try {
|
try {
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
|
|||||||
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
|
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
|
||||||
|
|
||||||
export function checkApiLevel(apiLevel: string): void {
|
export function checkApiLevel(apiLevel: string): void {
|
||||||
|
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox') return;
|
||||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -40,9 +40,8 @@ async function run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API level of the platform and system image
|
// API level of the platform and system image
|
||||||
const apiLevelInput = core.getInput('api-level', { required: true });
|
const apiLevel = core.getInput('api-level', { required: true });
|
||||||
checkApiLevel(apiLevelInput);
|
checkApiLevel(apiLevel);
|
||||||
const apiLevel = Number(apiLevelInput);
|
|
||||||
console.log(`API level: ${apiLevel}`);
|
console.log(`API level: ${apiLevel}`);
|
||||||
|
|
||||||
// target of the system image
|
// target of the system image
|
||||||
@@ -90,6 +89,10 @@ async function run() {
|
|||||||
const forceAvdCreation = forceAvdCreationInput === 'true';
|
const forceAvdCreation = forceAvdCreationInput === 'true';
|
||||||
console.log(`force avd creation: ${forceAvdCreation}`);
|
console.log(`force avd creation: ${forceAvdCreation}`);
|
||||||
|
|
||||||
|
// Emulator boot timeout seconds
|
||||||
|
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||||
|
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||||
|
|
||||||
// emulator options
|
// emulator options
|
||||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||||
console.log(`emulator options: ${emulatorOptions}`);
|
console.log(`emulator options: ${emulatorOptions}`);
|
||||||
@@ -206,6 +209,7 @@ async function run() {
|
|||||||
diskSize,
|
diskSize,
|
||||||
avdName,
|
avdName,
|
||||||
forceAvdCreation,
|
forceAvdCreation,
|
||||||
|
emulatorBootTimeout,
|
||||||
emulatorOptions,
|
emulatorOptions,
|
||||||
disableAnimations,
|
disableAnimations,
|
||||||
disableSpellchecker,
|
disableSpellchecker,
|
||||||
|
|||||||
+24
-10
@@ -4,24 +4,26 @@ import * as io from '@actions/io';
|
|||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const BUILD_TOOLS_VERSION = '33.0.0';
|
const BUILD_TOOLS_VERSION = '34.0.0';
|
||||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-8512546_latest.zip';
|
// SDK command-line tools 11.0
|
||||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip';
|
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
||||||
|
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||||
* and the system image for the chosen API level, CPU arch, and target.
|
* and the system image for the chosen API level, CPU arch, and target.
|
||||||
*/
|
*/
|
||||||
export async function installAndroidSdk(apiLevel: number, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
|
export async function installAndroidSdk(apiLevel: string, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`::group::Install Android SDK`);
|
console.log(`::group::Install Android SDK`);
|
||||||
const isOnMac = process.platform === 'darwin';
|
const isOnMac = process.platform === 'darwin';
|
||||||
|
const isArm = process.arch === 'arm64';
|
||||||
|
|
||||||
if (!isOnMac) {
|
if (!isOnMac) {
|
||||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||||
console.log('Installing new cmdline-tools.');
|
console.log('Installing new cmdline-tools.');
|
||||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||||
@@ -31,7 +33,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add paths for commandline-tools and platform-tools
|
// add paths for commandline-tools and platform-tools
|
||||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||||
|
|
||||||
// set standard AVD path
|
// set standard AVD path
|
||||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||||
@@ -41,7 +43,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
|
|
||||||
console.log('Installing latest build tools, platform tools, and platform.');
|
console.log('Installing latest build tools, platform tools, and platform.');
|
||||||
|
|
||||||
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
|
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
||||||
|
|
||||||
console.log('Installing latest emulator.');
|
console.log('Installing latest emulator.');
|
||||||
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||||
@@ -49,9 +51,21 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
|||||||
if (emulatorBuild) {
|
if (emulatorBuild) {
|
||||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||||
// TODO find out the correct download URLs for all build ids
|
// TODO find out the correct download URLs for all build ids
|
||||||
const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`;
|
var downloadUrlSuffix: string;
|
||||||
|
const majorBuildVersion = Number(emulatorBuild);
|
||||||
|
if (majorBuildVersion >= 8000000) {
|
||||||
|
if (isArm) {
|
||||||
|
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
||||||
|
} else {
|
||||||
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
|
}
|
||||||
|
} else if (majorBuildVersion >= 7000000) {
|
||||||
|
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||||
|
} else {
|
||||||
|
downloadUrlSuffix = `-${emulatorBuild}`;
|
||||||
|
}
|
||||||
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
||||||
await exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
await exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||||
await io.rmRF('emulator.zip');
|
await io.rmRF('emulator.zip');
|
||||||
}
|
}
|
||||||
console.log('Installing system images.');
|
console.log('Installing system images.');
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
target/
|
||||||
|
out/
|
||||||
|
local.properties
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.DS_Store
|
||||||
@@ -2,31 +2,36 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 33
|
namespace = "com.example.testapp"
|
||||||
buildToolsVersion "33.0.0"
|
|
||||||
|
compileSdkVersion 34
|
||||||
|
buildToolsVersion "34.0.0"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.example.testapp"
|
applicationId "com.example.testapp"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 33
|
targetSdkVersion 34
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
compileOptions {
|
||||||
release {
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
minifyEnabled false
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-21
@@ -1,21 +0,0 @@
|
|||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
package="com.example.testapp">
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.0'
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
classpath 'com.android.tools.build:gradle:8.2.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
@@ -2,26 +2,8 @@ org.gradle.parallel=true
|
|||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
|
|
||||||
# Enable Kotlin incremental compilation
|
|
||||||
kotlin.incremental=true
|
|
||||||
|
|
||||||
# Enable parallel tasks execution for Kotlin Gradle plugin
|
|
||||||
kotlin.parallel.tasks.in.project=true
|
|
||||||
|
|
||||||
# Kotlin code style
|
# Kotlin code style
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
|
||||||
# Run kapt directly using Gradle workers
|
|
||||||
kapt.use.worker.api=true
|
|
||||||
|
|
||||||
# Enable incremental annotation processor for KAPT
|
|
||||||
kapt.incremental.apt=true
|
|
||||||
|
|
||||||
# Turn off AP discovery in compile path to enable compile avoidance
|
|
||||||
kapt.include.compile.classpath=false
|
|
||||||
|
|
||||||
# Use R8 instead of ProGuard for code shrinking.
|
|
||||||
android.enableR8.fullMode=true
|
|
||||||
|
|
||||||
# Enable AndroidX
|
# Enable AndroidX
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
|||||||
BIN
Binary file not shown.
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
#Tue Nov 26 18:34:05 AEDT 2019
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
|
||||||
|
|||||||
Vendored
+193
-116
@@ -1,78 +1,127 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
app_path=$0
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
# Need this for daisy-chained symlinks.
|
||||||
ls=`ls -ld "$PRG"`
|
while
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
[ -h "$app_path" ]
|
||||||
PRG="$link"
|
do
|
||||||
else
|
ls=$( ls -ld "$app_path" )
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
link=${ls#*' -> '}
|
||||||
fi
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
# This is normally unused
|
||||||
APP_BASE_NAME=`basename "$0"`
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
DEFAULT_JVM_OPTS=""
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn () {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
nonstop=false
|
||||||
case "`uname`" in
|
case "$( uname )" in #(
|
||||||
CYGWIN* )
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
cygwin=true
|
Darwin* ) darwin=true ;; #(
|
||||||
;;
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
Darwin* )
|
NONSTOP* ) nonstop=true ;;
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
# shellcheck disable=SC2039,SC3045
|
||||||
fi
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
ulimit -n $MAX_FD
|
warn "Could not query maximum file descriptor limit"
|
||||||
if [ $? -ne 0 ] ; then
|
esac
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
case $MAX_FD in #(
|
||||||
fi
|
'' | soft) :;; #(
|
||||||
else
|
*)
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
fi
|
# shellcheck disable=SC2039,SC3045
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
save () {
|
# * args from the command line
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
# * the main class name
|
||||||
echo " "
|
# * -classpath
|
||||||
}
|
# * -D...appname settings
|
||||||
APP_ARGS=$(save "$@")
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
Vendored
+30
-22
@@ -1,3 +1,19 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@@ -10,18 +26,22 @@ if "%OS%"=="Windows_NT" setlocal
|
|||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS=
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@@ -35,7 +55,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -45,38 +65,26 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
exit /b 1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|||||||
Reference in New Issue
Block a user