From 5d8374ebae3d4b8c96fd48b171cddf6f2ed0e148 Mon Sep 17 00:00:00 2001 From: pproenca Date: Fri, 18 Nov 2016 13:58:03 +0100 Subject: [PATCH] Initial public release --- .gitignore | 3 + .travis.yml | 25 +++++ AUTHORS | 2 + CHANGELOG.md | 5 + CONTRIBUTING.md | 98 ++++++++++++++++ LICENSE | 192 ++++++++++++++++++++++++++++++++ README.md | 114 +++++++++++++++++++ bin/cmd/cleanup_pre.sh | 18 +++ bin/cmd/logs_pre.sh | 40 +++++++ bin/cmd/start.sh | 28 +++++ bin/cmd/start_post.sh | 20 ++++ bin/cmd/start_pre.sh | 46 ++++++++ bin/cmd/stop_pre.sh | 34 ++++++ bin/cmd/terminal_pre.sh | 35 ++++++ bin/cmd/wizard_pre.sh | 58 ++++++++++ bin/lib/functions.container.sh | 29 +++++ dependencies.ini | 1 + docker/Dockerfile | 36 ++++++ docker/api-24.conf | 6 + docker/install_dependencies.sh | 11 ++ docker/wxga720-api-24.env | 4 + docs/README.md | 114 +++++++++++++++++++ docs/_layouts/website/page.html | 53 +++++++++ docs/publish_docs | 39 +++++++ tests/bashunit-bootstrap.sh | 12 ++ tests/test.cmds.sh | 12 ++ version.txt | 1 + 27 files changed, 1036 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bin/cmd/cleanup_pre.sh create mode 100644 bin/cmd/logs_pre.sh create mode 100644 bin/cmd/start.sh create mode 100644 bin/cmd/start_post.sh create mode 100644 bin/cmd/start_pre.sh create mode 100644 bin/cmd/stop_pre.sh create mode 100644 bin/cmd/terminal_pre.sh create mode 100644 bin/cmd/wizard_pre.sh create mode 100644 bin/lib/functions.container.sh create mode 100644 dependencies.ini create mode 100644 docker/Dockerfile create mode 100644 docker/api-24.conf create mode 100755 docker/install_dependencies.sh create mode 100644 docker/wxga720-api-24.env create mode 100644 docs/README.md create mode 100644 docs/_layouts/website/page.html create mode 100755 docs/publish_docs create mode 100644 tests/bashunit-bootstrap.sh create mode 100644 tests/test.cmds.sh create mode 100644 version.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb487cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +athena.lock +*.swp +*.DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5282763 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +language: node_js +node_js: +- stable +services: +- docker +before_script: +- npm install -g gitbook-cli +- mkdir -p /opt/athena +- wget -qO- "https://github.com/athena-oss/athena/archive/v0.9.0.tar.gz" | tar --strip-components 1 -zx -C "/opt/athena" +- ln -s "$TRAVIS_BUILD_DIR" "/opt/athena/plugins/avd" +- touch /opt/athena/plugins/base/athena.lock +- export PATH=$PATH:/opt/athena +- mkdir -p /opt/bashunit +- wget -qO- "https://github.com/athena-oss/bashunit/archive/v0.3.1.tar.gz" | tar --strip-components 1 -zx -C "/opt/bashunit" +- export PATH=$PATH:/opt/bashunit +script: +- ATHENA_DIR="/opt/athena" bashunit tests/ +after_success: +- docs/publish_docs +cache: + directories: + - $(npm config get prefix)/bin/gitbook +env: + global: + secure: QrLv1PcF7v3CJvqWmMAR5kn8TaIMQSiHD/SU693RQJbpCd85fupAo653WiDgPGD57j9e6aSemnSTF/S3/2BvTMgm1H0kQfUO2JBX0vQvk14deXMuXVTEw+FI1Yp3QUOAVtdZUU6TiQzCur5vr3hNdszJ0FBOGnOZsPMyiLEyN0sONC8dgQLbrZc1kH0jWX4HTBZd9mu7lHzQrgTEEEOyvxFSs26X9MmlIN0KgZVTIyEvMHBuN4WmFkdZcIEm8LuOd0bGhakCTp7NCHLapYpvapfbuL6K2xYWBmqaZowh798h4biKbhRMnhIyyb7cHNBBBxZ19uu8u8fD3Rt21GHHzcqmRXIGTwKNO/JXj2p0+KNNFDGUUk1PtjKwMbfQYlmQ/WDn/U+M2MN0HuneMbaelY8J3jPWrMOa0O2jIFki1n0pzcB99I5yEJqRm/Ldn3cxfETliRQp8Lct714dBIPXrNFYeQwrsZRN3RZQXcfiWqq8b0DEllncKXxJmtF+gin70Gc7bokW8Bv+6MAAJc6evuLYhHtGMZfBZKp/mtWrDlqcqyhXCvEHiig29EY7p6P9cm/gW6s6cFUOFD0eiveLtzVdqMr0xGcTWzGwr0F/3Zx1VT+pdSaCM9L1RarUXlswORM2sSbbUsq4DkqacMxhF1li+n43GlhvVx3F5t9x2hA= diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..02c08c9 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Pedro Proença +Rafael Pinto diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7093db5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## 0.3.0 (November 18, 2016) + +### Athena Plugin AVD + +- Initial public release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..16337f6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,98 @@ +# Contributing to Athena AVD Plugin + +Athena is the first [OLX](http://www.olx.com/) open source project that is both under very active development and is also being used to automate stuff at [OLX](http://www.olx.com/). We're still working the details to make contributing to this project as easy and transparent as possible. Hopefully with the help of this document and your feedback we will eventually make it. + +## Our Development Process + +Some of our core contributers will be working directly on GitHub. These changes will be public from the beginning. + +### `master` changes fast + +We move fast and most likely things will break. Every time there is a commit our CI server will run the tests and hopefully they will pass all times. We will do our best to properly communicate the changes that can affect the application API and always version appropriately in order to make easier for you to use a specific version. + +### Pull Requests + +The core contributors will be monitoring for pull requests. When we get one, we will pull it in and apply it to our codebase and run our test suite to ensure nothing breaks. Then one of the core contributors needs to verify that all is working appropriately. When the API changes we may need to fix internal uses, which could cause some delay. We'll do our best to provide updates and feedback throughout the process. + +*Before* submitting a pull request, please make sure the following is done: + +1. Fork the repo and create your branch from `master`. +2. If you've added code that should be tested, add tests! +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes (`bashunit tests/`). + + +## Bugs + +### Where to Find Known Issues + +We will be using GitHub Issues for our public bugs. We will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn't already exist. + +### Reporting New Issues + +The best way to get your bug fixed is to provide a reduced test case. + +## How to Get in Touch + +Mailing list - [Athena in Google Groups](https://groups.google.com/a/olx.com/d/forum/athena) + +## Development best practices + +### Common + +* Global Variables : + - **SHOULD** be avoided and used only to store global state + - **MUST** be handled using getters and setters + - **MUST** be named in uppercase, e.g.: ```MY_VARIABLE_NAME``` + - **MUST** be prefixed with ATHENA_ when defined in Athena engine and prefixed with ```ATHENA_PLG_${PLUGIN_NAME}_``` when defined in a plugin, e.g.: + - ```ATHENA_MY_VARIABLE_NAME``` + - ```ATHENA_PLG_SELENIUM_MY_VARIABLE_NAME``` + +* Local variables : + - **MUST** be declared with the local keyword + - **MUST** be named in lowercase + + +* CLI functions: + * **MUST** be tested and documented + * Documentation **MUST** follow the following format : + ``` + # Description + # USAGE: [] + # RETURN: + ``` + * when used as a core athena function **MUST** follow the naming schema ```athena[.${context}.]${function_name}``` + * when used as a global plugin function **MUST** follow the naming schema ```athena.plugins.${plugin_name}.${function_name}``` + * **MUST** always return 0 when success and not 0 when fail + + +* Plugin Commands + + * **MUST** NOT have a shebang line + * Arguments **MUST** only be accessed or setted using the functions in ```athena.argument``` library + + + +### Plugins + + * Library functions **MUST** be located ```${PLUGIN}/bin/lib``` and when multiple contexts are handled **MUST** follow the naming schema ```${PLUGIN}/bin/lib/functions.${CONTEXT}.sh```, e.g.: ```java/bin/lib/functions.api.sh``` + + * Library functions **MUST** follow the following name schema : ```athena.plugins.${plugin_name}.${function_name}``` + + + * Folders that are supposed to be mounted in the docker container **MUST** be located in ```${PLUGIN}/mnt/${context}```, e.g.: ```java/mnt/api``` + + * Source code used per context **MUST** follow a recommended standard, e.g.: PHP **MUST** follow PSR-2, JAVA **MUST** follow Google (https://google.github.io/styleguide/javaguide.html) or other widely adopted + + * External libraries **MUST** not be “shipped” with the plugin and **MUST** have a **License** that allows us to use it as we see fit, e.g.: Apache 2.0 License + + * Documentation **MUST** be provided + + * Examples on HOW TO USE **MUST** be provided + + * The init command **MUST** NOT be used directly + + +## License + +By contributing to Athena and Athena Official Plugins, you agree that your contributions will be licensed under the [Apache License Version 2.0 (APLv2)](LICENSE). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d97ef8d --- /dev/null +++ b/LICENSE @@ -0,0 +1,192 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + + END OF TERMS AND CONDITIONS + + + Copyright 2016 OLX + + 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 + + http://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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..86ef8ef --- /dev/null +++ b/README.md @@ -0,0 +1,114 @@ +# AVD Plugin [![Build Status](https://travis-ci.org/athena-oss/plugin-avd.svg?branch=master)](https://travis-ci.org/athena-oss/plugin-avd) + +This plugins provides a straightforward API to manage Android Virtual Devices. + +You can easily use this plugin in your local development machine or in a CI/CD pipeline. + +## How to Install ? + +To install it simply run the following command : + +```bash +$ athena plugins install avd https://github.com/athena-oss/plugin-avd.git +``` + +or + +* On MAC OSX using [Homebrew](http://brew.sh/) : +```bash +$ brew tap athena-oss/tap +$ brew install plugin-avd +``` + +Read the [Documentation](http://athena-oss.github.io/plugin-avd) on using the [Athena](https://github.com/athena-oss/athena) AVD plugin. + +## How to Use ? + +This plugin provides the following commands: + +### start - Starts the AVD + +```bash +$ athena avd start [--help|...] + +$ # e.g. start one of the pre-defined devices +$ athena avd start wxga720-api-24 + +$ # e.g. start a pre-defined device and open a VNC at port 9001 +$ athena avd start wxga720-api-24 --vnc-port=9001 +``` + +### stop - Stops the AVD + +```bash +$ athena avd stop [--help|...] + +$ # e.g. stop a device that was started without any extra options +$ athena avd stop wxga720-api-24 + +$ # e.g. stop a device that was started with a VNC port at 9001 +$ athena avd stop wxga720-api-24 --vnc-port=9001 +``` + +### logs - Retrieve AVD logs + +```bash +$ athena avd logs [--help|...] + +$ # e.g. get logs from a device that was started without any extra options +$ athena avd logs wxga720-api-24 + +$ # e.g. get logs from a device that was started with a VNC port at 9001 +$ athena avd logs wxga720-api-24 --vnc-port=9001 +``` + +### terminal - Starts a shell inside the AVD container + +```bash +$ athena avd terminal [--help|...] + +$ # e.g. open a shell in a device that was started without any extra options +$ athena avd terminal wxga720-api-24 + +$ # e.g. open a shell in a device that was started with a VNC port at 9001 +$ athena avd terminal wxga720-api-24 --vnc-port=9001 +``` + +### cleanup - Remove AVD image from the host machine + +```bash +$ athena avd cleanup +``` + +### wizard - Step-by-step guide to create a new device profile + +```bash +$ athena avd wizard +``` + +## Profiles Explained + +* `api-.conf` - Contains the Android SDK information for a given API level +* `.env` - Contains the device ABI, the name, skin information and which API level to use (based on the file above) + +Both of these files are stored inside [Athena](https://github.com/athena-oss/athena) plugins/avd/docker directory. + +As soon as you add a new `.env` file inside the directory, mentioned above, it will be available for you automatically. + +If you your device uses a API level and the `api-.conf` does not exist, then you need to create it, otherwise the device will fail during build time. + +You can also use `athena avd wizard` to create a device profile step-by-step. + +## Contributing + +Checkout our guidelines on how to contribute in [CONTRIBUTING.md](CONTRIBUTING.md). + +## Versioning + +Releases are managed using github's release feature. We use [Semantic Versioning](http://semver.org) for all +the releases. Every change made to the code base will be referred to in the release notes (except for +cleanups and refactorings). + +## License + +Licensed under the [Apache License Version 2.0 (APLv2)](LICENSE). diff --git a/bin/cmd/cleanup_pre.sh b/bin/cmd/cleanup_pre.sh new file mode 100644 index 0000000..575a327 --- /dev/null +++ b/bin/cmd/cleanup_pre.sh @@ -0,0 +1,18 @@ +CMD_DESCRIPTION="Remove AVD image from the host machine." + +athena.usage 1 "" + +profile="$(athena.arg 1)" +athena.pop_args 1 + +athena.plugin.set_environment "$profile" + +image_name="$(athena.plugin.get_tag_name)" +image_version="$(athena.plugin.get_image_version)" + +if ! athena.docker.image_exists "$image_name" "$image_version"; then + athena.fatal "Image for '${profile}' was not found..." +fi + +athena.docker.stop_all_containers "$(athena.plugin.get_prefix_for_container_name avd)" --global +athena.docker.rmi "${image_name}:${image_version}" diff --git a/bin/cmd/logs_pre.sh b/bin/cmd/logs_pre.sh new file mode 100644 index 0000000..9907d8f --- /dev/null +++ b/bin/cmd/logs_pre.sh @@ -0,0 +1,40 @@ +CMD_DESCRIPTION="Retrieve AVD logs." + +if athena.arg_exists "--help"; then + athena.argument.set_arguments +fi + +athena.usage 1 " [--help|...]" "$(cat < ; Profile with which you started the server. + [--vnc-port=] ; VNC port with which you started the server. + [--adb-port=] ; ADB port with which you started the server. +EOF +)" + +profile=$(athena.arg 1) +athena.pop_args 1 +athena.plugin.set_environment "$profile" + +instance_id= +if athena.argument.argument_exists_and_remove "--adb-port" "adb_port"; then + instance_id="${instance_id}${adb_port}" +fi + +if athena.argument.argument_exists_and_remove "--vnc-port" "vnc_port"; then + instance_id="${instance_id}${vnc_port}" +fi + +if [[ -n "$instance_id" ]]; then + athena.os.set_instance "$instance_id" +fi + +if ! athena.docker.is_current_container_running; then + athena.fatal "AVD container ($(athena.plugin.get_container_name)) is not running..." +fi + +follow= +if athena.argument.argument_exists_and_remove "-f"; then + follow="-f" +fi + +athena.docker.print_or_follow_container_logs "$(athena.plugin.get_container_name)" $follow diff --git a/bin/cmd/start.sh b/bin/cmd/start.sh new file mode 100644 index 0000000..dfd4216 --- /dev/null +++ b/bin/cmd/start.sh @@ -0,0 +1,28 @@ +port=5555 +docker_ip=$(ip addr list eth0|grep "inet "|cut -d' ' -f6|cut -d/ -f1) +redir --laddr=${docker_ip} --lport=$port --caddr=127.0.0.1 --cport=$port & + +. /etc/environment + +emulator_opts=("-no-window" "-no-audio" "-gpu off" "-verbose") + +if [[ -n "$ANDROID_SCREEN_SKIN" ]]; then + emulator_opts+=("-skin ${ANDROID_SCREEN_SKIN}") +fi + +if athena.argument.argument_exists_and_remove "--emulator-opts" "other_opts"; then + emulator_opts+=("$other_opts") +fi +emulator_opts+=("-qemu -vnc :0") + +cmd="emulator64-${ANDROID_ARCH_NAME} -avd ${ANDROID_DEVICE_NAME} ${emulator_opts[@]}" +athena.info "executing command: $cmd" +$cmd & + +sleep 2 +emulator_pid=$! +athena.plugins.avd.await_virtual_device_boot +athena.plugins.avd.unlock_virtual_device + +adb kill-server +wait $emulator_pid diff --git a/bin/cmd/start_post.sh b/bin/cmd/start_post.sh new file mode 100644 index 0000000..8d80a75 --- /dev/null +++ b/bin/cmd/start_post.sh @@ -0,0 +1,20 @@ +failcounter=0 +timeout_in_sec=600 +container_name="$(athena.plugin.get_container_name)" + +athena.info "Waiting for device '${container_name}' to be ready..." + +while :; do + if athena.docker.logs "$(athena.plugin.get_container_name)" | grep -i "EMULATOR IS READY" &>/dev/null; then + echo + break + fi + + if [[ $failcounter -gt $timeout_in_sec ]]; then + athena.fatal "Timeout ($timeout_in_sec seconds) reached; failed to start device" + fi + + echo -n "." + let "failcounter += 1" + sleep 1 +done diff --git a/bin/cmd/start_pre.sh b/bin/cmd/start_pre.sh new file mode 100644 index 0000000..bd1ff7e --- /dev/null +++ b/bin/cmd/start_pre.sh @@ -0,0 +1,46 @@ +CMD_DESCRIPTION="Starts the AVD." + +if athena.arg_exists "--help"; then + athena.argument.set_arguments +fi + +athena.usage 1 " [--help|...]" "$(cat <<'EOF' + [--emulator-opts="..."] ; Extra options for the emulator. + [--vnc-port=] ; Port where the VNC will be listening at for connections. + [--adb-port=] ; Port where the android debug bridge will be listening at. + [--list-profiles] ; Get a list of available profiles. +EOF +)" + +if athena.arg_exists "--list-profiles"; then + athena.info "Available profiles:" + for file in $(athena.plugin.get_plg_docker_dir "$(athena.plugin.get_plg)")/*.env; do + athena.info "* $(basename ${file%.env})" + done + athena.os.exit +fi + +profile=$(athena.arg 1) +athena.pop_args 1 + +athena.plugin.set_environment "$profile" +athena.docker.add_daemon + +instance_id= +if athena.argument.argument_exists_and_remove "--adb-port" "adb_port"; then + athena.docker.add_option "-p ${adb_port}:5555" + instance_id="${instance_id}${adb_port}" +fi + +if athena.argument.argument_exists_and_remove "--vnc-port" "vnc_port"; then + athena.docker.add_option "-p ${vnc_port}:5900" + instance_id="${instance_id}${vnc_port}" +fi + +if [[ -n "$instance_id" ]]; then + athena.os.set_instance "$instance_id" +fi + +if athena.docker.is_current_container_running; then + athena.fatal "There's already an AVD with the same profile running ('$(athena.plugin.get_container_name)')..." +fi diff --git a/bin/cmd/stop_pre.sh b/bin/cmd/stop_pre.sh new file mode 100644 index 0000000..791aac1 --- /dev/null +++ b/bin/cmd/stop_pre.sh @@ -0,0 +1,34 @@ +CMD_DESCRIPTION="Stops the AVD." + +if athena.arg_exists "--help"; then + athena.argument.set_arguments +fi + +athena.usage 1 " [--help|...]" "$(cat < ; Profile with which you started the server. + [--vnc-port=] ; VNC port with which you started the server. + [--adb-port=] ; ADB port with which you started the server. +EOF +)" + +profile=$(athena.arg 1) +athena.plugin.set_environment "$profile" + +instance_id= +if athena.argument.argument_exists_and_remove "--adb-port" "adb_port"; then + instance_id="${instance_id}${adb_port}" +fi + +if athena.argument.argument_exists_and_remove "--vnc-port" "vnc_port"; then + instance_id="${instance_id}${vnc_port}" +fi + +if [[ -n "$instance_id" ]]; then + athena.os.set_instance "$instance_id" +fi + +if ! athena.docker.is_current_container_running; then + athena.fatal "AVD container '$(athena.plugin.get_container_name)' is not running..." +fi + +athena.docker.stop_container diff --git a/bin/cmd/terminal_pre.sh b/bin/cmd/terminal_pre.sh new file mode 100644 index 0000000..a1507e8 --- /dev/null +++ b/bin/cmd/terminal_pre.sh @@ -0,0 +1,35 @@ +CMD_DESCRIPTION="Starts a shell inside the AVD container." + +if athena.arg_exists "--help"; then + athena.argument.set_arguments +fi + +athena.usage 1 " [--help|...]" "$(cat < ; Profile with which you started the server. + [--vnc-port=] ; VNC port with which you started the server. + [--adb-port=] ; ADB port with which you started the server. +EOF +)" + +profile=$(athena.arg 1) +athena.pop_args 1 +athena.plugin.set_environment "$profile" + +instance_id= +if athena.argument.argument_exists_and_remove "--adb-port" "adb_port"; then + instance_id="${instance_id}${adb_port}" +fi + +if athena.argument.argument_exists_and_remove "--vnc-port" "vnc_port"; then + instance_id="${instance_id}${vnc_port}" +fi + +if [[ -n "$instance_id" ]]; then + athena.os.set_instance "$instance_id" +fi + +if ! athena.docker.is_current_container_running; then + athena.fatal "AVD container '$(athena.plugin.get_container_name)' is not running..." +fi + +athena.docker.exec -ti "$(athena.plugin.get_container_name)" /usr/bin/env bash diff --git a/bin/cmd/wizard_pre.sh b/bin/cmd/wizard_pre.sh new file mode 100644 index 0000000..0dc9eae --- /dev/null +++ b/bin/cmd/wizard_pre.sh @@ -0,0 +1,58 @@ +CMD_DESCRIPTION="Step-by-step guide to create a new device profile." + +function _ask() +{ + local question="$1" + local regex="$2" + local default="$3" + local answer= + + while :; do + athena.print "cyan" "[Plugin] " "$question" 1>&2 + read answer + + if [[ -z "$answer" ]] && [[ -n "$default" ]]; then + answer="$default" + break + elif [[ ! "$answer" =~ $regex ]]; then + athena.error "Invalid value. Must match the following expression: ${regex}..." 1>&2 + continue + fi + + break + done + + echo "$answer" + echo 1>&2 +} + +function _get_docker_dir() +{ + echo $(athena.plugin.get_plg_docker_dir "$(athena.plugin.get_plugin)") +} + +profile_name="$(_ask "What is the name of the profile ?" "^[a-z0-9-]{1,14}$")" +device_abi="$(_ask "What is the device ABI (default/armeabi-v7a) ?" ".*" "default/armeabi-v7a")" +device_skin="$(_ask "What is the device skin name (WXGA720) ?" ".*" "WXGA720")" + +athena.print "cyan" "[Plugin] " "Select an API level:" +select device_api_level in $(ls $(_get_docker_dir)/api-*.conf | sed "s/.*api-\([^.]*\).conf/\1/"); do + if [[ -n "$device_api_level" ]]; then + break + fi +done + +save_profile="$(_ask "Save the profile (Y/n) ?" "^[Yn]$" "Y")" +if [[ "$save_profile" != "Y" ]]; then + athena.os.exit +fi + +profile_file="$(_get_docker_dir)/${profile_name}.env" +cat < $profile_file +ANDROID_DEVICE_NAME=${profile_name} +ANDROID_ABI=${device_abi} +ANDROID_SCREEN_SKIN=${device_skin} +ANDROID_API_LEVEL=${device_api_level} +EOF + +athena.info "Profile saved to '${profile_file}'..." diff --git a/bin/lib/functions.container.sh b/bin/lib/functions.container.sh new file mode 100644 index 0000000..d59be4e --- /dev/null +++ b/bin/lib/functions.container.sh @@ -0,0 +1,29 @@ +function athena.plugins.avd.await_virtual_device_boot() +{ + if ! ps -ef | grep -n "emulator64-${ANDROID_ARCH_NAME}" | grep -v "grep" >/dev/null; then + echo "Cannot wait for device. No devices were found running..." 1>&2 + exit 1 + fi + + bootanim= + failcounter=0 + echo "Waiting for device to boot. This may take several minutes..." + while [[ ! "$bootanim" =~ "stopped" ]]; do + bootanim=$(adb -e wait-for-device shell getprop init.svc.bootanim 2>&1) + if [[ "$bootanim" =~ "not found" ]]; then + let "failcounter += 1" + if [[ $failcounter -gt 3 ]]; then + echo "Failed to start emulator" 1>&2 + exit 1 + fi + fi + echo -n "." + sleep 1 + done + echo "EMULATOR IS READY TO USE" +} + +function athena.plugins.avd.unlock_virtual_device() +{ + adb shell input keyevent 82 +} diff --git a/dependencies.ini b/dependencies.ini new file mode 100644 index 0000000..c4ca4a5 --- /dev/null +++ b/dependencies.ini @@ -0,0 +1 @@ +base=0.9.0 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..c3dc459 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,36 @@ +FROM java:8-jdk + +ARG ANDROID_DEVICE_NAME +ARG ANDROID_ABI +ARG ANDROID_SCREEN_SKIN +ARG ANDROID_API_LEVEL +ARG ADNROID_EXTRA_OPTS="" + +ENV ANDROID_DEVICE_NAME $ANDROID_DEVICE_NAME +ENV ANDROID_HOME /opt/android-sdk-linux +ENV ANDROID_SDK_ROOT $ANDROID_HOME +ENV PATH $PATH:${ANDROID_HOME}/tools:$ANDROID_HOME/platform-tools + +# Install dependencies +RUN apt-get update && apt-get install -y redir libc6-i386 lib32stdc++6 wget && \ + apt-get clean && \ + apt-get autoclean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Needed to be able to run VNC - bug of Android SDK +RUN mkdir -p ${ANDROID_HOME}/tools/keymaps && touch ${ANDROID_HOME}/tools/keymaps/en-us + +# install dependencies +RUN mkdir -p /root/.android +COPY api-${ANDROID_API_LEVEL}.conf /etc/environment +COPY install_dependencies.sh /tmp/install_dependencies.sh +RUN /tmp/install_dependencies.sh + +# create avd +RUN echo n | android create avd -t android-${ANDROID_API_LEVEL} -n ${ANDROID_DEVICE_NAME} --abi ${ANDROID_ABI} -s ${ANDROID_SCREEN_SKIN} ${ANDROID_EXTRA_OPTS} + +# Device ADB Console +EXPOSE 5555 + +# Device VNC +EXPOSE 5900 diff --git a/docker/api-24.conf b/docker/api-24.conf new file mode 100644 index 0000000..11f6ce9 --- /dev/null +++ b/docker/api-24.conf @@ -0,0 +1,6 @@ +ANDROID_API_LEVEL=24 +ANDROID_VERSION=7.0 +ANDROID_SDK_URL=http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz +ANDROID_SDK_STRING="Google APIs ARM EABI v7a System Image, Android API 24" +ANDROID_ARCH_NAME=arm +ANDROID_ARCH_IMAGE=armeabi-v7a diff --git a/docker/install_dependencies.sh b/docker/install_dependencies.sh new file mode 100755 index 0000000..64e03d7 --- /dev/null +++ b/docker/install_dependencies.sh @@ -0,0 +1,11 @@ +# load the environmnent +. /etc/environment + +# install SDK +wget -qO- "$ANDROID_SDK_URL" | tar -zx -C /opt +echo y | android update sdk --no-ui --all --filter platform-tools --force + +# install dependencies for emulator +echo y | android update sdk --no-ui --all -t `android list sdk --all | grep "SDK Platform Android ${ANDROID_VERSION}, API ${ANDROID_API_LEVEL}" | awk -F'[^0-9]*' '{print $2}'` +echo y | android update sdk --no-ui --all -t `android list sdk --all | grep "$ANDROID_SDK_STRING" | awk -F'[^0-9]*' '{print $2}'` +echo y | android update sdk --no-ui --all --filter sys-img-${ANDROID_ARCH_IMAGE}-android-${ANDROID_API_LEVEL} --force diff --git a/docker/wxga720-api-24.env b/docker/wxga720-api-24.env new file mode 100644 index 0000000..95af7c5 --- /dev/null +++ b/docker/wxga720-api-24.env @@ -0,0 +1,4 @@ +ANDROID_DEVICE_NAME=wxga720 +ANDROID_ABI=default/armeabi-v7a +ANDROID_SCREEN_SKIN=WXGA720 +ANDROID_API_LEVEL=24 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..86ef8ef --- /dev/null +++ b/docs/README.md @@ -0,0 +1,114 @@ +# AVD Plugin [![Build Status](https://travis-ci.org/athena-oss/plugin-avd.svg?branch=master)](https://travis-ci.org/athena-oss/plugin-avd) + +This plugins provides a straightforward API to manage Android Virtual Devices. + +You can easily use this plugin in your local development machine or in a CI/CD pipeline. + +## How to Install ? + +To install it simply run the following command : + +```bash +$ athena plugins install avd https://github.com/athena-oss/plugin-avd.git +``` + +or + +* On MAC OSX using [Homebrew](http://brew.sh/) : +```bash +$ brew tap athena-oss/tap +$ brew install plugin-avd +``` + +Read the [Documentation](http://athena-oss.github.io/plugin-avd) on using the [Athena](https://github.com/athena-oss/athena) AVD plugin. + +## How to Use ? + +This plugin provides the following commands: + +### start - Starts the AVD + +```bash +$ athena avd start [--help|...] + +$ # e.g. start one of the pre-defined devices +$ athena avd start wxga720-api-24 + +$ # e.g. start a pre-defined device and open a VNC at port 9001 +$ athena avd start wxga720-api-24 --vnc-port=9001 +``` + +### stop - Stops the AVD + +```bash +$ athena avd stop [--help|...] + +$ # e.g. stop a device that was started without any extra options +$ athena avd stop wxga720-api-24 + +$ # e.g. stop a device that was started with a VNC port at 9001 +$ athena avd stop wxga720-api-24 --vnc-port=9001 +``` + +### logs - Retrieve AVD logs + +```bash +$ athena avd logs [--help|...] + +$ # e.g. get logs from a device that was started without any extra options +$ athena avd logs wxga720-api-24 + +$ # e.g. get logs from a device that was started with a VNC port at 9001 +$ athena avd logs wxga720-api-24 --vnc-port=9001 +``` + +### terminal - Starts a shell inside the AVD container + +```bash +$ athena avd terminal [--help|...] + +$ # e.g. open a shell in a device that was started without any extra options +$ athena avd terminal wxga720-api-24 + +$ # e.g. open a shell in a device that was started with a VNC port at 9001 +$ athena avd terminal wxga720-api-24 --vnc-port=9001 +``` + +### cleanup - Remove AVD image from the host machine + +```bash +$ athena avd cleanup +``` + +### wizard - Step-by-step guide to create a new device profile + +```bash +$ athena avd wizard +``` + +## Profiles Explained + +* `api-.conf` - Contains the Android SDK information for a given API level +* `.env` - Contains the device ABI, the name, skin information and which API level to use (based on the file above) + +Both of these files are stored inside [Athena](https://github.com/athena-oss/athena) plugins/avd/docker directory. + +As soon as you add a new `.env` file inside the directory, mentioned above, it will be available for you automatically. + +If you your device uses a API level and the `api-.conf` does not exist, then you need to create it, otherwise the device will fail during build time. + +You can also use `athena avd wizard` to create a device profile step-by-step. + +## Contributing + +Checkout our guidelines on how to contribute in [CONTRIBUTING.md](CONTRIBUTING.md). + +## Versioning + +Releases are managed using github's release feature. We use [Semantic Versioning](http://semver.org) for all +the releases. Every change made to the code base will be referred to in the release notes (except for +cleanups and refactorings). + +## License + +Licensed under the [Apache License Version 2.0 (APLv2)](LICENSE). diff --git a/docs/_layouts/website/page.html b/docs/_layouts/website/page.html new file mode 100644 index 0000000..545cfcf --- /dev/null +++ b/docs/_layouts/website/page.html @@ -0,0 +1,53 @@ +{% extends template.self %} + +{% block head %} + +{% endblock %} diff --git a/docs/publish_docs b/docs/publish_docs new file mode 100755 index 0000000..bb8184f --- /dev/null +++ b/docs/publish_docs @@ -0,0 +1,39 @@ +#!/bin/bash -e + +function error() { + echo "ERROR: $1" + exit 1 +} + +function info() { + echo "INFO: $1" +} + +if [[ "$TRAVIS_BRANCH" != "master" ]] || [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then + info "Only commits pushed to origin master will trigger documentation publishing." + exit 0 +fi + +GITBOOK_DOCS_DIR="$TRAVIS_BUILD_DIR/docs" +GITBOOK_HTML_OUTPUT_DIR="$TRAVIS_BUILD_DIR/docs/_book" + +if [[ ! -d "$GITBOOK_DOCS_DIR" ]]; then + error "Documentation dir $GITBOOK_DOCS_DIR does not exist or it's not a valid directory." +fi + +gitbook build "$GITBOOK_DOCS_DIR" "$GITBOOK_HTML_OUTPUT_DIR" + +pushd "$GITBOOK_HTML_OUTPUT_DIR" +git init +git config --global user.name "Travis CI" +git config --global user.email "athena@olx.com" + +git remote add upstream "https://$GH_TOKEN@github.com/athena-oss/plugin-avd.git" +git fetch upstream +git reset upstream/gh-pages + +git add -A . +git commit -m"Automatic page rebuild for $TRAVIS_COMMIT." +git push -q upstream HEAD:gh-pages +popd + diff --git a/tests/bashunit-bootstrap.sh b/tests/bashunit-bootstrap.sh new file mode 100644 index 0000000..fdd4e27 --- /dev/null +++ b/tests/bashunit-bootstrap.sh @@ -0,0 +1,12 @@ +function athena.get_current_script_dir() +{ + if [[ -n "$ATHENA_DIR" ]]; then + echo "$ATHENA_DIR" + return + fi + + dirname "$BASHUNIT_TESTS_DIR/../../../.." +} +curr_script_dir="$(athena.get_current_script_dir)" +source "$curr_script_dir/bootstrap/variables.sh" +source "$curr_script_dir/bootstrap/host.functions.sh" diff --git a/tests/test.cmds.sh b/tests/test.cmds.sh new file mode 100644 index 0000000..006232f --- /dev/null +++ b/tests/test.cmds.sh @@ -0,0 +1,12 @@ +function testcase_start_device_and_check_if_running() +{ + $(athena.get_current_script_dir)/athena avd start wxga720-api-24 & + wait + + bashunit.test.assert_return "_is_avd_ready" +} + +function _is_avd_ready() +{ + (athena.docker.logs "athena-plugin-avd-wxga720-api-24-0" | grep "EMULATOR IS READY") +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.3.0