Skip to content

Commit 6bed875

Browse files
committed
add Android to CICD
1 parent 16a8d1d commit 6bed875

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

.github/workflows/CICD.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,60 @@ jobs:
844844
n_fails=$(echo "$output" | grep "^FAIL:\s" | wc --lines)
845845
if [ $n_fails -gt 0 ] ; then echo "::warning ::${n_fails}+ test failures" ; fi
846846
847+
test_android:
848+
name: Test Android builds
849+
runs-on: macos-latest
850+
strategy:
851+
fail-fast: false
852+
matrix:
853+
api-level: [28]
854+
target: [default]
855+
arch: [x86] # , arm64-v8a
856+
env:
857+
TERMUX: v0.118.0
858+
steps:
859+
- uses: actions/checkout@v2
860+
- name: AVD cache
861+
uses: actions/cache@v2
862+
id: avd-cache
863+
with:
864+
path: |
865+
~/.android/avd/*
866+
~/.android/avd/*/snapshots/*
867+
~/.android/adb*
868+
key: avd-${{ matrix.api-level }}-${{ matrix.arch }}+termux-${{ env.TERMUX }}
869+
- name: Create and cache emulator image
870+
if: steps.avd-cache.outputs.cache-hit != 'true'
871+
uses: reactivecircus/android-emulator-runner@v2
872+
with:
873+
api-level: ${{ matrix.api-level }}
874+
target: ${{ matrix.target }}
875+
arch: ${{ matrix.arch }}
876+
ram-size: 2048M
877+
disk-size: 4096M
878+
force-avd-creation: true
879+
emulator-options: -no-snapshot-load -noaudio -no-boot-anim -camera-back none
880+
script: |
881+
wget https://github.com/termux/termux-app/releases/download/${{ env.TERMUX }}/termux-app_${{ env.TERMUX }}+github-debug_${{ matrix.arch }}.apk
882+
util/android-commands.sh snapshot termux-app_${{ env.TERMUX }}+github-debug_${{ matrix.arch }}.apk
883+
adb -s emulator-5554 emu avd snapshot save ${{ matrix.api-level }}-${{ matrix.arch }}+termux-${{ env.TERMUX }}
884+
echo "Emulator image created."
885+
pkill -9 qemu-system-x86_64
886+
- name: Build and Test on Android
887+
uses: reactivecircus/android-emulator-runner@v2
888+
with:
889+
api-level: ${{ matrix.api-level }}
890+
target: ${{ matrix.target }}
891+
arch: ${{ matrix.arch }}
892+
ram-size: 2048M
893+
disk-size: 4096M
894+
force-avd-creation: false
895+
emulator-options: -no-snapshot-save -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -snapshot ${{ matrix.api-level }}-${{ matrix.arch }}+termux-${{ env.TERMUX }}
896+
script: |
897+
util/android-commands.sh sync
898+
util/android-commands.sh build
899+
util/android-commands.sh tests
900+
847901
test_freebsd:
848902
name: Tests/FreeBSD test suite
849903
needs: [ min_version, deps ]

util/android-commands.sh

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# spell-checker:ignore termux keyevent sdcard binutils unmatch adb's dumpsys logcat pkill
2+
3+
# There are three shells: the host's, adb, and termux. Only adb lets us run
4+
# commands directly on the emulated device, only termux provides a GNU
5+
# environment on the emulated device (to e.g. run cargo). So we use adb to
6+
# launch termux, then to send keystrokes to it while it's running.
7+
# This means that the commands sent to termux are first parsed as arguments in
8+
# this shell, then as arguments in the adb shell, before finally being used as
9+
# text inputs to the app. Hence, the "'wrapping'" on those commands.
10+
# There's no way to get any feedback from termux, so every time we run a
11+
# command on it, we make sure it ends by creating a unique *.probe file at the
12+
# end of the command. The contents of the file are used as a return code: 0 on
13+
# success, some other number for errors (an empty file is basically the same as
14+
# 0). Note that the return codes are text, not raw bytes.
15+
16+
17+
this_repo="$(dirname $(dirname -- "$(readlink -- "${0}")"))"
18+
19+
help () {
20+
echo \
21+
"Usage: $0 COMMAND [ARG]
22+
23+
where COMMAND is one of:
24+
snapshot APK install APK and dependencies on an emulator to prep a snapshot
25+
(you can, but probably don't want to, run this for physical
26+
devices -- just set up termux and the dependencies yourself)
27+
sync [REPO] push the repo at REPO to the device, deleting and restoring all
28+
symlinks (locally) in the process; by default, REPO is:
29+
$this_repo
30+
build run \`cargo build --features feat_os_unix_android\` on the
31+
device, then pull the output as build.log
32+
tests run \`cargo test --features feat_os_unix_android\` on the
33+
device, then pull the output as tests.log
34+
35+
If you have multiple devices, use the ANDROID_SERIAL environment variable to
36+
specify which to connect to."
37+
}
38+
39+
hit_enter() {
40+
adb shell input keyevent 66
41+
}
42+
43+
launch_termux() {
44+
echo "launching termux"
45+
if ! adb shell 'am start -n com.termux/.HomeActivity' ; then
46+
echo "failed to launch termux"
47+
exit 1
48+
fi
49+
# the emulator can sometimes be a little slow to launch the app
50+
while ! adb shell 'ls /sdcard/launch.probe' 2>/dev/null; do
51+
echo "waiting for launch.probe"
52+
sleep 5
53+
adb shell input text 'touch\ /sdcard/launch.probe' && hit_enter
54+
done
55+
echo "found launch.probe"
56+
adb shell 'rm /sdcard/launch.probe' && echo "removed launch.probe"
57+
}
58+
59+
run_termux_command() {
60+
command="$1" # text of the escaped command, including creating the probe!
61+
probe="$2" # unique file that indicates the command is complete
62+
launch_termux
63+
adb shell input text "$command" && hit_enter
64+
while ! adb shell "ls $probe" 2>/dev/null; do echo "waiting for $probe"; sleep 30; done
65+
return_code=$(adb shell "cat $probe")
66+
adb shell "rm $probe"
67+
echo "return code: $return_code"
68+
return $return_code
69+
}
70+
71+
snapshot () {
72+
apk="$1"
73+
echo "running snapshot"
74+
adb install -g "$apk"
75+
probe='/sdcard/pkg.probe'
76+
command="'yes | pkg install rust binutils openssl -y; touch $probe'"
77+
run_termux_command "$command" "$probe"
78+
echo "snapshot complete"
79+
adb shell input text "exit" && hit_enter && hit_enter
80+
}
81+
82+
sync () {
83+
repo="$1"
84+
echo "running sync $1"
85+
# android doesn't allow symlinks on shared dirs, and adb can't selectively push files
86+
symlinks=$(find "$repo" -type l)
87+
# dash doesn't support process substitution :(
88+
echo $symlinks >symlinks
89+
git -C "$repo" diff --name-status | cut -f 2 >modified
90+
modified_links=$(join symlinks modified)
91+
if [ ! -z "$modified_links" ]; then
92+
echo "You have modified symlinks. Either stash or commit them, then try again: $modified_links"
93+
exit 1
94+
fi
95+
if ! git ls-files --error-unmatch $symlinks >/dev/null; then
96+
echo "You have untracked symlinks. Either remove or commit them, then try again."
97+
exit 1
98+
fi
99+
rm $symlinks
100+
# adb's shell user only has access to shared dirs...
101+
adb push "$repo" /sdcard/coreutils
102+
git -C "$repo" checkout $symlinks
103+
# ...but shared dirs can't build, so move it home as termux
104+
probe='/sdcard/mv.probe'
105+
command="'mv /sdcard/coreutils ~/; touch $probe'"
106+
run_termux_command "$command" "$probe"
107+
}
108+
109+
build () {
110+
probe='/sdcard/build.probe'
111+
command="'cd ~/coreutils && cargo build --features feat_os_unix_android 2>/sdcard/build.log; echo \$? >$probe'"
112+
echo "running build"
113+
run_termux_command "$command" "$probe"
114+
return_code=$?
115+
adb pull /sdcard/build.log .
116+
cat build.log
117+
return $return_code
118+
}
119+
120+
tests () {
121+
launch_termux
122+
probe='/sdcard/tests.probe'
123+
command="'cd ~/coreutils && cargo test --features feat_os_unix_android --no-fail-fast >/sdcard/tests.log 2>&1; echo \$? >$probe'"
124+
run_termux_command "$command" "$probe"
125+
return_code=$?
126+
adb pull /sdcard/tests.log .
127+
cat tests.log
128+
return $return_code
129+
}
130+
131+
#adb logcat &
132+
exit_code=0
133+
134+
if [ $# -eq 1 ]; then
135+
case "$1" in
136+
sync) sync "$this_repo"; exit_code=$?;;
137+
build) build; exit_code=$?;;
138+
tests) tests; exit_code=$?;;
139+
*) help;;
140+
esac
141+
elif [ $# -eq 2 ]; then
142+
case "$1" in
143+
snapshot) snapshot "$2"; exit_code=$?;;
144+
sync) sync "$2"; exit_code=$?;;
145+
*) help; exit 1;;
146+
esac
147+
else
148+
help
149+
exit_code=1
150+
fi
151+
152+
#pkill adb
153+
exit $exit_code

0 commit comments

Comments
 (0)