Compare commits

..

10 commits

Author SHA1 Message Date
Mathieu Virbel
825c92a613
Merge pull request #592 from jsoref/spelling
Spelling
2017-12-17 19:52:53 +01:00
Josh Soref
655096f555 spelling: specificities 2017-11-30 07:06:58 +00:00
Josh Soref
90a8c2c0f9 spelling: separators 2017-11-30 07:05:27 +00:00
Josh Soref
0e353c7ffa spelling: separate 2017-11-30 07:05:07 +00:00
Josh Soref
46355322a8 spelling: run 2017-11-30 07:04:53 +00:00
Josh Soref
c00634ddd8 spelling: regularly 2017-11-30 07:03:27 +00:00
Josh Soref
24a30ce542 spelling: preferable 2017-11-30 07:02:12 +00:00
Josh Soref
472254260b spelling: heavily 2017-11-30 06:58:56 +00:00
Josh Soref
365593c997 spelling: additional 2017-11-30 06:53:52 +00:00
Josh Soref
accc6b346b spelling: across 2017-11-30 06:53:34 +00:00
43 changed files with 1153 additions and 3751 deletions

View file

@ -1,25 +0,0 @@
version = 1
test_patterns = ["tests/**"]
[[analyzers]]
name = "python"
enabled = true
[analyzers.meta]
runtime_version = "3.x.x"
[[analyzers]]
name = "docker"
enabled = true
[analyzers.meta]
dockerfile_paths = [
"dockerfile_dev",
"dockerfile_prod"
]
[[analyzers]]
name = "ruby"
enabled = true

View file

@ -1,38 +0,0 @@
<!--
The issue tracker is a tool to address bugs.
For support questions, please use: https://github.com/kivy/buildozer#support
Before opening a new issue, make sure you do the following:
* check that your issue isn't already filed: https://github.com/kivy/buildozer/issues
* prepare a short, runnable example that reproduces the issue
* make sure to have `log_level = 2` in your `buildozer.spec`
* reproduce the problem with the latest development version of Kivy
* double-check that the issue is indeed a bug and not a support request
-->
### Versions
* Python:
* OS:
* Buildozer:
### Description
// REPLACE ME: What are you trying to get done, what has happened, what went wrong, and what did you expect?
### buildozer.spec
Command:
```sh
// REPLACE ME: buildozer command ran? e.g. buildozer android debug
```
Spec file:
```
// REPLACE ME: Paste your buildozer.spec file here
```
### Logs
```
// REPLACE ME: Paste the build ouput containing the error
```

19
.github/support.yml vendored
View file

@ -1,19 +0,0 @@
# Configuration for support-requests - https://github.com/dessant/support-requests
# Label used to mark issues as support requests
supportLabel: support
# Comment to post on issues marked as support requests. Add a link
# to a support page, or set to `false` to disable
supportComment: >
:wave: @{issue-author}, we use the issue tracker exclusively for bug reports
and feature requests. However, this issue appears to be a support request.
Please use our [support channels](https://github.com/kivy/buildozer#support)
to get help with the project.
Let us know if this comment was made in error, and we'll be happy
to reopen the issue.
# Whether to close issues marked as support requests
close: true
# Whether to lock issues marked as support requests
lock: false

View file

@ -1,40 +0,0 @@
on: [push, pull_request]
name: Android
jobs:
Integration:
strategy:
matrix:
os:
- 'ubuntu-latest'
- 'macOs-latest'
runs-on: ${{ matrix.os }}
steps:
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v2
- name: Setup environment
run: |
pip install -e .
pip install Cython
- run: buildozer --help
- run: buildozer init
- name: SDK, NDK and p4a download
run: |
sed -i.bak "s/# android.accept_sdk_license = False/android.accept_sdk_license = True/" buildozer.spec
sed -i.bak "s/#p4a.branch = master/p4a.branch = develop/" buildozer.spec
buildozer android p4a -- --help
# Install OS specific dependencies
- name: Install Linux dependencies
if: matrix.os == 'ubuntu-latest'
run: sudo apt -y install automake
- name: Install macOS dependencies
if: matrix.os == 'macOS-latest'
run: |
brew install automake
sudo ln -sfn /usr/local/opt/openssl /usr/local/ssl
- name: buildozer android debug
run: |
touch main.py
buildozer android debug

View file

@ -1,24 +0,0 @@
on: [push, pull_request]
name: iOS
jobs:
Integration:
runs-on: macOS-latest
steps:
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v2
- name: Setup environment
run: |
pip install -e .
pip install Cython cookiecutter pbxproj
- run: buildozer --help
- run: buildozer init
- name: Install dependencies
run: |
brew install autoconf automake libtool pkg-config
- name: buildozer ios debug
run: |
touch main.py
buildozer ios debug

View file

@ -1,25 +0,0 @@
name: PyPI release
on: [push]
jobs:
pypi_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade setuptools wheel twine
- name: Build
run: |
python setup.py sdist bdist_wheel
twine check dist/*
- name: Publish package
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@v1.1.0
with:
user: __token__
password: ${{ secrets.pypi_password }}

View file

@ -1,60 +0,0 @@
on: [push, pull_request]
name: Tests
jobs:
Tests:
name: base
strategy:
matrix:
python:
- '3.6'
- '3.7'
- '3.8'
os:
- 'ubuntu-latest'
- 'macOs-latest'
architecture:
- 'x64'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Requirements
run: |
pip install -U coveralls setuptools tox>=2.0
- name: Tox
run: tox
- name: Coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_SERVICE_NAME: github
run: coveralls
Docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Docker build
run: docker build --tag=kivy/buildozer .
- name: Docker run
run: docker run kivy/buildozer --version
Python2:
runs-on: ubuntu-latest
steps:
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: 2.7
- uses: actions/checkout@v2
- name: Try Python 2 install
run: |
# we don't want the build to fail with the exit 1 so we catch with "||"
python2 -m pip install -e . 2> error.log || echo Failing as expected
cat error.log
grep "Unsupported Python version" error.log

View file

@ -1,581 +1,5 @@
# Change Log # Change Log
## [1.2.0](https://github.com/kivy/buildozer/tree/1.2.0) (2020-05-30)
[Full Changelog](https://github.com/kivy/buildozer/compare/1.1.0...1.2.0)
**Merged pull requests:**
- Bumps to latest Cython version [\#1132](https://github.com/kivy/buildozer/pull/1132) ([AndreMiras](https://github.com/AndreMiras))
- Also integration test on macOS [\#1131](https://github.com/kivy/buildozer/pull/1131) ([AndreMiras](https://github.com/AndreMiras))
- Tests android.numeric\_version config [\#1129](https://github.com/kivy/buildozer/pull/1129) ([AndreMiras](https://github.com/AndreMiras))
- Refactored the TargetAndroid tests [\#1127](https://github.com/kivy/buildozer/pull/1127) ([pavelsof](https://github.com/pavelsof))
- Adds p4a --numeric-version support [\#1126](https://github.com/kivy/buildozer/pull/1126) ([AndreMiras](https://github.com/AndreMiras))
- Linter fixes and README.md update [\#1118](https://github.com/kivy/buildozer/pull/1118) ([AndreMiras](https://github.com/AndreMiras))
- Removes Python 2 constructions [\#1114](https://github.com/kivy/buildozer/pull/1114) ([AndreMiras](https://github.com/AndreMiras))
## [1.1.0](https://github.com/kivy/buildozer/tree/1.1.0) (2020-05-18)
[Full Changelog](https://github.com/kivy/buildozer/compare/1.0...1.1.0)
**Fixed bugs:**
- [Docker image] SSLError("Can't connect to HTTPS URL because the SSL module is not available.") [\#1096](https://github.com/kivy/buildozer/issues/1096)
- NameError: name 'raw\_input' is not defined [\#1070](https://github.com/kivy/buildozer/issues/1070)
- Setup coverage testing [\#1058](https://github.com/kivy/buildozer/issues/1058)
- AttributeError: 'function' object has no attribute 'glob' [\#1044](https://github.com/kivy/buildozer/issues/1044)
**Closed issues:**
- Pygallary [\#1109](https://github.com/kivy/buildozer/issues/1109)
- Buildozer compilation ERROR: No matching distribution found for hostpython2 (from -r requirements.txt (line 2)) [\#1104](https://github.com/kivy/buildozer/issues/1104)
- Circular errors with Java version and Android SDK [\#1103](https://github.com/kivy/buildozer/issues/1103)
- APK not running on Android 10? [\#1102](https://github.com/kivy/buildozer/issues/1102)
- Buildozer command fails: Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate [\#1095](https://github.com/kivy/buildozer/issues/1095)
- Command Failed Error [\#1092](https://github.com/kivy/buildozer/issues/1092)
- APK Can't be install (package can't be install in android) [\#1091](https://github.com/kivy/buildozer/issues/1091)
- buildozer Install python 3.8.1 [\#1090](https://github.com/kivy/buildozer/issues/1090)
- i have weak reference error while using python 3.8 [\#1089](https://github.com/kivy/buildozer/issues/1089)
- buildozer is choosing odd venv, and using a different python? [\#1080](https://github.com/kivy/buildozer/issues/1080)
- Fatal Python error: init\_fs\_encoding: failed to get the Python codec of the filesystem encoding [\#1076](https://github.com/kivy/buildozer/issues/1076)
- Buildozer just wont compile my app [\#1074](https://github.com/kivy/buildozer/issues/1074)
- Autoreconf not found? [\#1072](https://github.com/kivy/buildozer/issues/1072)
- error while buildozer android debug deploy run [\#1064](https://github.com/kivy/buildozer/issues/1064)
- Syntax error in Kivy and KivyMD dependencies file when using Buildozer to compile KivyMD app [\#1051](https://github.com/kivy/buildozer/issues/1051)
- Adding CFFI as a Buildozer requirement breaks the Android build [\#1050](https://github.com/kivy/buildozer/issues/1050)
- Is buildozer compatible with Python 3.7 [\#1048](https://github.com/kivy/buildozer/issues/1048)
- Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0 [\#1042](https://github.com/kivy/buildozer/issues/1042)
- Error while running buildozer android debug deploy [\#1038](https://github.com/kivy/buildozer/issues/1038)
- cant able to build apk on linux with python3 [\#1033](https://github.com/kivy/buildozer/issues/1033)
- Keystore was tampered with, or password was incorrect [\#1028](https://github.com/kivy/buildozer/issues/1028)
- Windows support to build Android APK [\#1022](https://github.com/kivy/buildozer/issues/1022)
- How to make third party site-packages 'requests' run on Android [\#1021](https://github.com/kivy/buildozer/issues/1021)
- Crash on buildozer android debug command. Command failed: /usr/bin/python -m pythonforandroid.toolchain [\#1017](https://github.com/kivy/buildozer/issues/1017)
- Build failed: Couldn't find executable for CC [\#1014](https://github.com/kivy/buildozer/issues/1014)
- Cloning Error of python-for-android [\#1008](https://github.com/kivy/buildozer/issues/1008)
- checking whether the C compiler works... no [\#1007](https://github.com/kivy/buildozer/issues/1007)
- Kivy :How to ask for storage permission when app starts [\#1004](https://github.com/kivy/buildozer/issues/1004)
- Buildozer :No module named 'numpy.core.\_multiarray\_umath' [\#1002](https://github.com/kivy/buildozer/issues/1002)
- Kivy app Crashes while import openpyxl [\#1001](https://github.com/kivy/buildozer/issues/1001)
- Warning when i run "buildozer -v android debug" [\#982](https://github.com/kivy/buildozer/issues/982)
- sdkmanager is notinstalled [\#927](https://github.com/kivy/buildozer/issues/927)
**Merged pull requests:**
- Update README.md [\#1111](https://github.com/kivy/buildozer/pull/1111) ([tshirtman](https://github.com/tshirtman))
- Fixes Docker apt cache missed [\#1107](https://github.com/kivy/buildozer/pull/1107) ([AndreMiras](https://github.com/AndreMiras))
- Adds libssl-dev to the install dependencies [\#1106](https://github.com/kivy/buildozer/pull/1106) ([AndreMiras](https://github.com/AndreMiras))
- Automatically publish to PyPI upon tagging [\#1105](https://github.com/kivy/buildozer/pull/1105) ([AndreMiras](https://github.com/AndreMiras))
- Fix punctuation and typo in README.md [\#1101](https://github.com/kivy/buildozer/pull/1101) ([hematogender](https://github.com/hematogender))
- Build integration test [\#1100](https://github.com/kivy/buildozer/pull/1100) ([AndreMiras](https://github.com/AndreMiras))
- Fixes missing libssl-dev dependency [\#1099](https://github.com/kivy/buildozer/pull/1099) ([AndreMiras](https://github.com/AndreMiras))
- Drops Python 2 support [\#1094](https://github.com/kivy/buildozer/pull/1094) ([AndreMiras](https://github.com/AndreMiras))
- Checks SDK, NDK and p4a get downloaded on first run [\#1093](https://github.com/kivy/buildozer/pull/1093) ([AndreMiras](https://github.com/AndreMiras))
- Integration testing [\#1083](https://github.com/kivy/buildozer/pull/1083) ([AndreMiras](https://github.com/AndreMiras))
- Also tests against macOS platform [\#1078](https://github.com/kivy/buildozer/pull/1078) ([AndreMiras](https://github.com/AndreMiras))
- Fix NameError with Python 3 and iOS target [\#1071](https://github.com/kivy/buildozer/pull/1071) ([lerela](https://github.com/lerela))
- Unit tests TargetAndroid.build\_package() [\#1069](https://github.com/kivy/buildozer/pull/1069) ([AndreMiras](https://github.com/AndreMiras))
- Dedicated Docker build/run job [\#1068](https://github.com/kivy/buildozer/pull/1068) ([AndreMiras](https://github.com/AndreMiras))
- F841: local variable is assigned to but never used [\#1066](https://github.com/kivy/buildozer/pull/1066) ([AndreMiras](https://github.com/AndreMiras))
- PEP8 organisation and fixes [\#1065](https://github.com/kivy/buildozer/pull/1065) ([AndreMiras](https://github.com/AndreMiras))
- Fixes coveralls.io on pull requests [\#1063](https://github.com/kivy/buildozer/pull/1063) ([AndreMiras](https://github.com/AndreMiras))
- Coveralls TOKEN is only available on branch master [\#1062](https://github.com/kivy/buildozer/pull/1062) ([AndreMiras](https://github.com/AndreMiras))
- Starts unit testing buildozer/targets/android.py [\#1061](https://github.com/kivy/buildozer/pull/1061) ([AndreMiras](https://github.com/AndreMiras))
- Setup coverage testing [\#1060](https://github.com/kivy/buildozer/pull/1060) ([AndreMiras](https://github.com/AndreMiras))
- Fix Dockerfile dependencies [\#1053](https://github.com/kivy/buildozer/pull/1053) ([Sirfanas](https://github.com/Sirfanas))
- Updates default buildozer.spec NDK from 17c to 19b [\#1041](https://github.com/kivy/buildozer/pull/1041) ([AndreMiras](https://github.com/AndreMiras))
- Fix config typo in default.spec [\#1026](https://github.com/kivy/buildozer/pull/1026) ([touilleMan](https://github.com/touilleMan))
- Android gradle build: fix apk name [\#1025](https://github.com/kivy/buildozer/pull/1025) ([SomberNight](https://github.com/SomberNight))
## [1.0](https://github.com/kivy/buildozer/tree/1.0) (2019-12-22)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.39...1.0)
**Fixed bugs:**
- Accept license terms prompt is not visible [\#916](https://github.com/kivy/buildozer/issues/916)
- Unable to build release. File "/usr/lib/python3.6/shutil.py", line 96, in copyfile with open\(src, 'rb'\) as fsrc: IOError: \[Errno 2\] No such file or directory: [\#851](https://github.com/kivy/buildozer/issues/851)
- error: cannot find -lpython3.7 [\#842](https://github.com/kivy/buildozer/issues/842)
- android.accept\_sdk\_license may misbehave [\#816](https://github.com/kivy/buildozer/issues/816)
- Python3 error with pexpect [\#221](https://github.com/kivy/buildozer/issues/221)
**Closed issues:**
- Sup Req : Buildozer debug does not complete - Error threading.py, sh.py, etc.. [\#1000](https://github.com/kivy/buildozer/issues/1000)
- Buildozer failed to execute the last command [\#999](https://github.com/kivy/buildozer/issues/999)
- Android fullscreen mode: cannot hide status bar! [\#989](https://github.com/kivy/buildozer/issues/989)
- buildozer uses wrong python version and disrespects requirement versions [\#988](https://github.com/kivy/buildozer/issues/988)
- The version of Kivy installed on this system is too old. [\#987](https://github.com/kivy/buildozer/issues/987)
- Failed to download any source lists! [\#986](https://github.com/kivy/buildozer/issues/986)
- Aidl cannot be executed error buildozer [\#984](https://github.com/kivy/buildozer/issues/984)
- buildozer debug error "\[WARNING\]" when i run buildozer andriod debug [\#980](https://github.com/kivy/buildozer/issues/980)
- Building kivy app with python3 requirement gives "No compiled python is present to zip, skipping." warning and "Unable to import kivy.\_clock. Have you perhaps forgotten to compile kivy? ..." error when run on android device. [\#977](https://github.com/kivy/buildozer/issues/977)
- Java And Python-for-android toolchain errors [\#975](https://github.com/kivy/buildozer/issues/975)
- buildozer + python3 [\#973](https://github.com/kivy/buildozer/issues/973)
- Error while running ".buildozer.../native-build/python -OO -m compileall -b -f /.../app [\#972](https://github.com/kivy/buildozer/issues/972)
- buildozer fails with kivymd link [\#968](https://github.com/kivy/buildozer/issues/968)
- ndk\_platform doesn't exist: /home/rr/android-ndk-r20/platforms/android-20/arch-arm [\#966](https://github.com/kivy/buildozer/issues/966)
- Paused at Installing/updating SDK platform tools if necessary [\#965](https://github.com/kivy/buildozer/issues/965)
- java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema [\#962](https://github.com/kivy/buildozer/issues/962)
- please add aidl into Dockerfile [\#960](https://github.com/kivy/buildozer/issues/960)
- Missing \_ctypes module [\#955](https://github.com/kivy/buildozer/issues/955)
- Kivy-Buildozer release version doesnt upload google store [\#953](https://github.com/kivy/buildozer/issues/953)
- buildozer using wrong kivy version [\#943](https://github.com/kivy/buildozer/issues/943)
- buildozer ndk-api=21 error [\#942](https://github.com/kivy/buildozer/issues/942)
- app crash [\#939](https://github.com/kivy/buildozer/issues/939)
- ERROR: JAVA\_HOME is set to an invalid directory: /usr/lib/jvm/java-8-oracle [\#929](https://github.com/kivy/buildozer/issues/929)
- no-issue [\#926](https://github.com/kivy/buildozer/issues/926)
- can't find file to patch toggle\_jpg\_png\_webp.patch [\#921](https://github.com/kivy/buildozer/issues/921)
- No matching distribution found for io [\#915](https://github.com/kivy/buildozer/issues/915)
- Error: No matching distribution found for io\(from -r requirements.txt \(line 5\)\) [\#914](https://github.com/kivy/buildozer/issues/914)
- I'm also experiencing the same issue, using macOS 10.14.3 and no Docker -- just plain Buildozer from the PyPi repo. What is the recommended course of action to fix this? [\#913](https://github.com/kivy/buildozer/issues/913)
- app crash [\#911](https://github.com/kivy/buildozer/issues/911)
- warnings while building apk using buildozer [\#910](https://github.com/kivy/buildozer/issues/910)
- buildozer error please help me!! [\#906](https://github.com/kivy/buildozer/issues/906)
- My application does not open in android but if it works in geany, help please. [\#903](https://github.com/kivy/buildozer/issues/903)
- \[Docker image\] Can't compile apk: /bin/tar ... "Cannot utime: Operation not permitted" [\#902](https://github.com/kivy/buildozer/issues/902)
- Fails to call numpy fft on android [\#899](https://github.com/kivy/buildozer/issues/899)
- Command failed: /usr/bin/python3 -m pythonforandroid.toolchain [\#898](https://github.com/kivy/buildozer/issues/898)
- error: C compiler cannot create executables [\#897](https://github.com/kivy/buildozer/issues/897)
- stopped at "Installing/updating SDK platform tools if necessary" [\#896](https://github.com/kivy/buildozer/issues/896)
- ValueError: Tried to access ndk\_ver but it has not been set - this should not happen, something went wrong! [\#893](https://github.com/kivy/buildozer/issues/893)
- Buildozer not installing from custom source folders [\#892](https://github.com/kivy/buildozer/issues/892)
- Error with build requirements PIL \(Python 3\) [\#890](https://github.com/kivy/buildozer/issues/890)
- rocker plants.cvs -an active -r -p rco.png [\#889](https://github.com/kivy/buildozer/issues/889)
- rocker plants.cvs -an active -r -p rco.png [\#888](https://github.com/kivy/buildozer/issues/888)
- rocker plants.cvs -an active -r -p rco.png [\#887](https://github.com/kivy/buildozer/issues/887)
- rocker plants.cvs -an active -r -p rco.png [\#886](https://github.com/kivy/buildozer/issues/886)
- rocker plants.cvs -an active -r -p rco.png [\#885](https://github.com/kivy/buildozer/issues/885)
- host=arm-linux-androideabi [\#884](https://github.com/kivy/buildozer/issues/884)
- Buildozer has attribute errors and will not run [\#883](https://github.com/kivy/buildozer/issues/883)
- buildozer on osx not working [\#879](https://github.com/kivy/buildozer/issues/879)
- Android API Issue [\#877](https://github.com/kivy/buildozer/issues/877)
- What is the way to add folders and files? [\#875](https://github.com/kivy/buildozer/issues/875)
- Buildozer Error [\#874](https://github.com/kivy/buildozer/issues/874)
- Problem with "Unpacking sdl2\_image" and "Parent module 'pythonforandroid.recipes' not found" [\#872](https://github.com/kivy/buildozer/issues/872)
- buildozer android debug deploy is stuck [\#870](https://github.com/kivy/buildozer/issues/870)
- running autoreconf -vif [\#866](https://github.com/kivy/buildozer/issues/866)
- Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema [\#862](https://github.com/kivy/buildozer/issues/862)
- Can not build x86 APK file [\#861](https://github.com/kivy/buildozer/issues/861)
- But then a lot more issues, deep in the weeds now. [\#858](https://github.com/kivy/buildozer/issues/858)
- Create tests for PR fix bug when logcat value which cannot be decode to utf-8 [\#857](https://github.com/kivy/buildozer/issues/857)
- Can't Cythonize pyjnius: TypeError: can't pickle Argument objects [\#850](https://github.com/kivy/buildozer/issues/850)
- buildozer -h complains about NoneType target [\#849](https://github.com/kivy/buildozer/issues/849)
- Building failes at compiling openssl\[armeabi-v7a\] [\#841](https://github.com/kivy/buildozer/issues/841)
- Applying patches for libffi\[armeabi-v7a\] [\#840](https://github.com/kivy/buildozer/issues/840)
- Errors while running buildozer android debug deploy [\#832](https://github.com/kivy/buildozer/issues/832)
- "Command failed" when running "buildozer android debug deploy run" [\#829](https://github.com/kivy/buildozer/issues/829)
- Build Python3 for Android with Azure-keyvault and merest [\#828](https://github.com/kivy/buildozer/issues/828)
- Outdated Android NDK download URL in Kivy Virtual Machine [\#827](https://github.com/kivy/buildozer/issues/827)
- App crashes on startup [\#826](https://github.com/kivy/buildozer/issues/826)
- I found the origin of the problem mentioned in issue \#694 \(Aidl not found\) [\#824](https://github.com/kivy/buildozer/issues/824)
- download\(\) is not CI log friendly [\#823](https://github.com/kivy/buildozer/issues/823)
- Application stuck in portrait mode [\#820](https://github.com/kivy/buildozer/issues/820)
- Orientation landscape when set to portrait [\#818](https://github.com/kivy/buildozer/issues/818)
- Certain python requirements fail due to `\_ctypes` [\#815](https://github.com/kivy/buildozer/issues/815)
- Running buildozer help crashes [\#813](https://github.com/kivy/buildozer/issues/813)
- \[Buildozer 0.40.dev0, Buildozer 0.39\] AttributeError: 'Buildozer' object has no attribute 'translate\_target' [\#812](https://github.com/kivy/buildozer/issues/812)
- Version number failing to be added to apk [\#810](https://github.com/kivy/buildozer/issues/810)
- Virtual machine out of date [\#764](https://github.com/kivy/buildozer/issues/764)
- Docker doesn't build [\#751](https://github.com/kivy/buildozer/issues/751)
- Buildozer exit code on recipe fail [\#674](https://github.com/kivy/buildozer/issues/674)
- not able to release apk in release mode - build failed [\#363](https://github.com/kivy/buildozer/issues/363)
- Issue with NDK r11b [\#308](https://github.com/kivy/buildozer/issues/308)
- Feature: Create a compat.py for correct PY3 support and implement it [\#300](https://github.com/kivy/buildozer/issues/300)
- Curl missing in KivyVM [\#296](https://github.com/kivy/buildozer/issues/296)
- Virtual machine image could have better support for international keyboards [\#295](https://github.com/kivy/buildozer/issues/295)
- Virtual machine image does not have enough disk space [\#294](https://github.com/kivy/buildozer/issues/294)
- Not quite an issue, just some dependency stuff [\#247](https://github.com/kivy/buildozer/issues/247)
- \# Command failed: ./distribute.sh -m "kivy" -d "stapp" [\#204](https://github.com/kivy/buildozer/issues/204)
- Command ./distribute.sh failed -- no buildozer.spec found when it exists [\#203](https://github.com/kivy/buildozer/issues/203)
- buildozer -v android debug : Compile fails at fcntlmodule.c [\#196](https://github.com/kivy/buildozer/issues/196)
- Build errors on OSX 10.10 \(for android\) [\#165](https://github.com/kivy/buildozer/issues/165)
- Feature Request: Vagrantfile [\#154](https://github.com/kivy/buildozer/issues/154)
**Merged pull requests:**
- Feature GitHub actions [\#1005](https://github.com/kivy/buildozer/pull/1005) ([tito](https://github.com/tito))
- Fixes test\_p4a\_recommended\_android\_ndk\_found\(\) mocking [\#983](https://github.com/kivy/buildozer/pull/983) ([AndreMiras](https://github.com/AndreMiras))
- Fixes packaging for current p4a develop branch [\#978](https://github.com/kivy/buildozer/pull/978) ([misl6](https://github.com/misl6))
- Updates install instructions and troubleshooting [\#976](https://github.com/kivy/buildozer/pull/976) ([AndreMiras](https://github.com/AndreMiras))
- fix: show output of sdk update if auto\_accept\_license is false [\#970](https://github.com/kivy/buildozer/pull/970) ([tshirtman](https://github.com/tshirtman))
- Add libs only for current arch [\#969](https://github.com/kivy/buildozer/pull/969) ([misl6](https://github.com/misl6))
- Rename final apk with arch in the name [\#967](https://github.com/kivy/buildozer/pull/967) ([tito](https://github.com/tito))
- Code improvements around NDK download [\#961](https://github.com/kivy/buildozer/pull/961) ([inclement](https://github.com/inclement))
- Separate build per android.arch [\#957](https://github.com/kivy/buildozer/pull/957) ([tito](https://github.com/tito))
- spec file: cast paths in source.exclude\_dirs to lowercase [\#956](https://github.com/kivy/buildozer/pull/956) ([SomberNight](https://github.com/SomberNight))
- added cmake to requirements [\#950](https://github.com/kivy/buildozer/pull/950) ([mcroni](https://github.com/mcroni))
- Add ability to get p4a's recommended android's NDK version [\#947](https://github.com/kivy/buildozer/pull/947) ([opacam](https://github.com/opacam))
- New feature: allow to use a p4a fork [\#940](https://github.com/kivy/buildozer/pull/940) ([opacam](https://github.com/opacam))
- Minor linter fix [\#937](https://github.com/kivy/buildozer/pull/937) ([AndreMiras](https://github.com/AndreMiras))
- Update installation.rst [\#936](https://github.com/kivy/buildozer/pull/936) ([yairlempert](https://github.com/yairlempert))
- clarify overriding of config tokens [\#935](https://github.com/kivy/buildozer/pull/935) ([brentpicasso](https://github.com/brentpicasso))
- Extend add\_libs to arm64-v8a [\#934](https://github.com/kivy/buildozer/pull/934) ([misl6](https://github.com/misl6))
- Doc/installation updates [\#932](https://github.com/kivy/buildozer/pull/932) ([tshirtman](https://github.com/tshirtman))
- customizability options [\#919](https://github.com/kivy/buildozer/pull/919) ([zworkb](https://github.com/zworkb))
- disable orientation and window option for service\_only bootstrap [\#912](https://github.com/kivy/buildozer/pull/912) ([zworkb](https://github.com/zworkb))
- Unit test unicode decode on command output, fixes \#857 [\#905](https://github.com/kivy/buildozer/pull/905) ([AndreMiras](https://github.com/AndreMiras))
- Made sure to print all lines of license question by always flushing [\#904](https://github.com/kivy/buildozer/pull/904) ([inclement](https://github.com/inclement))
- Exits with error code on build exception, fixes \#674 [\#882](https://github.com/kivy/buildozer/pull/882) ([AndreMiras](https://github.com/AndreMiras))
- Download Apache ANT at the same path as the buildozer.spec android.ant\_path option [\#860](https://github.com/kivy/buildozer/pull/860) ([robertpro](https://github.com/robertpro))
- Fix for bug when logcat value which cannot be decode to utf-8 [\#856](https://github.com/kivy/buildozer/pull/856) ([Draqun](https://github.com/Draqun))
- Changes default log level to debug \(2\) [\#855](https://github.com/kivy/buildozer/pull/855) ([AndreMiras](https://github.com/AndreMiras))
- Handles unknown command/target error gracefully, closes \#812 [\#853](https://github.com/kivy/buildozer/pull/853) ([AndreMiras](https://github.com/AndreMiras))
- Updates system requirements needed to build recipes [\#852](https://github.com/kivy/buildozer/pull/852) ([AndreMiras](https://github.com/AndreMiras))
- Various Dockerfile improvements [\#848](https://github.com/kivy/buildozer/pull/848) ([AndreMiras](https://github.com/AndreMiras))
- Support p4a uses-library argument [\#846](https://github.com/kivy/buildozer/pull/846) ([pax0r](https://github.com/pax0r))
- Removed reference to Kivy VM [\#845](https://github.com/kivy/buildozer/pull/845) ([Megalex42](https://github.com/Megalex42))
- Removes extra log\_env\(\) call [\#843](https://github.com/kivy/buildozer/pull/843) ([AndreMiras](https://github.com/AndreMiras))
- add missing android arch to spec file [\#839](https://github.com/kivy/buildozer/pull/839) ([OptimusGREEN](https://github.com/OptimusGREEN))
- feat: make unzip quiet [\#836](https://github.com/kivy/buildozer/pull/836) ([mkg20001](https://github.com/mkg20001))
- fix: drop release-unsigned from release output path [\#835](https://github.com/kivy/buildozer/pull/835) ([mkg20001](https://github.com/mkg20001))
- Add ci\_mode to toggle download progress [\#833](https://github.com/kivy/buildozer/pull/833) ([mkg20001](https://github.com/mkg20001))
- Unit test logger [\#831](https://github.com/kivy/buildozer/pull/831) ([AndreMiras](https://github.com/AndreMiras))
- refactor auto accept license [\#822](https://github.com/kivy/buildozer/pull/822) ([AndreMiras](https://github.com/AndreMiras))
- Unit tests buildozer --help command, refs \#813 [\#821](https://github.com/kivy/buildozer/pull/821) ([AndreMiras](https://github.com/AndreMiras))
- Use getbooldefault\(\) for boolean, fixes \#806 [\#817](https://github.com/kivy/buildozer/pull/817) ([AndreMiras](https://github.com/AndreMiras))
- Update the issue template [\#814](https://github.com/kivy/buildozer/pull/814) ([AndreMiras](https://github.com/AndreMiras))
- Show envs when run2 [\#802](https://github.com/kivy/buildozer/pull/802) ([maho](https://github.com/maho))
## [0.39](https://github.com/kivy/buildozer/tree/0.39) (2019-02-04)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.38...0.39)
## [0.38](https://github.com/kivy/buildozer/tree/0.38) (2019-02-03)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.36...0.38)
**Fixed bugs:**
- TypeError: read\(\) takes exactly 2 arguments \(3 given\) [\#793](https://github.com/kivy/buildozer/issues/793)
- TypeError: read\(\) takes exactly 2 arguments \(3 given\) [\#792](https://github.com/kivy/buildozer/issues/792)
- AttributeError: 'str' object has no attribute 'decode' [\#756](https://github.com/kivy/buildozer/issues/756)
**Closed issues:**
- Openssl compilation fails, '\_\_atomic' undefined [\#800](https://github.com/kivy/buildozer/issues/800)
- --ndk-api appears twice [\#798](https://github.com/kivy/buildozer/issues/798)
- Error in toolchain.py and argument --ndk-api 9 [\#797](https://github.com/kivy/buildozer/issues/797)
- Target ndk-api is 19, but the \*\*python3 recipe supports only 21\*\* [\#796](https://github.com/kivy/buildozer/issues/796)
- Add support for --frameworks on iOS [\#790](https://github.com/kivy/buildozer/issues/790)
- Hello World impossible: checking whether the C compiler works... no [\#785](https://github.com/kivy/buildozer/issues/785)
- Buildozer 0.37 UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 [\#782](https://github.com/kivy/buildozer/issues/782)
- APK Crashes on start with no obvious cause [\#779](https://github.com/kivy/buildozer/issues/779)
- Outdated Android NDK download URL in Kivy Virtual Machine [\#778](https://github.com/kivy/buildozer/issues/778)
- Buildozer "gradlew failed!" [\#777](https://github.com/kivy/buildozer/issues/777)
- Conflicting documentation Python2 versus Python3 [\#774](https://github.com/kivy/buildozer/issues/774)
- No valid --ndk-api received, using the default of 0 = min\(android-api=0, default ndk-api=21\) [\#772](https://github.com/kivy/buildozer/issues/772)
- `default.spec` specifies `python3` but also incompatible NDK and API settings [\#770](https://github.com/kivy/buildozer/issues/770)
- Error: minsdk argument does not match the api that is compiled against [\#768](https://github.com/kivy/buildozer/issues/768)
- Need to support sensorLandscape [\#762](https://github.com/kivy/buildozer/issues/762)
- minsdk argument does not match the api that is compiled against [\#761](https://github.com/kivy/buildozer/issues/761)
- Need to be able to specify the NDK API target [\#758](https://github.com/kivy/buildozer/issues/758)
- Buildozer cannot import name pythran\_is\_numpy\_func\_supported [\#753](https://github.com/kivy/buildozer/issues/753)
- Python3 recipe not building, error with self.ctx.python\_recipe [\#752](https://github.com/kivy/buildozer/issues/752)
- compile error [\#744](https://github.com/kivy/buildozer/issues/744)
- APK build failed "ndk\_platform doesn't exist" \(Python3.6; android.api = 27\) [\#742](https://github.com/kivy/buildozer/issues/742)
- Logo Design Proposal [\#734](https://github.com/kivy/buildozer/issues/734)
- `android clean` not working \(FileNotFoundError: \[Errno 2\] No such file or directory\) [\#732](https://github.com/kivy/buildozer/issues/732)
- Can't Make an APK via Buildozer [\#712](https://github.com/kivy/buildozer/issues/712)
- App build Failed [\#707](https://github.com/kivy/buildozer/issues/707)
- ERROR: /home/kivy/.buildozer/android/platform/apache-ant-1.9.4/bin/ant failed! [\#706](https://github.com/kivy/buildozer/issues/706)
- APK using txt file in main.py issue. [\#704](https://github.com/kivy/buildozer/issues/704)
- "Copying APK" fails because of wrong path used [\#699](https://github.com/kivy/buildozer/issues/699)
- Cannot build [\#697](https://github.com/kivy/buildozer/issues/697)
- Fail on build [\#692](https://github.com/kivy/buildozer/issues/692)
- Cannot build "Hello World" APK [\#687](https://github.com/kivy/buildozer/issues/687)
- Error when building an android APK using Kivy [\#684](https://github.com/kivy/buildozer/issues/684)
- can't get audio stream from a server [\#683](https://github.com/kivy/buildozer/issues/683)
- Continuous integration testing [\#679](https://github.com/kivy/buildozer/issues/679)
- Post build fails because copying built apk fails [\#671](https://github.com/kivy/buildozer/issues/671)
- Buildozer can't compile for Android on Manjaro Linux [\#670](https://github.com/kivy/buildozer/issues/670)
- Icon/Logo Proposal [\#669](https://github.com/kivy/buildozer/issues/669)
- Buildozer cant compile platform Ubuntu 16.04 [\#668](https://github.com/kivy/buildozer/issues/668)
- Buildozer gets stuck at unpacking kivy [\#667](https://github.com/kivy/buildozer/issues/667)
- Kivy window [\#666](https://github.com/kivy/buildozer/issues/666)
- Failed building wheel for pyaudio [\#665](https://github.com/kivy/buildozer/issues/665)
- Buildozer compilation gets stuck [\#663](https://github.com/kivy/buildozer/issues/663)
- IOError: \[Errno 2\] No such file or directory: u'/home/samurai-girl/python2/.buildozer/android/platform/build/dists/test/build/outputs/apk/test-debug.apk' [\#662](https://github.com/kivy/buildozer/issues/662)
- Unable to build \_ctypes.so [\#660](https://github.com/kivy/buildozer/issues/660)
- error while packaging for android on macOS [\#659](https://github.com/kivy/buildozer/issues/659)
- Command failed: /usr/bin/python2 -m pythonforandroid.toolchain [\#658](https://github.com/kivy/buildozer/issues/658)
- Cannot build apk with buildozer android debug [\#656](https://github.com/kivy/buildozer/issues/656)
- How to correctly build an APK package with Python 3? [\#655](https://github.com/kivy/buildozer/issues/655)
- SDK does not have any Build Tools installed. [\#652](https://github.com/kivy/buildozer/issues/652)
- Error building Kivy app with opencv\(and numpy\) - raise CommandNotFoundError\(path\) [\#651](https://github.com/kivy/buildozer/issues/651)
- FileNotFoundError: \[Errno 2\] [\#649](https://github.com/kivy/buildozer/issues/649)
- The python3crystax recipe can only be built when using the CrystaX NDK. Exiting. [\#648](https://github.com/kivy/buildozer/issues/648)
- build apk : error can not find the build/output folder [\#647](https://github.com/kivy/buildozer/issues/647)
- help me building cryptography [\#646](https://github.com/kivy/buildozer/issues/646)
- sslv3 alert handshake failure on Addroid [\#643](https://github.com/kivy/buildozer/issues/643)
- Opening Android SDK Manager to download "Google Repository" and "Google Play services" [\#642](https://github.com/kivy/buildozer/issues/642)
- kivy python host failed [\#641](https://github.com/kivy/buildozer/issues/641)
- python.host failed [\#640](https://github.com/kivy/buildozer/issues/640)
- Kivy Crashing [\#638](https://github.com/kivy/buildozer/issues/638)
- .so lib files missing debug symbols [\#637](https://github.com/kivy/buildozer/issues/637)
- Kivy app doesn't run [\#634](https://github.com/kivy/buildozer/issues/634)
- "\* daemon not running. starting it now on port 5037 \* \* daemon started successfully \*" [\#633](https://github.com/kivy/buildozer/issues/633)
- FileNotFoundError: \[Errno 2\] No such file or directory: '/home/alex/Documents/pengame/.buildozer/android/platform/build/dists/helloworldapp/build/outputs/apk/helloworldapp-debug.apk' [\#632](https://github.com/kivy/buildozer/issues/632)
- Compiling Kivy app to apk fails with a pip error [\#631](https://github.com/kivy/buildozer/issues/631)
- ERROR: /home/ubuntu/.buildozer/android/platform/apache-ant-1.9.4/bin/ant failed! [\#625](https://github.com/kivy/buildozer/issues/625)
- Build error when building Kivy app [\#624](https://github.com/kivy/buildozer/issues/624)
- buildozer debug is not running this error is showing [\#622](https://github.com/kivy/buildozer/issues/622)
- unexpected e\_machine: 3 [\#621](https://github.com/kivy/buildozer/issues/621)
- buildozer matplotlib [\#617](https://github.com/kivy/buildozer/issues/617)
- IOError: \[Errno 2\] No such file or directory: u'/Users/gauravgupta/kivy/.buildozer/android/platform/build/dists/myellipse/build/outputs/apk/myellipse-debug.apk' [\#613](https://github.com/kivy/buildozer/issues/613)
- Build failing in final ANT stage [\#610](https://github.com/kivy/buildozer/issues/610)
- Cannot build apk [\#606](https://github.com/kivy/buildozer/issues/606)
- Installing buildozer for Python 3 failed [\#604](https://github.com/kivy/buildozer/issues/604)
- FileNotFoundError at end of build when copying APK file. [\#602](https://github.com/kivy/buildozer/issues/602)
- BUILD FAILED [\#601](https://github.com/kivy/buildozer/issues/601)
- Error with buildozer [\#591](https://github.com/kivy/buildozer/issues/591)
- ImportError: No module named Cython.Distutils While running buildozer android debug [\#587](https://github.com/kivy/buildozer/issues/587)
- python 2.7 compile with NDK 15c [\#584](https://github.com/kivy/buildozer/issues/584)
- Problem upgrade to newest version [\#583](https://github.com/kivy/buildozer/issues/583)
- Simple Kivy test app can't compile to android apk [\#581](https://github.com/kivy/buildozer/issues/581)
- Apple Watch Support [\#574](https://github.com/kivy/buildozer/issues/574)
- Skip error or better error message: requirements with extra comma [\#562](https://github.com/kivy/buildozer/issues/562)
- failed to build numpy on Mac [\#557](https://github.com/kivy/buildozer/issues/557)
- p4a.source\_dir set and android clean --\> crash [\#556](https://github.com/kivy/buildozer/issues/556)
- Kivy python android build error? [\#555](https://github.com/kivy/buildozer/issues/555)
- python3 import networkx needs lib2to3 but cannot be imported [\#554](https://github.com/kivy/buildozer/issues/554)
- buildozer android debug deploy run ERROR [\#550](https://github.com/kivy/buildozer/issues/550)
- App Crashes [\#541](https://github.com/kivy/buildozer/issues/541)
- Requirements: Requests, Ssl [\#539](https://github.com/kivy/buildozer/issues/539)
- Error: Aidl cannot be executed [\#532](https://github.com/kivy/buildozer/issues/532)
- Kivy and Beautifulsoup with Buildozer fail on Python 3. [\#529](https://github.com/kivy/buildozer/issues/529)
- I'm having similar problem [\#528](https://github.com/kivy/buildozer/issues/528)
- Awkward error while building apk [\#526](https://github.com/kivy/buildozer/issues/526)
- The "android" command is deprecated [\#519](https://github.com/kivy/buildozer/issues/519)
- Kivy: Permission denied \(when running buildozer android on Mac OS X\) [\#517](https://github.com/kivy/buildozer/issues/517)
- Extraction of "Kivy2.7z" failed [\#516](https://github.com/kivy/buildozer/issues/516)
- buildozer still download ndk from wrong path [\#506](https://github.com/kivy/buildozer/issues/506)
- android-new landscape error on restart [\#482](https://github.com/kivy/buildozer/issues/482)
- Add possibility to choose pip version for modules in the requirements section [\#475](https://github.com/kivy/buildozer/issues/475)
- Bulldozer android\_new fails when ffmpeg is added to the requirements: No C Compiler found! [\#463](https://github.com/kivy/buildozer/issues/463)
- CalledProcessError: Command '\['python', 'package\_app.py', '--displayname=Music Favorites'\]' returned non-zero exit status 1 [\#448](https://github.com/kivy/buildozer/issues/448)
- \[Errno 13\] Permission denied; Buildozer on Flask Server [\#445](https://github.com/kivy/buildozer/issues/445)
- Error while compiling a kivy app for android \(undefined reference to 'SDL\_main' collect2: error: ld returned 1 exit status\) [\#438](https://github.com/kivy/buildozer/issues/438)
- AsyncImage not loading in .apk [\#433](https://github.com/kivy/buildozer/issues/433)
- Big Bug, ORMs cant find sqlite3.so [\#426](https://github.com/kivy/buildozer/issues/426)
- cp: cannot stat '~/.buildozer/android/platform/python-for-android/src/libs/armeabi/\*.so': No such file or directory [\#422](https://github.com/kivy/buildozer/issues/422)
- using android\_new causes missing packages errors [\#420](https://github.com/kivy/buildozer/issues/420)
- Buildozer fails with "Command '\['ant', 'debug'\]' returned non-zero exit status 1" [\#419](https://github.com/kivy/buildozer/issues/419)
- Buildozer fails to build when ffmpeg is added [\#418](https://github.com/kivy/buildozer/issues/418)
- Build on arm64 android [\#412](https://github.com/kivy/buildozer/issues/412)
- Building with "android\_new" target fails due to missing architecture on pythonforandroid.toolchain apk [\#407](https://github.com/kivy/buildozer/issues/407)
- Command '\['ant', 'debug'\]' returned non-zero exit status 1 when building PIL library [\#406](https://github.com/kivy/buildozer/issues/406)
- Android, Pygame backend: buildozer android debug deploy run tries to launch wrong Activity [\#401](https://github.com/kivy/buildozer/issues/401)
- AttributeError: 'NoneType' object has no attribute 'splitlines' [\#400](https://github.com/kivy/buildozer/issues/400)
- Pyzmq import fails on Android with python2 / kivy 1.9 / cython 0.23 [\#397](https://github.com/kivy/buildozer/issues/397)
- Python 3: \# Aidl cannot be executed AttributeError: 'module' object has no attribute 'maxint' [\#392](https://github.com/kivy/buildozer/issues/392)
- subprocess.CalledProcessError [\#391](https://github.com/kivy/buildozer/issues/391)
- python.host could not find platform independent libraries [\#390](https://github.com/kivy/buildozer/issues/390)
- Buildozer android\_new fails [\#388](https://github.com/kivy/buildozer/issues/388)
- toolchain.py: error: argument --private is required [\#384](https://github.com/kivy/buildozer/issues/384)
- Android fails on running Kivy apk [\#381](https://github.com/kivy/buildozer/issues/381)
- ImportError: No module named plyer with android\_new as a target [\#379](https://github.com/kivy/buildozer/issues/379)
- buildozer -v android debug runs into problem [\#376](https://github.com/kivy/buildozer/issues/376)
- subprocess.CalledProcessError [\#372](https://github.com/kivy/buildozer/issues/372)
- Can't install Pillow , return errors [\#371](https://github.com/kivy/buildozer/issues/371)
- failed to load ctypes as android app built on OSX [\#368](https://github.com/kivy/buildozer/issues/368)
- old\_toolchain not shows images [\#367](https://github.com/kivy/buildozer/issues/367)
- Buildozer deployment dlopen failed libSDL2.so has unexpected e\_machine: 40 [\#365](https://github.com/kivy/buildozer/issues/365)
- Rebuild only selected packages [\#226](https://github.com/kivy/buildozer/issues/226)
**Merged pull requests:**
- Updated README for Python 3 [\#809](https://github.com/kivy/buildozer/pull/809) ([inclement](https://github.com/inclement))
- Update README.md to add opencollective [\#808](https://github.com/kivy/buildozer/pull/808) ([tito](https://github.com/tito))
- Made buildozer respect user sdk dir when accessing sdkmanager [\#807](https://github.com/kivy/buildozer/pull/807) ([inclement](https://github.com/inclement))
- Removed android\_old and updated SDK management to work with current SDK [\#806](https://github.com/kivy/buildozer/pull/806) ([inclement](https://github.com/inclement))
- Removed redundant --ndk-api argument and fixed default value [\#805](https://github.com/kivy/buildozer/pull/805) ([inclement](https://github.com/inclement))
- Update for p4a master [\#803](https://github.com/kivy/buildozer/pull/803) ([inclement](https://github.com/inclement))
- Unit tests read spec file, refs \#793 [\#799](https://github.com/kivy/buildozer/pull/799) ([AndreMiras](https://github.com/AndreMiras))
- Support the --add-frameworks flag in kivy-ios [\#795](https://github.com/kivy/buildozer/pull/795) ([hackalog](https://github.com/hackalog))
- Introduces CI and tox testing, fixes \#679 [\#794](https://github.com/kivy/buildozer/pull/794) ([AndreMiras](https://github.com/AndreMiras))
- Fix python 2 crash when reading config file [\#791](https://github.com/kivy/buildozer/pull/791) ([etc0de](https://github.com/etc0de))
- Handle buildozer.spec with unicode chars [\#789](https://github.com/kivy/buildozer/pull/789) ([guysoft](https://github.com/guysoft))
- Specify GitHub branches in buildozer.spec [\#787](https://github.com/kivy/buildozer/pull/787) ([hackalog](https://github.com/hackalog))
- Fixes minor comment typo introduced in \#759 [\#786](https://github.com/kivy/buildozer/pull/786) ([AndreMiras](https://github.com/AndreMiras))
- Docker from current git [\#775](https://github.com/kivy/buildozer/pull/775) ([maho](https://github.com/maho))
- Fix output directory for gradle [\#766](https://github.com/kivy/buildozer/pull/766) ([wo01](https://github.com/wo01))
- support sensorLandscape mode. resolves \#762 [\#763](https://github.com/kivy/buildozer/pull/763) ([brentpicasso](https://github.com/brentpicasso))
- allow specifying of Android NDK API. Resolves \#758 [\#759](https://github.com/kivy/buildozer/pull/759) ([brentpicasso](https://github.com/brentpicasso))
- Update cython version from the docs [\#757](https://github.com/kivy/buildozer/pull/757) ([AndreMiras](https://github.com/AndreMiras))
- fix android sdk/ndk information link [\#755](https://github.com/kivy/buildozer/pull/755) ([avere001](https://github.com/avere001))
- this allows to build with ndk 17c \(and other recent-ish ones\) [\#754](https://github.com/kivy/buildozer/pull/754) ([tshirtman](https://github.com/tshirtman))
- fix ndk URLs [\#747](https://github.com/kivy/buildozer/pull/747) ([zworkb](https://github.com/zworkb))
## [0.36](https://github.com/kivy/buildozer/tree/0.36) (2018-11-21)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.35...0.36)
**Fixed bugs:**
- Error in debug, install platform, Indexerror. [\#731](https://github.com/kivy/buildozer/issues/731)
**Closed issues:**
- Buildozer looking for nonexistent script [\#749](https://github.com/kivy/buildozer/issues/749)
- Can not build APK file with buildozer. UnicodeDecodeError [\#746](https://github.com/kivy/buildozer/issues/746)
- CrystaX no longer the preferred NDK for Python3 [\#745](https://github.com/kivy/buildozer/issues/745)
- AKP build fails \(android.py line 524\) [\#738](https://github.com/kivy/buildozer/issues/738)
- Buildozer 0.35 with IndexError: list index out of range on Mac OS [\#737](https://github.com/kivy/buildozer/issues/737)
- cannot build pyjnius for armeabi-v7a [\#735](https://github.com/kivy/buildozer/issues/735)
- I can't package my app the way i always did. [\#733](https://github.com/kivy/buildozer/issues/733)
- OSError: \[Errno 18\] Invalid cross-device link [\#644](https://github.com/kivy/buildozer/issues/644)
**Merged pull requests:**
- Correctly write out a sub-process's `stdout` when using Python 3. [\#743](https://github.com/kivy/buildozer/pull/743) ([dbrnz](https://github.com/dbrnz))
- Explicitly run `pip3` when using Python 3 [\#741](https://github.com/kivy/buildozer/pull/741) ([dbrnz](https://github.com/dbrnz))
- workaround for working in WSL [\#740](https://github.com/kivy/buildozer/pull/740) ([tshirtman](https://github.com/tshirtman))
- Allow for `install\_reqs` line having whitespace at start. [\#736](https://github.com/kivy/buildozer/pull/736) ([dbrnz](https://github.com/dbrnz))
- Fix Support config file name [\#730](https://github.com/kivy/buildozer/pull/730) ([dessant](https://github.com/dessant))
## [0.35](https://github.com/kivy/buildozer/tree/0.35) (2018-10-24)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.34...0.35)
**Fixed bugs:**
- Buildozer should not regex/hack install\_reqs [\#722](https://github.com/kivy/buildozer/issues/722)
**Closed issues:**
- Command failed: /usr/bin/python -m pythonforandroid.toolchain create... [\#727](https://github.com/kivy/buildozer/issues/727)
- buildozer fails at installing platfrom [\#726](https://github.com/kivy/buildozer/issues/726)
- Unable to build APK [\#725](https://github.com/kivy/buildozer/issues/725)
- Buildozer APK not working: OS X, Docker, or fresh Ubuntu 16.04 [\#723](https://github.com/kivy/buildozer/issues/723)
- gcc Segmentation Fault [\#720](https://github.com/kivy/buildozer/issues/720)
- Error debugging for android [\#719](https://github.com/kivy/buildozer/issues/719)
- ndk\_platform doesn't exist \(when switching to API = 28\) [\#717](https://github.com/kivy/buildozer/issues/717)
- FileNotFoundError: \[Errno 2\] \(SOLVED\) - It was Encoding Error [\#715](https://github.com/kivy/buildozer/issues/715)
- SDL\_JAVA\_PACKAGE\_PATH error? [\#714](https://github.com/kivy/buildozer/issues/714)
- Python3Crystax instructions in README [\#710](https://github.com/kivy/buildozer/issues/710)
- Bug or support request? [\#708](https://github.com/kivy/buildozer/issues/708)
- build requirement failed [\#701](https://github.com/kivy/buildozer/issues/701)
- I am using Virtual Machine provided in the official kivy website for building android APK, this is the part of log file [\#696](https://github.com/kivy/buildozer/issues/696)
- App minimizes instantly after launching. [\#695](https://github.com/kivy/buildozer/issues/695)
- Aidl not detected [\#694](https://github.com/kivy/buildozer/issues/694)
- python 3 ssl [\#690](https://github.com/kivy/buildozer/issues/690)
- Is there something like multiprocessing? [\#685](https://github.com/kivy/buildozer/issues/685)
- Kivy in pyCharm [\#682](https://github.com/kivy/buildozer/issues/682)
- Toolchain error. Help,please! [\#678](https://github.com/kivy/buildozer/issues/678)
- virtual machine does not compile apk Fails with errors [\#677](https://github.com/kivy/buildozer/issues/677)
- An error in Buildozer Apk \(Python Kivy\) Help PLZ! [\#676](https://github.com/kivy/buildozer/issues/676)
- App crashes on android but works fine in idle window using buildozer [\#675](https://github.com/kivy/buildozer/issues/675)
- Pyjnius exception Adbuddiz class not found [\#661](https://github.com/kivy/buildozer/issues/661)
- Buildozer failed to execute the last command \#/usr/bin/python3 -m pythonforandroid.toolchain create --dist\_name=blueb --bootstrap=sdl2 --requirements=python3crystax,kivy --arch x86 --copy-libs --color=always --storage-dir=/home/jp/Desktop/BlueB/.buildozer/android/platform/build [\#654](https://github.com/kivy/buildozer/issues/654)
- java.lang.ClassNotFoundException: sun.misc.BASE64Encoder [\#639](https://github.com/kivy/buildozer/issues/639)
- IOError: \[Errno 2\] No such file or directory: [\#636](https://github.com/kivy/buildozer/issues/636)
- App crashes with aws boto3 [\#635](https://github.com/kivy/buildozer/issues/635)
- APK Immediately Closes After Opening in Debug, Release, and Zipaligned & Signed Versions [\#629](https://github.com/kivy/buildozer/issues/629)
- Using Python/Buildozer to compile Kivy for Android [\#628](https://github.com/kivy/buildozer/issues/628)
- "configure: error: C compiler cannot create executables See `config.log' for more details" \(\# Command failed: ./distribute.sh -m "kivy" -d "pollygot"\) [\#627](https://github.com/kivy/buildozer/issues/627)
- "OSError: \[Errno 30\] Read-only file system" \(\# Command failed: virtualenv --python=python2.7 ./venv\) [\#626](https://github.com/kivy/buildozer/issues/626)
- Java compiling issue: buildozer uses obsolete source value 1.5 [\#619](https://github.com/kivy/buildozer/issues/619)
- Cloning into 'python-for-android-new-toolchain'... [\#618](https://github.com/kivy/buildozer/issues/618)
- Failed to build application: 'WindowInfoX11' is not a type identifier [\#616](https://github.com/kivy/buildozer/issues/616)
- Sudo issue\[closed\] [\#615](https://github.com/kivy/buildozer/issues/615)
- buildozer-vm-2 installed from scratch ABENDS [\#611](https://github.com/kivy/buildozer/issues/611)
- ASCII decode problem [\#608](https://github.com/kivy/buildozer/issues/608)
- error: could not delete 'build/lib.linux-x86\_64-2.7/buildozer/targets/android.py': Permission denied [\#607](https://github.com/kivy/buildozer/issues/607)
- APK Build Failing with Python 3.6 [\#605](https://github.com/kivy/buildozer/issues/605)
- IOError: \[Errno 2\] No such file or directory: u'/home/kivy/buildozer/.buildozer/android/platform/build/... [\#603](https://github.com/kivy/buildozer/issues/603)
- Feature Request: Dockerfile or image in dockerhub [\#589](https://github.com/kivy/buildozer/issues/589)
- Buildozer debug error. [\#545](https://github.com/kivy/buildozer/issues/545)
**Merged pull requests:**
- Fix \#645 [\#729](https://github.com/kivy/buildozer/pull/729) ([tito](https://github.com/tito))
- Enable Support app [\#728](https://github.com/kivy/buildozer/pull/728) ([dessant](https://github.com/dessant))
- Updates p4a deps parsing [\#724](https://github.com/kivy/buildozer/pull/724) ([AndreMiras](https://github.com/AndreMiras))
- Improved error handling if p4a setup.py can't be read [\#721](https://github.com/kivy/buildozer/pull/721) ([inclement](https://github.com/inclement))
- Various spelling corrections [\#718](https://github.com/kivy/buildozer/pull/718) ([Zen-CODE](https://github.com/Zen-CODE))
- Updates Python 3 install instructions, fixes \#710 [\#711](https://github.com/kivy/buildozer/pull/711) ([AndreMiras](https://github.com/AndreMiras))
- Remove obsolete sh package dependency [\#705](https://github.com/kivy/buildozer/pull/705) ([Cheaterman](https://github.com/Cheaterman))
- Changes how is\_gradle\_build is detected. [\#700](https://github.com/kivy/buildozer/pull/700) ([rammie](https://github.com/rammie))
- Cleans installation docs [\#689](https://github.com/kivy/buildozer/pull/689) ([AndreMiras](https://github.com/AndreMiras))
- Adds issue template with basic required info [\#688](https://github.com/kivy/buildozer/pull/688) ([AndreMiras](https://github.com/AndreMiras))
- buildozer Dockerfile, fixes \#589 [\#681](https://github.com/kivy/buildozer/pull/681) ([AndreMiras](https://github.com/AndreMiras))
- Removes few unused variables [\#680](https://github.com/kivy/buildozer/pull/680) ([AndreMiras](https://github.com/AndreMiras))
- Fixed a typo pointed out by AndreMiras [\#664](https://github.com/kivy/buildozer/pull/664) ([inclement](https://github.com/inclement))
- Updates installation.rst with Ubuntu 18.04 instructions [\#657](https://github.com/kivy/buildozer/pull/657) ([AndreMiras](https://github.com/AndreMiras))
- fix prerelease version [\#653](https://github.com/kivy/buildozer/pull/653) ([marceloneil](https://github.com/marceloneil))
- allow setting launchMode for the main activity in the manifest [\#650](https://github.com/kivy/buildozer/pull/650) ([SomberNight](https://github.com/SomberNight))
- Fixes Invalid cross-device link [\#645](https://github.com/kivy/buildozer/pull/645) ([robertpro](https://github.com/robertpro))
- Quote --storage-dir value [\#630](https://github.com/kivy/buildozer/pull/630) ([ghost](https://github.com/ghost))
- Allow adding Java activities to the manifest [\#612](https://github.com/kivy/buildozer/pull/612) ([bauerj](https://github.com/bauerj))
- add comment re p4a.port in default.spec [\#600](https://github.com/kivy/buildozer/pull/600) ([replabrobin](https://github.com/replabrobin))
- Spelling [\#592](https://github.com/kivy/buildozer/pull/592) ([jsoref](https://github.com/jsoref))
## [0.34](https://github.com/kivy/buildozer/tree/0.34) (2017-12-15)
[Full Changelog](https://github.com/kivy/buildozer/compare/0.33...0.34)
**Closed issues:**
- IOERROR invalid directory [\#599](https://github.com/kivy/buildozer/issues/599)
- Buidozer 0.33 AttributeError: 'module' object has no attribute 'directory' [\#598](https://github.com/kivy/buildozer/issues/598)
- Issu with buildozer packing [\#596](https://github.com/kivy/buildozer/issues/596)
- Gradle: path may not be null or empty string. path='null' [\#595](https://github.com/kivy/buildozer/issues/595)
- ERROR: Trying to release a package that starts with org.test; what can I do? [\#593](https://github.com/kivy/buildozer/issues/593)
- App crash with python3 [\#590](https://github.com/kivy/buildozer/issues/590)
- Problem running buildozer android debug first time [\#586](https://github.com/kivy/buildozer/issues/586)
- buildozer download some content failed [\#585](https://github.com/kivy/buildozer/issues/585)
- complie platform failed [\#580](https://github.com/kivy/buildozer/issues/580)
- Module OS - buildozer.spec [\#579](https://github.com/kivy/buildozer/issues/579)
- Buildozer doesn't compile app with cryptography requirement [\#578](https://github.com/kivy/buildozer/issues/578)
- Buildozer x psycopg2 [\#575](https://github.com/kivy/buildozer/issues/575)
- Problem with Android API 23 [\#573](https://github.com/kivy/buildozer/issues/573)
- App crashing on startup- ImportError: dlopen failed: \_imaging.so is 64-bit [\#568](https://github.com/kivy/buildozer/issues/568)
- Buildozer issue with latest Xcode/macOS [\#566](https://github.com/kivy/buildozer/issues/566)
- Requests SSL error [\#565](https://github.com/kivy/buildozer/issues/565)
- buildozer failed for `Broken toolchain` when building numpy with python.host [\#564](https://github.com/kivy/buildozer/issues/564)
- Encountered a bad program behavior [\#563](https://github.com/kivy/buildozer/issues/563)
- error at using pycypto in the requirements [\#558](https://github.com/kivy/buildozer/issues/558)
- Websocket error: SSL not available. [\#552](https://github.com/kivy/buildozer/issues/552)
- "crystax\_python does not exist" with python3crystax [\#551](https://github.com/kivy/buildozer/issues/551)
- App crashes after build [\#549](https://github.com/kivy/buildozer/issues/549)
- Installing CyLP on windows [\#548](https://github.com/kivy/buildozer/issues/548)
- Service notification launch intent causes app crash [\#547](https://github.com/kivy/buildozer/issues/547)
- Application crashes on start [\#546](https://github.com/kivy/buildozer/issues/546)
- New android target is unable to produce a python 4 android service [\#543](https://github.com/kivy/buildozer/issues/543)
- Buildozer Build Error [\#538](https://github.com/kivy/buildozer/issues/538)
- \# Aidl not found, please install it. [\#537](https://github.com/kivy/buildozer/issues/537)
- Error compiling Cython file on Ubuntu 14.0.4 with python 2.7 and 3.4/5 [\#536](https://github.com/kivy/buildozer/issues/536)
- Failed compilation on ubuntu with python 2.7 configure: error: C compiler cannot create executables [\#535](https://github.com/kivy/buildozer/issues/535)
- Remove app permissions added by default [\#534](https://github.com/kivy/buildozer/issues/534)
- Buildozer error while packaging [\#531](https://github.com/kivy/buildozer/issues/531)
- Buildozer failing to pack .apk [\#530](https://github.com/kivy/buildozer/issues/530)
- toolchain fails to recognize option --sdk [\#524](https://github.com/kivy/buildozer/issues/524)
- \# Command failed: /usr/bin/python -m pythonforandroid.toolchain create --dist\_name=myapp --bootstrap=sdl2 --requirements=kivy --arch armeabi-v7a --copy-libs --color=always --storage-dir=/home/abhipso/thembapp/.buildozer/android/platform/build [\#521](https://github.com/kivy/buildozer/issues/521)
- apk way too large - 800mb [\#520](https://github.com/kivy/buildozer/issues/520)
- \[features\] Snapcraft implementation [\#514](https://github.com/kivy/buildozer/issues/514)
- Possibility of building in kivy virtual machine all locally [\#513](https://github.com/kivy/buildozer/issues/513)
- Python3\(crystax ndk\) builds broken [\#511](https://github.com/kivy/buildozer/issues/511)
- build fails in virtualenv [\#509](https://github.com/kivy/buildozer/issues/509)
- password for the virtual machine? [\#507](https://github.com/kivy/buildozer/issues/507)
- Failed to build APK with python 3.6 : \[sh.CommandNotFound: python3.5\] [\#504](https://github.com/kivy/buildozer/issues/504)
- Don't Unpacking opencv for armeabi-v7a [\#503](https://github.com/kivy/buildozer/issues/503)
- Fails to package app on OSX Sierra 10.12.4 \(hdiutil: attach failed - image not recognized keka\) [\#494](https://github.com/kivy/buildozer/issues/494)
- File missing building release APK [\#469](https://github.com/kivy/buildozer/issues/469)
- Building APK using Buildozer/Kivy [\#459](https://github.com/kivy/buildozer/issues/459)
- buildozer failed to build apk: subprocess.CalledProcessError: Command '\['ant', 'debug'\]' returned non-zero exit status 1 [\#373](https://github.com/kivy/buildozer/issues/373)
- AttributeError: 'Context' object has no attribute 'hostpython' in recipe [\#361](https://github.com/kivy/buildozer/issues/361)
- Cant compile apk with sqlite3 \(using python3 crystax\) [\#359](https://github.com/kivy/buildozer/issues/359)
**Merged pull requests:**
- Imported os to fix ImportError [\#594](https://github.com/kivy/buildozer/pull/594) ([inclement](https://github.com/inclement))
- add p4a.port config option; to allow specifiying webview port [\#588](https://github.com/kivy/buildozer/pull/588) ([replabrobin](https://github.com/replabrobin))
- Fix Py3 utf-8 encode error [\#582](https://github.com/kivy/buildozer/pull/582) ([Zen-CODE](https://github.com/Zen-CODE))
- Fixes `p4a.branch` comment [\#577](https://github.com/kivy/buildozer/pull/577) ([AndreMiras](https://github.com/AndreMiras))
- Fix old toolchain index error [\#576](https://github.com/kivy/buildozer/pull/576) ([Zen-CODE](https://github.com/Zen-CODE))
- Some fixes in old android target [\#572](https://github.com/kivy/buildozer/pull/572) ([rnixx](https://github.com/rnixx))
- Removed --sdk argument for p4a [\#571](https://github.com/kivy/buildozer/pull/571) ([inclement](https://github.com/inclement))
- Update specifications.rst [\#560](https://github.com/kivy/buildozer/pull/560) ([crajun](https://github.com/crajun))
- Changed p4a directory name for current toolchain [\#527](https://github.com/kivy/buildozer/pull/527) ([inclement](https://github.com/inclement))
- Update android.py, updated recreate the project.properties section [\#525](https://github.com/kivy/buildozer/pull/525) ([mokhoo](https://github.com/mokhoo))
- Fix unicode coding error in android build target [\#518](https://github.com/kivy/buildozer/pull/518) ([jamalex](https://github.com/jamalex))
- Add 404 status code handling on kivy download [\#508](https://github.com/kivy/buildozer/pull/508) ([SecretObsession](https://github.com/SecretObsession))
- Use dmg instead of 7z [\#505](https://github.com/kivy/buildozer/pull/505) ([shivan1b](https://github.com/shivan1b))
## [0.33](https://github.com/kivy/buildozer/tree/0.33) (2017-05-15) ## [0.33](https://github.com/kivy/buildozer/tree/0.33) (2017-05-15)
[Full Changelog](https://github.com/kivy/buildozer/compare/v0.32...0.33) [Full Changelog](https://github.com/kivy/buildozer/compare/v0.32...0.33)
@ -1066,10 +490,11 @@
**Merged pull requests:** **Merged pull requests:**
- Updated Android NDK default version to 9c [\#82](https://github.com/kivy/buildozer/pull/82) ([brousch](https://github.com/brousch)) - Updated Android NDK default version to 9c [\#82](https://github.com/kivy/buildozer/pull/82) ([brousch](https://github.com/brousch))
- Add 'bin' to suggested default directory excludes [\#78](https://github.com/kivy/buildozer/pull/78) ([joseph-jnl](https://github.com/joseph-jnl)) - Add 'bin' to suggested default directory excludes [\#78](https://github.com/kivy/buildozer/pull/78) ([josephlee021](https://github.com/josephlee021))
- Clarified wording in README [\#75](https://github.com/kivy/buildozer/pull/75) ([inclement](https://github.com/inclement)) - Clarified wording in README [\#75](https://github.com/kivy/buildozer/pull/75) ([inclement](https://github.com/inclement))
- Check for package name starting with number [\#65](https://github.com/kivy/buildozer/pull/65) ([inclement](https://github.com/inclement)) - Check for package name starting with number [\#65](https://github.com/kivy/buildozer/pull/65) ([inclement](https://github.com/inclement))
- \[FIX\] Detect 32/64 bit on Windows, to download Android NDK [\#62](https://github.com/kivy/buildozer/pull/62) ([alanjds](https://github.com/alanjds)) - \[FIX\] Detect 32/64 bit on Windows, to download Android NDK [\#62](https://github.com/kivy/buildozer/pull/62) ([alanjds](https://github.com/alanjds))
- Add ability to choose python-for-android directory [\#60](https://github.com/kivy/buildozer/pull/60) ([inclement](https://github.com/inclement))
- Added --private and --dir Android storage option [\#58](https://github.com/kivy/buildozer/pull/58) ([brousch](https://github.com/brousch)) - Added --private and --dir Android storage option [\#58](https://github.com/kivy/buildozer/pull/58) ([brousch](https://github.com/brousch))
- Added a 'serve' command to serve bin/ over SimpleHTTPServer [\#49](https://github.com/kivy/buildozer/pull/49) ([brousch](https://github.com/brousch)) - Added a 'serve' command to serve bin/ over SimpleHTTPServer [\#49](https://github.com/kivy/buildozer/pull/49) ([brousch](https://github.com/brousch))
@ -1086,7 +511,6 @@
**Merged pull requests:** **Merged pull requests:**
- Add ability to choose python-for-android directory [\#60](https://github.com/kivy/buildozer/pull/60) ([inclement](https://github.com/inclement))
- Update default Android NDK to r9 [\#53](https://github.com/kivy/buildozer/pull/53) ([brousch](https://github.com/brousch)) - Update default Android NDK to r9 [\#53](https://github.com/kivy/buildozer/pull/53) ([brousch](https://github.com/brousch))
- Added android.wakelock option [\#51](https://github.com/kivy/buildozer/pull/51) ([brousch](https://github.com/brousch)) - Added android.wakelock option [\#51](https://github.com/kivy/buildozer/pull/51) ([brousch](https://github.com/brousch))
- Fixed another 'Unknown' typo [\#48](https://github.com/kivy/buildozer/pull/48) ([brousch](https://github.com/brousch)) - Fixed another 'Unknown' typo [\#48](https://github.com/kivy/buildozer/pull/48) ([brousch](https://github.com/brousch))

View file

@ -1,81 +0,0 @@
# Dockerfile for providing buildozer
#
# Build with:
# docker build --tag=kivy/buildozer .
#
# In order to give the container access to your current working directory
# it must be mounted using the --volume option.
# Run with (e.g. `buildozer --version`):
# docker run \
# --volume "$HOME/.buildozer":/home/user/.buildozer \
# --volume "$PWD":/home/user/hostcwd \
# kivy/buildozer --version
#
# Or for interactive shell:
# docker run --interactive --tty --rm \
# --volume "$HOME/.buildozer":/home/user/.buildozer \
# --volume "$PWD":/home/user/hostcwd \
# --entrypoint /bin/bash \
# kivy/buildozer
#
# If you get a `PermissionError` on `/home/user/.buildozer/cache`,
# try updating the permissions from the host with:
# sudo chown $USER -R ~/.buildozer
# Or simply recreate the directory from the host with:
# rm -rf ~/.buildozer && mkdir ~/.buildozer
FROM ubuntu:20.04
ENV USER="user"
ENV HOME_DIR="/home/${USER}"
ENV WORK_DIR="${HOME_DIR}/hostcwd" \
SRC_DIR="${HOME_DIR}/src" \
PATH="${HOME_DIR}/.local/bin:${PATH}"
# configures locale
RUN apt update -qq > /dev/null \
&& DEBIAN_FRONTEND=noninteractive apt install -qq --yes --no-install-recommends \
locales && \
locale-gen en_US.UTF-8
ENV LANG="en_US.UTF-8" \
LANGUAGE="en_US.UTF-8" \
LC_ALL="en_US.UTF-8"
# system requirements to build most of the recipes
RUN apt update -qq > /dev/null \
&& DEBIAN_FRONTEND=noninteractive apt install -qq --yes --no-install-recommends \
autoconf \
automake \
build-essential \
ccache \
cmake \
gettext \
git \
libffi-dev \
libltdl-dev \
libssl-dev \
libtool \
openjdk-13-jdk \
patch \
pkg-config \
python3-pip \
python3-setuptools \
sudo \
unzip \
zip \
zlib1g-dev
# prepares non root env
RUN useradd --create-home --shell /bin/bash ${USER}
# with sudo access and no password
RUN usermod -append --groups sudo ${USER}
RUN echo "%sudo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
USER ${USER}
WORKDIR ${WORK_DIR}
COPY --chown=user:user . ${SRC_DIR}
# installs buildozer and dependencies
RUN pip3 install --user --upgrade Cython==0.29.19 wheel pip virtualenv ${SRC_DIR}
ENTRYPOINT ["buildozer"]

View file

@ -1,4 +1,3 @@
include *COPYING include *COPYING
include *CHANGELOG.md include *CHANGELOG.md
include *README.md
recursive-include buildozer *.spec recursive-include buildozer *.spec

220
README.md
View file

@ -1,220 +0,0 @@
Buildozer
=========
[![Tests](https://github.com/kivy/buildozer/workflows/Tests/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3ATests)
[![Android](https://github.com/kivy/buildozer/workflows/Android/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AAndroid)
[![iOS](https://github.com/kivy/buildozer/workflows/iOS/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AiOS)
[![Coverage Status](https://coveralls.io/repos/github/kivy/buildozer/badge.svg)](https://coveralls.io/github/kivy/buildozer)
[![Backers on Open Collective](https://opencollective.com/kivy/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/kivy/sponsors/badge.svg)](#sponsors)
Buildozer is a tool for creating application packages easily.
The goal is to have one "buildozer.spec" file in your app directory, describing
your application requirements and settings such as title, icon, included modules
etc. Buildozer will use that spec to create a package for Android, iOS, Windows,
OSX and/or Linux.
Buildozer currently supports packaging for Android via the [python-for-android](https://github.com/kivy/python-for-android/)
project, and for iOS via the kivy-ios project. iOS and OSX are still under work.
For Android, buildozer will automatically download and prepare the
build dependencies. For more information, see
[Android-SDK-NDK-Information](https://github.com/kivy/kivy/wiki/Android-SDK-NDK-Information).
Note that only Python 3 is supported.
Note that this tool has nothing to do with the eponymous online build service
[buildozer.io](https://buildozer.io).
## Installing Buildozer with target Python 3 (default):
- Install buildozer:
# via pip (latest stable, recommended)
# if you use a virtualenv, don't use the `--user` option
pip install --user buildozer
# latest dev version
# if you use a virtualenv, don't use the `--user` option
pip install --user https://github.com/kivy/buildozer/archive/master.zip
# git clone, for working on buildozer
git clone https://github.com/kivy/buildozer
cd buildozer
python setup.py build
pip install -e .
- Check buildozer is in your path
`which buildozer`
# if there is no result, and you installed with --user, add this line at the end of your `~/.bashrc` file.
export PATH=~/.local/bin/:$PATH
# and then run
. ~/.bashrc
- Go into your application directory and run:
buildozer init
# edit the buildozer.spec, then
buildozer android debug deploy run
## Buildozer Docker image
A Dockerfile is available to use buildozer through a Docker environment.
- Build with:
docker build --tag=buildozer .
- Run with:
docker run --volume "$(pwd)":/home/user/hostcwd buildozer --version
## Buildozer GitHub action
Use [ArtemSBulgakov/buildozer-action@v1](https://github.com/ArtemSBulgakov/buildozer-action)
to build your packages automatically on push or pull request.
See [full workflow example](https://github.com/ArtemSBulgakov/buildozer-action#full-workflow).
## Examples of Buildozer commands
```
# buildozer target command
buildozer android clean
buildozer android update
buildozer android deploy
buildozer android debug
buildozer android release
# or all in one (compile in debug, deploy on device)
buildozer android debug deploy
# set the default command if nothing set
buildozer setdefault android debug deploy run
```
## Usage
```
Usage:
buildozer [--profile <name>] [--verbose] [target] <command>...
buildozer --version
Available targets:
android Android target, based on python-for-android project
ios iOS target, based on kivy-ios project
Global commands (without target):
distclean Clean the whole Buildozer environment
help Show the Buildozer help
init Create an initial buildozer.spec in the current directory
serve Serve the bin directory via SimpleHTTPServer
setdefault Set the default command to run when no arguments are given
version Show the Buildozer version
Target commands:
clean Clean the target environment
update Update the target dependencies
debug Build the application in debug mode
release Build the application in release mode
deploy Deploy the application on the device
run Run the application on the device
serve Serve the bin directory via SimpleHTTPServer
Target "ios" commands:
list_identities List the available identities to use for signing.
xcode Open the xcode project.
Target "android" commands:
adb Run adb from the Android SDK. Args must come after --, or
use --alias to make an alias
logcat Show the log from the device
p4a Run p4a commands. Args must come after --, or use --alias
to make an alias
```
## `buildozer.spec`
See [buildozer/default.spec](https://raw.github.com/kivy/buildozer/master/buildozer/default.spec) for an up-to-date spec file.
## Default config
You can override the value of *any* `buildozer.spec` config token by
setting an appropriate environment variable. These are all of the
form ``$SECTION_TOKEN``, where SECTION is the config file section and
TOKEN is the config token to override. Dots are replaced by
underscores.
For example, here are some config tokens from the [app] section of the
config, along with the environment variables that would override them.
- ``title`` -> ``$APP_TITLE``
- ``package.name`` -> ``$APP_PACKAGE_NAME``
- ``p4a.source_dir`` -> ``$APP_P4A_SOURCE_DIR``
## Support
If you need assistance, you can ask for help on our mailing list:
* User Group : https://groups.google.com/group/kivy-users
* Email : kivy-users@googlegroups.com
Discord channel:
Server : https://chat.kivy.org
Channel : #support
For [debugging on Android](https://python-for-android.readthedocs.io/en/stable/troubleshooting/?highlight=adb#debugging-on-android), don't hesitate to use ADB to get logs of your application.
## Contributing
We love pull requests and discussing novel ideas. Check out our
[contribution guide](https://kivy.org/docs/contribute.html) and
feel free to improve buildozer.
The following mailing list and IRC channel are used exclusively for
discussions about developing the Kivy framework and its sister projects:
* Dev Group : https://groups.google.com/group/kivy-dev
* Email : kivy-dev@googlegroups.com
We also have a Discord channel:
* Server : https://chat.kivy.org
* Channel : #support
## License
Buildozer is released under the terms of the MIT License. Please refer to the
LICENSE file.
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/kivy#backer)]
<a href="https://opencollective.com/kivy#backers" target="_blank"><img src="https://opencollective.com/kivy/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/kivy#sponsor)]
<a href="https://opencollective.com/kivy/sponsor/0/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/1/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/2/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/3/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/4/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/5/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/6/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/7/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/8/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/kivy/sponsor/9/website" target="_blank"><img src="https://opencollective.com/kivy/sponsor/9/avatar.svg"></a>

241
README.rst Normal file
View file

@ -0,0 +1,241 @@
Buildozer
=========
Buildozer is a tool for creating application packages easily.
The goal is to have one "buildozer.spec" file in your app directory, describing
your application requirements and settings such as title, icon, included modules
etc. Buildozer will use that spec to create a package for Android, iOS, Windows,
OSX and/or Linux.
Buildozer currently supports packaging for Android via the `python-for-android
<http://github.com/kivy/python-for-android/>`_
project, and for iOS via the kivy-ios project. iOS and OSX are still under work.
For Android: please have a look at `Android-SDK-NDK-Informations
<https://github.com/kivy/kivy/wiki/Android-SDK-NDK-Informations>`_. Please note that
the default SDK/NDK coded in Buildozer works for Python 2.
We provide a ready-to-use `Virtual Machine for Virtualbox <https://kivy.org/#download>`_.
Note that this tool has nothing to do with the eponymous online build service
`buildozer.io <http://buildozer.io />`_.
Installing Buildozer with python2 support:
------------------------------------------
#. Install buildozer::
# via pip (latest stable, recommended)
sudo pip install buildozer
# latest dev version
sudo pip install https://github.com/kivy/buildozer/archive/master.zip
# git clone, for working on buildozer
git clone https://github.com/kivy/buildozer
cd buildozer
python setup.py build
sudo pip install -e .
#. Go into your application directory and run::
buildozer init
# edit the buildozer.spec, then
buildozer android debug deploy run
Installing Buildozer with python3 support:
------------------------------------------
The pip package does not yet support python3.
#. Install buildozer from source::
git clone https://github.com/kivy/buildozer
cd buildozer
python setup.py build
sudo pip install -e .
#. Download and extract the Crystax NDK somewhere (~/.buildozer/crystax-ndk is one option): https://www.crystax.net/en/download
#. Go into your application directory and execute::
buildozer init
#. Make sure the following lines are in your buildozer.spec file.::
# Require python3crystax:
requirements = python3crystax,kivy
# Point to the directory where you extracted the crystax-ndk:
android.ndk_path = <Your install path here. Use ~ for home DIR>
#. Finally, build, deploy and run the app on your phone::
buildozer android debug deploy run
#. Please note the "android" buildozer target, and use that for any and all buildozer commands you run (even if the docs just say "android").
Examples of Buildozer commands:
--------------------------------
::
# buildozer target command
buildozer android clean
buildozer android update
buildozer android deploy
buildozer android debug
buildozer android release
# or all in one (compile in debug, deploy on device)
buildozer android debug deploy
# set the default command if nothing set
buildozer setdefault android debug deploy run
Usage
-----
::
Usage:
buildozer [--profile <name>] [--verbose] [target] <command>...
buildozer --version
Available targets:
android Android target, based on python-for-android project
ios iOS target, based on kivy-ios project
android_old Android target, based on python-for-android project (old toolchain)
Global commands (without target):
distclean Clean the whole Buildozer environment.
help Show the Buildozer help.
init Create a initial buildozer.spec in the current directory
serve Serve the bin directory via SimpleHTTPServer
setdefault Set the default command to run when no arguments are given
version Show the Buildozer version
Target commands:
clean Clean the target environment
update Update the target dependencies
debug Build the application in debug mode
release Build the application in release mode
deploy Deploy the application on the device
run Run the application on the device
serve Serve the bin directory via SimpleHTTPServer
Target "android_old" commands:
adb Run adb from the Android SDK. Args must come after --, or
use --alias to make an alias
logcat Show the log from the device
Target "ios" commands:
list_identities List the available identities to use for signing.
xcode Open the xcode project.
Target "android" commands:
adb Run adb from the Android SDK. Args must come after --, or
use --alias to make an alias
logcat Show the log from the device
p4a Run p4a commands. Args must come after --, or use --alias
to make an alias
buildozer.spec
--------------
See `buildozer/default.spec <https://raw.github.com/kivy/buildozer/master/buildozer/default.spec>`_ for an up-to-date spec file.
Default config
--------------
You can override the value of *any* buildozer.spec config token by
setting an appropriate environment variable. These are all of the
form ``$SECTION_TOKEN``, where SECTION is the config file section and
TOKEN is the config token to override. Dots are replaced by
underscores.
For example, here are some config tokens from the [app] section of the
config, along with the environment variables that would override them.
- ``title`` -> ``$APP_TITLE``
- ``package.name`` -> ``$APP_PACKAGE_NAME``
- ``p4a.source_dir`` -> ``$APP_P4A_SOURCE_DIR``
Buildozer Virtual Machine
-------------------------
The current virtual machine (available via https://kivy.org/downloads/) allow
you to have a ready to use vm for building android application.
Using shared folders
++++++++++++++++++++
If the Virtualbox Guest tools are outdated, install the latest one:
- in the Virtualbox: `Devices` -> `Install Guest Additions CD images`
- in the guest/linux: Go to the cdrom and run the installer
- reboot the vm
VirtualBox filesystem doesn't support symlink anymore (don't
try the setextradata solution, it doesn't work.). So you must
do the build outside the shared folder. One solution:
- `sudo mkdir /build`
- `sudo chown kivy /build`
- In your buildozer.spec, section `[buildozer]`, set `build_dir = /build/buildozer-myapp`
Using your devices via the VM
+++++++++++++++++++++++++++++
There is a little icon on the bottom left that represent an USB plug.
Select it, and select your android device on it. Then you can check:
- `buildozer android adb -- devices`
If it doesn't, use Google. They are so many differents way / issues
depending your phone that Google will be your only source of
information, not us :)
Support
-------
If you need assistance, you can ask for help on our mailing list:
* User Group : https://groups.google.com/group/kivy-users
* Email : kivy-users@googlegroups.com
We also have an IRC channel:
* Server : irc.freenode.net
* Port : 6667, 6697 (SSL only)
* Channel : #kivy
Contributing
------------
We love pull requests and discussing novel ideas. Check out our
`contribution guide <http://kivy.org/docs/contribute.html>`_ and
feel free to improve buildozer.
The following mailing list and IRC channel are used exclusively for
discussions about developing the Kivy framework and its sister projects:
* Dev Group : https://groups.google.com/group/kivy-dev
* Email : kivy-dev@googlegroups.com
IRC channel:
* Server : irc.freenode.net
* Port : 6667, 6697 (SSL only)
* Channel : #kivy-dev
License
-------
Buildozer is released under the terms of the MIT License. Please refer to the
LICENSE file.

View file

@ -6,29 +6,30 @@ Generic Python packager for Android / iOS. Desktop later.
''' '''
__version__ = '1.2.0.dev0' __version__ = '0.34dev'
import os import os
import re import re
import sys import sys
import zipfile
import select import select
import codecs import codecs
import textwrap import textwrap
import warnings
from buildozer.jsonstore import JsonStore from buildozer.jsonstore import JsonStore
from sys import stdout, stderr, exit from sys import stdout, stderr, exit
from re import search from re import search
from os.path import join, exists, dirname, realpath, splitext, expanduser from os.path import join, exists, dirname, realpath, splitext, expanduser
from subprocess import Popen, PIPE, TimeoutExpired from subprocess import Popen, PIPE
from os import environ, unlink, walk, sep, listdir, makedirs from os import environ, unlink, rename, walk, sep, listdir, makedirs
from copy import copy from copy import copy
from shutil import copyfile, rmtree, copytree, move from shutil import copyfile, rmtree, copytree
from fnmatch import fnmatch from fnmatch import fnmatch
try:
from pprint import pformat from urllib.request import FancyURLopener
from configparser import SafeConfigParser
from urllib.request import FancyURLopener except ImportError:
from configparser import ConfigParser from urllib import FancyURLopener
from ConfigParser import SafeConfigParser
try: try:
import fcntl import fcntl
except ImportError: except ImportError:
@ -40,7 +41,7 @@ try:
colorama.init() colorama.init()
RESET_SEQ = colorama.Fore.RESET + colorama.Style.RESET_ALL RESET_SEQ = colorama.Fore.RESET + colorama.Style.RESET_ALL
COLOR_SEQ = lambda x: x # noqa: E731 COLOR_SEQ = lambda x: x
BOLD_SEQ = '' BOLD_SEQ = ''
if sys.platform == 'win32': if sys.platform == 'win32':
BLACK = colorama.Fore.BLACK + colorama.Style.DIM BLACK = colorama.Fore.BLACK + colorama.Style.DIM
@ -53,7 +54,7 @@ try:
except ImportError: except ImportError:
if sys.platform != 'win32': if sys.platform != 'win32':
RESET_SEQ = "\033[0m" RESET_SEQ = "\033[0m"
COLOR_SEQ = lambda x: "\033[1;{}m".format(30 + x) # noqa: E731 COLOR_SEQ = lambda x: "\033[1;{}m".format(30 + x)
BOLD_SEQ = "\033[1m" BOLD_SEQ = "\033[1m"
BLACK = 0 BLACK = 0
RED = 1 RED = 1
@ -70,14 +71,13 @@ except ImportError:
LOG_LEVELS_C = (RED, BLUE, BLACK) LOG_LEVELS_C = (RED, BLUE, BLACK)
LOG_LEVELS_T = 'EID' LOG_LEVELS_T = 'EID'
SIMPLE_HTTP_SERVER_PORT = 8000 SIMPLE_HTTP_SERVER_PORT = 8000
IS_PY3 = sys.version_info[0] >= 3
class ChromeDownloader(FancyURLopener): class ChromeDownloader(FancyURLopener):
version = ( version = (
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ' 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36') '(KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36')
urlretrieve = ChromeDownloader().retrieve urlretrieve = ChromeDownloader().retrieve
@ -97,23 +97,20 @@ class BuildozerCommandException(BuildozerException):
pass pass
class Buildozer: class Buildozer(object):
ERROR = 0
INFO = 1
DEBUG = 2
standard_cmds = ('distclean', 'update', 'debug', 'release', standard_cmds = ('distclean', 'update', 'debug', 'release',
'deploy', 'run', 'serve') 'deploy', 'run', 'serve')
def __init__(self, filename='buildozer.spec', target=None): def __init__(self, filename='buildozer.spec', target=None):
self.log_level = 2 super(Buildozer, self).__init__()
self.log_level = 1
self.environ = {} self.environ = {}
self.specfilename = filename self.specfilename = filename
self.state = None self.state = None
self.build_id = None self.build_id = None
self.config_profile = '' self.config_profile = ''
self.config = ConfigParser(allow_no_value=True) self.config = SafeConfigParser(allow_no_value=True)
self.config.optionxform = lambda value: value self.config.optionxform = lambda value: value
self.config.getlist = self._get_config_list self.config.getlist = self._get_config_list
self.config.getlistvalues = self._get_config_list_values self.config.getlistvalues = self._get_config_list_values
@ -122,7 +119,7 @@ class Buildozer:
self.config.getrawdefault = self._get_config_raw_default self.config.getrawdefault = self._get_config_raw_default
if exists(filename): if exists(filename):
self.config.read(filename, "utf-8") self.config.read(filename)
self.check_configuration_tokens() self.check_configuration_tokens()
# Check all section/tokens for env vars, and replace the # Check all section/tokens for env vars, and replace the
@ -131,10 +128,18 @@ class Buildozer:
try: try:
self.log_level = int(self.config.getdefault( self.log_level = int(self.config.getdefault(
'buildozer', 'log_level', '2')) 'buildozer', 'log_level', '1'))
except Exception: except:
pass pass
build_dir = self.config.getdefault('buildozer', 'builddir', None)
if build_dir:
# for backwards compatibility, append .buildozer to builddir
build_dir = join(build_dir, '.buildozer')
self.build_dir = self.config.getdefault('buildozer', 'build_dir', build_dir)
if self.build_dir:
self.build_dir = realpath(join(self.root_dir, self.build_dir))
self.user_bin_dir = self.config.getdefault('buildozer', 'bin_dir', None) self.user_bin_dir = self.config.getdefault('buildozer', 'bin_dir', None)
if self.user_bin_dir: if self.user_bin_dir:
self.user_bin_dir = realpath(join(self.root_dir, self.user_bin_dir)) self.user_bin_dir = realpath(join(self.root_dir, self.user_bin_dir))
@ -147,9 +152,10 @@ class Buildozer:
def set_target(self, target): def set_target(self, target):
'''Set the target to use (one of buildozer.targets, such as "android") '''Set the target to use (one of buildozer.targets, such as "android")
''' '''
target = self.translate_target(target)
self.targetname = target self.targetname = target
m = __import__('buildozer.targets.{0}'.format(target), m = __import__('buildozer.targets.{0}'.format(target),
fromlist=['buildozer']) fromlist=['buildozer'])
self.target = m.get_target(self) self.target = m.get_target(self)
self.check_build_layout() self.check_build_layout()
self.check_configuration_tokens() self.check_configuration_tokens()
@ -172,6 +178,7 @@ class Buildozer:
self.info('Check application requirements') self.info('Check application requirements')
self.check_application_requirements() self.check_application_requirements()
self.info('Check garden requirements')
self.check_garden_requirements() self.check_garden_requirements()
self.info('Compile platform') self.info('Compile platform')
@ -221,19 +228,13 @@ class Buildozer:
print('{} {}'.format(LOG_LEVELS_T[level], msg)) print('{} {}'.format(LOG_LEVELS_T[level], msg))
def debug(self, msg): def debug(self, msg):
self.log(self.DEBUG, msg) self.log(2, msg)
def log_env(self, level, env):
"""dump env into debug logger in readable format"""
self.log(level, "ENVIRONMENT:")
for k, v in env.items():
self.log(level, " {} = {}".format(k, pformat(v)))
def info(self, msg): def info(self, msg):
self.log(self.INFO, msg) self.log(1, msg)
def error(self, msg): def error(self, msg):
self.log(self.ERROR, msg) self.log(0, msg)
# #
# Internal check methods # Internal check methods
@ -253,7 +254,7 @@ class Buildozer:
def cmd(self, command, **kwargs): def cmd(self, command, **kwargs):
# prepare the environ, based on the system + our own env # prepare the environ, based on the system + our own env
env = environ.copy() env = copy(environ)
env.update(self.environ) env.update(self.environ)
# prepare the process # prepare the process
@ -269,18 +270,15 @@ class Buildozer:
get_stderr = kwargs.pop('get_stderr', False) get_stderr = kwargs.pop('get_stderr', False)
break_on_error = kwargs.pop('break_on_error', True) break_on_error = kwargs.pop('break_on_error', True)
sensible = kwargs.pop('sensible', False) sensible = kwargs.pop('sensible', False)
run_condition = kwargs.pop('run_condition', None)
quiet = kwargs.pop('quiet', False)
if not quiet: if not sensible:
if not sensible: self.debug('Run {0!r}'.format(command))
self.debug('Run {0!r}'.format(command)) else:
if type(command) in (list, tuple):
self.debug('Run {0!r} ...'.format(command[0]))
else: else:
if isinstance(command, (list, tuple)): self.debug('Run {0!r} ...'.format(command.split()[0]))
self.debug('Run {0!r} ...'.format(command[0])) self.debug('Cwd {}'.format(kwargs.get('cwd')))
else:
self.debug('Run {0!r} ...'.format(command.split()[0]))
self.debug('Cwd {}'.format(kwargs.get('cwd')))
# open the process # open the process
if sys.platform == 'win32': if sys.platform == 'win32':
@ -300,9 +298,9 @@ class Buildozer:
ret_stdout = [] if get_stdout else None ret_stdout = [] if get_stdout else None
ret_stderr = [] if get_stderr else None ret_stderr = [] if get_stderr else None
while not run_condition or run_condition(): while True:
try: try:
readx = select.select([fd_stdout, fd_stderr], [], [], 1)[0] readx = select.select([fd_stdout, fd_stderr], [], [])[0]
except select.error: except select.error:
break break
if fd_stdout in readx: if fd_stdout in readx:
@ -312,7 +310,10 @@ class Buildozer:
if get_stdout: if get_stdout:
ret_stdout.append(chunk) ret_stdout.append(chunk)
if show_output: if show_output:
stdout.write(chunk.decode('utf-8', 'replace')) if IS_PY3:
stdout.write(str(chunk))
else:
stdout.write(chunk)
if fd_stderr in readx: if fd_stderr in readx:
chunk = process.stderr.read() chunk = process.stderr.read()
if not chunk: if not chunk:
@ -320,24 +321,20 @@ class Buildozer:
if get_stderr: if get_stderr:
ret_stderr.append(chunk) ret_stderr.append(chunk)
if show_output: if show_output:
stderr.write(chunk.decode('utf-8', 'replace')) if IS_PY3:
stderr.write(chunk.decode('utf-8'))
else:
stderr.write(chunk)
stdout.flush() stdout.flush()
stderr.flush() stderr.flush()
try:
process.communicate(
timeout=(1 if run_condition and not run_condition() else None)
)
except TimeoutExpired:
pass
process.communicate()
if process.returncode != 0 and break_on_error: if process.returncode != 0 and break_on_error:
self.error('Command failed: {0}'.format(command)) self.error('Command failed: {0}'.format(command))
#self.log_env(self.ERROR, kwargs['env'])
self.error('') self.error('')
self.error('Buildozer failed to execute the last command') self.error('Buildozer failed to execute the last command')
if self.log_level <= self.INFO: if self.log_level <= 1:
self.error('If the error is not obvious, please raise the log_level to 2') self.error('If the error is not obvious, please raise the log_level to 2')
self.error('and retry the latest command.') self.error('and retry the latest command.')
else: else:
@ -346,12 +343,10 @@ class Buildozer:
self.error('raising an issue with buildozer itself.') self.error('raising an issue with buildozer itself.')
self.error('In case of a bug report, please add a full log with log_level = 2') self.error('In case of a bug report, please add a full log with log_level = 2')
raise BuildozerCommandException() raise BuildozerCommandException()
if ret_stdout: if ret_stdout:
ret_stdout = b''.join(ret_stdout) ret_stdout = b''.join(ret_stdout)
if ret_stderr: if ret_stderr:
ret_stderr = b''.join(ret_stderr) ret_stderr = b''.join(ret_stderr)
return (ret_stdout.decode('utf-8', 'ignore') if ret_stdout else None, return (ret_stdout.decode('utf-8', 'ignore') if ret_stdout else None,
ret_stderr.decode('utf-8') if ret_stderr else None, ret_stderr.decode('utf-8') if ret_stderr else None,
process.returncode) process.returncode)
@ -360,7 +355,7 @@ class Buildozer:
from pexpect import spawnu from pexpect import spawnu
# prepare the environ, based on the system + our own env # prepare the environ, based on the system + our own env
env = environ.copy() env = copy(environ)
env.update(self.environ) env.update(self.environ)
# prepare the process # prepare the process
@ -370,7 +365,10 @@ class Buildozer:
show_output = kwargs.pop('show_output') show_output = kwargs.pop('show_output')
if show_output: if show_output:
kwargs['logfile'] = codecs.getwriter('utf8')(stdout.buffer) if IS_PY3:
kwargs['logfile'] = codecs.getwriter('utf8')(stdout.buffer)
else:
kwargs['logfile'] = codecs.getwriter('utf8')(stdout)
if not sensible: if not sensible:
self.debug('Run (expect) {0!r}'.format(command)) self.debug('Run (expect) {0!r}'.format(command))
@ -405,13 +403,13 @@ class Buildozer:
adderror('[app] One of "version" or "version.regex" must be set') adderror('[app] One of "version" or "version.regex" must be set')
if version and version_regex: if version and version_regex:
adderror('[app] Conflict between "version" and "version.regex"' adderror('[app] Conflict between "version" and "version.regex"'
', only one can be used.') ', only one can be used.')
if version_regex and not get('app', 'version.filename', ''): if version_regex and not get('app', 'version.filename', ''):
adderror('[app] "version.filename" is missing' adderror('[app] "version.filename" is missing'
', required by "version.regex"') ', required by "version.regex"')
orientation = get('app', 'orientation', 'landscape') orientation = get('app', 'orientation', 'landscape')
if orientation not in ('landscape', 'portrait', 'all', 'sensorLandscape'): if orientation not in ('landscape', 'portrait', 'all'):
adderror('[app] "orientation" have an invalid value') adderror('[app] "orientation" have an invalid value')
if errors: if errors:
@ -481,9 +479,9 @@ class Buildozer:
return return
# remove all the requirements that the target can compile # remove all the requirements that the target can compile
onlyname = lambda x: x.split('==')[0] # noqa: E731 onlyname = lambda x: x.split('==')[0]
requirements = [x for x in requirements if onlyname(x) not in requirements = [x for x in requirements if onlyname(x) not in
target_available_packages] target_available_packages]
if requirements and hasattr(sys, 'real_prefix'): if requirements and hasattr(sys, 'real_prefix'):
e = self.error e = self.error
@ -494,12 +492,10 @@ class Buildozer:
exit(1) exit(1)
# did we already installed the libs ? # did we already installed the libs ?
if ( if exists(self.applibs_dir) and \
exists(self.applibs_dir) and self.state.get('cache.applibs', '') == requirements:
self.state.get('cache.applibs', '') == requirements self.debug('Application requirements already installed, pass')
): return
self.debug('Application requirements already installed, pass')
return
# recreate applibs # recreate applibs
self.rmdir(self.applibs_dir) self.rmdir(self.applibs_dir)
@ -520,17 +516,51 @@ class Buildozer:
cwd=self.buildozer_dir) cwd=self.buildozer_dir)
def check_garden_requirements(self): def check_garden_requirements(self):
'''Ensure required garden packages are available to be included.
'''
garden_requirements = self.config.getlist('app', garden_requirements = self.config.getlist('app',
'garden_requirements', '') 'garden_requirements', '')
if garden_requirements:
warnings.warn("`garden_requirements` settings is deprecated, use `requirements` instead", DeprecationWarning) # have we installed the garden packages?
if exists(self.gardenlibs_dir) and \
self.state.get('cache.gardenlibs', '') == garden_requirements:
self.debug('Garden requirements already installed, pass')
return
# we're going to reinstall all the garden libs.
self.rmdir(self.gardenlibs_dir)
# but if we don't have requirements, or if the user removed everything,
# don't do anything.
if not garden_requirements:
self.state['cache.gardenlibs'] = garden_requirements
return
self._ensure_virtualenv()
self.cmd('pip install Kivy-Garden==0.1.1', env=self.env_venv)
# recreate gardenlibs
self.mkdir(self.gardenlibs_dir)
for requirement in garden_requirements:
self._install_garden_package(requirement)
# save gardenlibs state
self.state['cache.gardenlibs'] = garden_requirements
def _install_garden_package(self, package):
self._ensure_virtualenv()
self.debug('Install garden package {} in buildozer_dir'.format(package))
self.cmd('garden install --app {}'.format(package),
env=self.env_venv,
cwd=self.buildozer_dir)
def _ensure_virtualenv(self): def _ensure_virtualenv(self):
if hasattr(self, 'venv'): if hasattr(self, 'venv'):
return return
self.venv = join(self.buildozer_dir, 'venv') self.venv = join(self.buildozer_dir, 'venv')
if not self.file_exists(self.venv): if not self.file_exists(self.venv):
self.cmd('python3 -m venv ./venv', self.cmd('virtualenv --python=python2.7 ./venv',
cwd=self.buildozer_dir) cwd=self.buildozer_dir)
# read virtualenv output and parse it # read virtualenv output and parse it
@ -581,9 +611,8 @@ class Buildozer:
target = join(cwd, target) target = join(cwd, target)
self.debug('Rename {0} to {1}'.format(source, target)) self.debug('Rename {0} to {1}'.format(source, target))
if not os.path.isdir(os.path.dirname(target)): if not os.path.isdir(os.path.dirname(target)):
self.error(('Rename {0} to {1} fails because {2} is not a ' self.error('Rename {0} to {1} fails becaues {2} is not a directory'.format(source, target, os.path.directory(target)))
'directory').format(source, target, target)) rename(source, target)
move(source, target)
def file_copy(self, source, target, cwd=None): def file_copy(self, source, target, cwd=None):
if cwd: if cwd:
@ -594,6 +623,10 @@ class Buildozer:
def file_extract(self, archive, cwd=None): def file_extract(self, archive, cwd=None):
if archive.endswith('.tgz') or archive.endswith('.tar.gz'): if archive.endswith('.tgz') or archive.endswith('.tar.gz'):
# XXX tarfile doesn't work for NDK-r8c :(
#tf = tarfile.open(archive, 'r:*')
#tf.extractall(path=cwd)
#tf.close()
self.cmd('tar xzf {0}'.format(archive), cwd=cwd) self.cmd('tar xzf {0}'.format(archive), cwd=cwd)
return return
@ -604,12 +637,12 @@ class Buildozer:
if archive.endswith('.bin'): if archive.endswith('.bin'):
# To process the bin files for linux and darwin systems # To process the bin files for linux and darwin systems
self.cmd('chmod a+x {0}'.format(archive), cwd=cwd) self.cmd('chmod a+x {0}'.format(archive),cwd=cwd)
self.cmd('./{0}'.format(archive), cwd=cwd) self.cmd('./{0}'.format(archive),cwd=cwd)
return return
if archive.endswith('.zip'): if archive.endswith('.zip'):
self.cmd('unzip -q {}'.format(join(cwd, archive)), cwd=cwd) self.cmd('unzip {}'.format(join(cwd, archive)), cwd=cwd)
return return
raise Exception('Unhandled extraction for type {0}'.format(archive)) raise Exception('Unhandled extraction for type {0}'.format(archive))
@ -640,9 +673,8 @@ class Buildozer:
else: else:
progression = '{0:.2f}%'.format( progression = '{0:.2f}%'.format(
index * blksize * 100. / float(size)) index * blksize * 100. / float(size))
if "CI" not in environ: stdout.write('- Download {}\r'.format(progression))
stdout.write('- Download {}\r'.format(progression)) stdout.flush()
stdout.flush()
url = url + filename url = url + filename
if cwd: if cwd:
@ -692,11 +724,12 @@ class Buildozer:
def build_application(self): def build_application(self):
self._copy_application_sources() self._copy_application_sources()
self._copy_application_libs() self._copy_application_libs()
self._copy_garden_libs()
self._add_sitecustomize() self._add_sitecustomize()
def _copy_application_sources(self): def _copy_application_sources(self):
# XXX clean the inclusion/exclusion algo. # XXX clean the inclusion/exclusion algo.
source_dir = realpath(expanduser(self.config.getdefault('app', 'source.dir', '.'))) source_dir = realpath(self.config.getdefault('app', 'source.dir', '.'))
include_exts = self.config.getlist('app', 'source.include_exts', '') include_exts = self.config.getlist('app', 'source.include_exts', '')
exclude_exts = self.config.getlist('app', 'source.exclude_exts', '') exclude_exts = self.config.getlist('app', 'source.exclude_exts', '')
exclude_dirs = self.config.getlist('app', 'source.exclude_dirs', '') exclude_dirs = self.config.getlist('app', 'source.exclude_dirs', '')
@ -706,17 +739,11 @@ class Buildozer:
'') '')
app_dir = self.app_dir app_dir = self.app_dir
include_exts = [ext.lower() for ext in include_exts]
exclude_exts = [ext.lower() for ext in exclude_exts]
exclude_dirs = [dir.lower() for dir in exclude_dirs]
exclude_patterns = [pat.lower() for pat in exclude_patterns]
include_patterns = [pat.lower() for pat in include_patterns]
self.debug('Copy application source from {}'.format(source_dir)) self.debug('Copy application source from {}'.format(source_dir))
rmtree(self.app_dir) rmtree(self.app_dir)
for root, dirs, files in walk(source_dir, followlinks=True): for root, dirs, files in walk(source_dir):
# avoid hidden directory # avoid hidden directory
if True in [x.startswith('.') for x in root.split(sep)]: if True in [x.startswith('.') for x in root.split(sep)]:
continue continue
@ -777,7 +804,7 @@ class Buildozer:
# TODO more filters # TODO more filters
basename, ext = splitext(fn) basename, ext = splitext(fn)
if ext: if ext:
ext = ext[1:].lower() ext = ext[1:]
if include_exts and ext not in include_exts: if include_exts and ext not in include_exts:
continue continue
if exclude_exts and ext in exclude_exts: if exclude_exts and ext in exclude_exts:
@ -798,12 +825,17 @@ class Buildozer:
# copy also the libs # copy also the libs
copytree(self.applibs_dir, join(self.app_dir, '_applibs')) copytree(self.applibs_dir, join(self.app_dir, '_applibs'))
def _copy_garden_libs(self):
if exists(self.gardenlibs_dir):
copytree(self.gardenlibs_dir, join(self.app_dir, 'libs'))
def _add_sitecustomize(self): def _add_sitecustomize(self):
copyfile(join(dirname(__file__), 'sitecustomize.py'), copyfile(join(dirname(__file__), 'sitecustomize.py'),
join(self.app_dir, 'sitecustomize.py')) join(self.app_dir, 'sitecustomize.py'))
main_py = join(self.app_dir, 'service', 'main.py') main_py = join(self.app_dir, 'service', 'main.py')
if not self.file_exists(main_py): if not self.file_exists(main_py):
#self.error('Unable to patch main_py to add applibs directory.')
return return
header = (b'import sys, os; ' header = (b'import sys, os; '
@ -820,33 +852,16 @@ class Buildozer:
'''Return a "valid" name from a name with lot of invalid chars '''Return a "valid" name from a name with lot of invalid chars
(allowed characters: a-z, A-Z, 0-9, -, _) (allowed characters: a-z, A-Z, 0-9, -, _)
''' '''
return re.sub(r'[^a-zA-Z0-9_\-]', '_', name) return re.sub('[^a-zA-Z0-9_\-]', '_', name)
@property @property
def root_dir(self): def root_dir(self):
return realpath(expanduser(dirname(self.specfilename))) return realpath(dirname(self.specfilename))
@property
def user_build_dir(self):
"""The user-provided build dir, if any."""
# Check for a user-provided build dir
# Check the (deprecated) builddir token, for backwards compatibility
build_dir = self.config.getdefault('buildozer', 'builddir', None)
if build_dir is not None:
# for backwards compatibility, append .buildozer to builddir
build_dir = join(build_dir, '.buildozer')
build_dir = self.config.getdefault('buildozer', 'build_dir', build_dir)
if build_dir is not None:
build_dir = realpath(join(self.root_dir, expanduser(build_dir)))
return build_dir
@property @property
def buildozer_dir(self): def buildozer_dir(self):
'''The directory in which to run the app build.''' if self.build_dir:
if self.user_build_dir is not None: return self.build_dir
return self.user_build_dir
return join(self.root_dir, '.buildozer') return join(self.root_dir, '.buildozer')
@property @property
@ -867,6 +882,10 @@ class Buildozer:
def applibs_dir(self): def applibs_dir(self):
return join(self.buildozer_dir, 'applibs') return join(self.buildozer_dir, 'applibs')
@property
def gardenlibs_dir(self):
return join(self.buildozer_dir, 'libs')
@property @property
def global_buildozer_dir(self): def global_buildozer_dir(self):
return join(expanduser('~'), '.buildozer') return join(expanduser('~'), '.buildozer')
@ -891,10 +910,28 @@ class Buildozer:
return package_name return package_name
return '{}.{}'.format(package_domain, package_name) return '{}.{}'.format(package_domain, package_name)
# #
# command line invocation # command line invocation
# #
def translate_target(self, target, inverse=False):
# FIXME at some point, refactor to remove completely android old toolchain
if inverse:
if target == "android":
target = "android_old"
elif target == "android_new":
target = "android"
else:
if target == "android":
target = "android_new"
elif target == "android_new":
self.error("ERROR: The target android_new is now android")
exit(1)
elif target == "android_old":
target = "android"
return target
def targets(self): def targets(self):
for fn in listdir(join(dirname(__file__), 'targets')): for fn in listdir(join(dirname(__file__), 'targets')):
if fn.startswith('.') or fn.startswith('__'): if fn.startswith('.') or fn.startswith('__'):
@ -905,7 +942,7 @@ class Buildozer:
try: try:
m = __import__('buildozer.targets.{0}'.format(target), m = __import__('buildozer.targets.{0}'.format(target),
fromlist=['buildozer']) fromlist=['buildozer'])
yield target, m yield self.translate_target(target, inverse=True), m
except NotImplementedError: except NotImplementedError:
pass pass
except: except:
@ -935,7 +972,8 @@ class Buildozer:
if not meth.__doc__: if not meth.__doc__:
continue continue
doc = list(meth.__doc__.strip().splitlines())[0].strip() doc = [x for x in
meth.__doc__.strip().splitlines()][0].strip()
print(' {0:<18} {1}'.format(name, doc)) print(' {0:<18} {1}'.format(name, doc))
print('') print('')
@ -1012,8 +1050,8 @@ class Buildozer:
# maybe it's a target? # maybe it's a target?
targets = [x[0] for x in self.targets()] targets = [x[0] for x in self.targets()]
if command not in targets: if self.translate_target(command, inverse=True) not in targets:
print('Unknown command/target {}'.format(command)) print('Unknown command/target {}'.format(self.translate_target(command, inverse=True)))
exit(1) exit(1)
self.set_target(command) self.set_target(command)
@ -1023,6 +1061,11 @@ class Buildozer:
'''If effective user id is 0, display a warning and require '''If effective user id is 0, display a warning and require
user input to continue (or to cancel)''' user input to continue (or to cancel)'''
if IS_PY3:
input_func = input
else:
input_func = raw_input
warn_on_root = self.config.getdefault('buildozer', 'warn_on_root', '1') warn_on_root = self.config.getdefault('buildozer', 'warn_on_root', '1')
try: try:
euid = os.geteuid() == 0 euid = os.geteuid() == 0
@ -1035,7 +1078,7 @@ class Buildozer:
print('\033[91mThis is \033[1mnot\033[0m \033[91mrecommended, and may lead to problems later.\033[0m') print('\033[91mThis is \033[1mnot\033[0m \033[91mrecommended, and may lead to problems later.\033[0m')
cont = None cont = None
while cont not in ('y', 'n'): while cont not in ('y', 'n'):
cont = input('Are you sure you want to continue [y/n]? ') cont = input_func('Are you sure you want to continue [y/n]? ')
if cont == 'n': if cont == 'n':
sys.exit() sys.exit()
@ -1060,23 +1103,6 @@ class Buildozer:
return return
rmtree(self.global_buildozer_dir) rmtree(self.global_buildozer_dir)
def cmd_appclean(self, *args):
'''Clean the .buildozer folder in the app directory.
This command specifically refuses to delete files in a
user-specified build directory, to avoid accidentally deleting
more than the user intends.
'''
if self.user_build_dir is not None:
self.error(
('Failed: build_dir is specified as {} in the buildozer config. `appclean` will '
'not attempt to delete files in a user-specified build directory.').format(self.user_build_dir))
elif exists(self.buildozer_dir):
self.info('Deleting {}'.format(self.buildozer_dir))
rmtree(self.buildozer_dir)
else:
self.error('{} already deleted, skipping.'.format(self.buildozer_dir))
def cmd_help(self, *args): def cmd_help(self, *args):
'''Show the Buildozer help. '''Show the Buildozer help.
''' '''
@ -1142,6 +1168,8 @@ class Buildozer:
value, section_base, profile)) value, section_base, profile))
self.config.set(section_base, name, value) self.config.set(section_base, name, value)
def _get_config_list_values(self, *args, **kwargs): def _get_config_list_values(self, *args, **kwargs):
kwargs['with_values'] = True kwargs['with_values'] = True
return self._get_config_list(*args, **kwargs) return self._get_config_list(*args, **kwargs)
@ -1217,7 +1245,6 @@ def set_config_from_envs(config):
for token in config.options(section): for token in config.options(section):
set_config_token_from_env(section, token, config) set_config_token_from_env(section, token, config)
def set_config_token_from_env(section, token, config): def set_config_token_from_env(section, token, config):
'''Given a config section and token, checks for an appropriate '''Given a config section and token, checks for an appropriate
environment variable. If the variable exists, sets the config entry to environment variable. If the variable exists, sets the config entry to

View file

@ -22,7 +22,7 @@ source.include_exts = py,png,jpg,kv,atlas
#source.exclude_exts = spec #source.exclude_exts = spec
# (list) List of directory to exclude (let empty to not exclude anything) # (list) List of directory to exclude (let empty to not exclude anything)
#source.exclude_dirs = tests, bin, venv #source.exclude_dirs = tests, bin
# (list) List of exclusions using pattern matching # (list) List of exclusions using pattern matching
#source.exclude_patterns = license,images/*/*.jpg #source.exclude_patterns = license,images/*/*.jpg
@ -36,19 +36,22 @@ version = 0.1
# (list) Application requirements # (list) Application requirements
# comma separated e.g. requirements = sqlite3,kivy # comma separated e.g. requirements = sqlite3,kivy
requirements = python3,kivy requirements = kivy
# (str) Custom source folders for requirements # (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes # Sets custom source for any requirements with recipes
# requirements.source.kivy = ../../kivy # requirements.source.kivy = ../../kivy
# (list) Garden requirements
#garden_requirements =
# (str) Presplash of the application # (str) Presplash of the application
#presplash.filename = %(source.dir)s/data/presplash.png #presplash.filename = %(source.dir)s/data/presplash.png
# (str) Icon of the application # (str) Icon of the application
#icon.filename = %(source.dir)s/data/icon.png #icon.filename = %(source.dir)s/data/icon.png
# (str) Supported orientation (one of landscape, sensorLandscape, portrait or all) # (str) Supported orientation (one of landscape, portrait or all)
orientation = portrait orientation = portrait
# (list) List of service to declare # (list) List of service to declare
@ -74,43 +77,27 @@ osx.kivy_version = 1.9.1
# (bool) Indicate if the application should be fullscreen or not # (bool) Indicate if the application should be fullscreen or not
fullscreen = 0 fullscreen = 0
# (string) Presplash background color (for android toolchain) # (string) Presplash background color (for new android toolchain)
# Supported formats are: #RRGGBB #AARRGGBB or one of the following names: # Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
# red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,
# darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,
# olive, purple, silver, teal. # olive, purple, silver, teal.
#android.presplash_color = #FFFFFF #android.presplash_color = #FFFFFF
# (string) Presplash animation using Lottie format.
# see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/
# for general documentation.
# Lottie files can be created using various tools, like Adobe After Effect or Synfig.
#android.presplash_lottie = "path/to/lottie/file.json"
# (str) Adaptive icon of the application (used if Android API level is 26+ at runtime)
#icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png
#icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
# (list) Permissions # (list) Permissions
#android.permissions = INTERNET #android.permissions = INTERNET
# (list) features (adds uses-feature -tags to manifest) # (int) Android API to use
#android.features = android.hardware.usb.host #android.api = 19
# (int) Target Android API, should be as high as possible. # (int) Minimum API required
#android.api = 27 #android.minapi = 9
# (int) Minimum API your APK will support.
#android.minapi = 21
# (int) Android SDK version to use # (int) Android SDK version to use
#android.sdk = 20 #android.sdk = 20
# (str) Android NDK version to use # (str) Android NDK version to use
#android.ndk = 19b #android.ndk = 9c
# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
#android.ndk_api = 21
# (bool) Use --private data storage (True) or --dir public storage (False) # (bool) Use --private data storage (True) or --dir public storage (False)
#android.private_storage = True #android.private_storage = True
@ -129,33 +116,8 @@ fullscreen = 0
# when an update is due and you just want to test/build your package # when an update is due and you just want to test/build your package
# android.skip_update = False # android.skip_update = False
# (bool) If True, then automatically accept SDK license
# agreements. This is intended for automation only. If set to False,
# the default, you will be shown the license when first running
# buildozer.
# android.accept_sdk_license = False
# (str) Android entry point, default is ok for Kivy-based app # (str) Android entry point, default is ok for Kivy-based app
#android.entrypoint = org.kivy.android.PythonActivity #android.entrypoint = org.renpy.android.PythonActivity
# (str) Full name including package path of the Java class that implements Android Activity
# use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity
#android.activity_class_name = org.kivy.android.PythonActivity
# (str) Extra xml to write directly inside the <manifest> element of AndroidManifest.xml
# use that parameter to provide a filename from where to load your custom XML code
#android.extra_manifest_xml = ./src/android/extra_manifest.xml
# (str) Extra xml to write directly inside the <manifest><application> tag of AndroidManifest.xml
# use that parameter to provide a filename from where to load your custom XML arguments:
#android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml
# (str) Full name including package path of the Java class that implements Python Service
# use that parameter to set custom Java class instead of PythonService
#android.service_class_name = org.kivy.android.PythonService
# (str) Android app theme, default is ok for Kivy-based app
# android.apptheme = "@android:style/Theme.NoTitleBar"
# (list) Pattern to whitelist for the whole project # (list) Pattern to whitelist for the whole project
#android.whitelist = #android.whitelist =
@ -176,36 +138,16 @@ fullscreen = 0
# directory containing the files) # directory containing the files)
#android.add_src = #android.add_src =
# (list) Android AAR archives to add # (list) Android AAR archives to add (currently works only with sdl2_gradle
# bootstrap)
#android.add_aars = #android.add_aars =
# (list) Gradle dependencies to add # (list) Gradle dependencies to add (currently works only with sdl2_gradle
# bootstrap)
#android.gradle_dependencies = #android.gradle_dependencies =
# (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' # (str) python-for-android branch to use, defaults to master
# contains an 'androidx' package, or any package from Kotlin source. #p4a.branch = stable
# android.enable_androidx requires android.api >= 28
#android.enable_androidx = False
# (list) add java compile options
# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
# see https://developer.android.com/studio/write/java8-support for further information
# android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"
# (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}
# please enclose in double quotes
# e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"
#android.add_gradle_repositories =
# (list) packaging options to add
# see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
# can be necessary to solve conflicts in gradle_dependencies
# please enclose in double quotes
# e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"
#android.add_packaging_options =
# (list) Java classes to add as activities to the manifest.
#android.add_activities = com.example.ExampleActivity
# (str) OUYA Console category. Should be one of GAME or APP # (str) OUYA Console category. Should be one of GAME or APP
# If you leave this blank, OUYA support will not be enabled # If you leave this blank, OUYA support will not be enabled
@ -217,13 +159,9 @@ fullscreen = 0
# (str) XML file to include as an intent filters in <activity> tag # (str) XML file to include as an intent filters in <activity> tag
#android.manifest.intent_filters = #android.manifest.intent_filters =
# (str) launchMode to set for the main activity
#android.manifest.launch_mode = standard
# (list) Android additional libraries to copy into libs/armeabi # (list) Android additional libraries to copy into libs/armeabi
#android.add_libs_armeabi = libs/android/*.so #android.add_libs_armeabi = libs/android/*.so
#android.add_libs_armeabi_v7a = libs/android-v7/*.so #android.add_libs_armeabi_v7a = libs/android-v7/*.so
#android.add_libs_arm64_v8a = libs/android-v8/*.so
#android.add_libs_x86 = libs/android-x86/*.so #android.add_libs_x86 = libs/android-x86/*.so
#android.add_libs_mips = libs/android-mips/*.so #android.add_libs_mips = libs/android-mips/*.so
@ -238,59 +176,19 @@ fullscreen = 0
# project.properties automatically.) # project.properties automatically.)
#android.library_references = #android.library_references =
# (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag
#android.uses_library =
# (str) Android logcat filters to use # (str) Android logcat filters to use
#android.logcat_filters = *:S python:D #android.logcat_filters = *:S python:D
# (bool) Android logcat only display log for activity's pid
#android.logcat_pid_only = False
# (str) Android additional adb arguments
#android.adb_args = -H host.docker.internal
# (bool) Copy library instead of making a libpymodules.so # (bool) Copy library instead of making a libpymodules.so
#android.copy_libs = 1 #android.copy_libs = 1
# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86
android.arch = armeabi-v7a android.arch = armeabi-v7a
# (int) overrides automatic versionCode computation (used in build.gradle)
# this is not the same as app version and should only be edited if you know what you're doing
# android.numeric_version = 1
# (bool) enables Android auto backup feature (Android API >=23)
android.allow_backup = True
# (str) XML file for custom backup rules (see official auto backup documentation)
# android.backup_rules =
# (str) If you need to insert variables into your AndroidManifest.xml file,
# you can do so with the manifestPlaceholders property.
# This property takes a map of key-value pairs. (via a string)
# Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]
# android.manifest_placeholders = [:]
# (bool) disables the compilation of py to pyc/pyo files when packaging
# android.no-compile-pyo = True
# #
# Python for android (p4a) specific # Python for android (p4a) specific
# #
# (str) python-for-android URL to use for checkout
#p4a.url =
# (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)
#p4a.fork = kivy
# (str) python-for-android branch to use, defaults to master
#p4a.branch = master
# (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch
#p4a.commit = HEAD
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
#p4a.source_dir = #p4a.source_dir =
@ -303,16 +201,6 @@ android.allow_backup = True
# (str) Bootstrap to use for android builds # (str) Bootstrap to use for android builds
# p4a.bootstrap = sdl2 # p4a.bootstrap = sdl2
# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)
#p4a.port =
# Control passing the --use-setup-py vs --ignore-setup-py to p4a
# "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not
# Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py
# NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate
# setup.py if you're using Poetry, but you need to add "toml" to source.include_exts.
#p4a.setup_py = false
# #
# iOS specific # iOS specific
@ -320,50 +208,19 @@ android.allow_backup = True
# (str) Path to a custom kivy-ios folder # (str) Path to a custom kivy-ios folder
#ios.kivy_ios_dir = ../kivy-ios #ios.kivy_ios_dir = ../kivy-ios
# Alternately, specify the URL and branch of a git checkout:
ios.kivy_ios_url = https://github.com/kivy/kivy-ios
ios.kivy_ios_branch = master
# Another platform dependency: ios-deploy
# Uncomment to use a custom checkout
#ios.ios_deploy_dir = ../ios_deploy
# Or specify URL and branch
ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
ios.ios_deploy_branch = 1.10.0
# (bool) Whether or not to sign the code
ios.codesign.allowed = false
# (str) Name of the certificate to use for signing the debug version # (str) Name of the certificate to use for signing the debug version
# Get a list of available identities: buildozer ios list_identities # Get a list of available identities: buildozer ios list_identities
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)" #ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
# (str) The development team to use for signing the debug version
#ios.codesign.development_team.debug = <hexstring>
# (str) Name of the certificate to use for signing the release version # (str) Name of the certificate to use for signing the release version
#ios.codesign.release = %(ios.codesign.debug)s #ios.codesign.release = %(ios.codesign.debug)s
# (str) The development team to use for signing the release version
#ios.codesign.development_team.release = <hexstring>
# (str) URL pointing to .ipa file to be installed
# This option should be defined along with `display_image_url` and `full_size_image_url` options.
#ios.manifest.app_url =
# (str) URL pointing to an icon (57x57px) to be displayed during download
# This option should be defined along with `app_url` and `full_size_image_url` options.
#ios.manifest.display_image_url =
# (str) URL pointing to a large icon (512x512px) to be used by iTunes
# This option should be defined along with `app_url` and `display_image_url` options.
#ios.manifest.full_size_image_url =
[buildozer] [buildozer]
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2 log_level = 1
# (int) Display warning if buildozer is run as root (0 = False, 1 = True) # (int) Display warning if buildozer is run as root (0 = False, 1 = True)
warn_on_root = 1 warn_on_root = 1

View file

@ -1,18 +1,21 @@
""" """
Replacement for shelve, using json. Replacement for shelve, using json.
This was needed to correctly support db between Python 2 and 3. This is currently needed to correctly support db between Python 2 and 3.
""" """
__all__ = ["JsonStore"] __all__ = ["JsonStore"]
import io import io
from json import load, dump import sys
from json import load, dump, dumps
from os.path import exists from os.path import exists
IS_PY3 = sys.version_info[0] >= 3
class JsonStore: class JsonStore(object):
def __init__(self, filename): def __init__(self, filename):
super(JsonStore, self).__init__()
self.filename = filename self.filename = filename
self.data = {} self.data = {}
if exists(filename): if exists(filename):
@ -43,5 +46,11 @@ class JsonStore:
return self.data.keys() return self.data.keys()
def sync(self): def sync(self):
with open(self.filename, 'w') as fd: # http://stackoverflow.com/questions/12309269/write-json-data-to-file-in-python/14870531#14870531
dump(self.data, fd, ensure_ascii=False) if IS_PY3:
with open(self.filename, 'w') as fd:
dump(self.data, fd, ensure_ascii=False)
else:
with io.open(self.filename, 'w', encoding='utf-8') as fd:
fd.write(unicode(dumps(self.data, ensure_ascii=False)))

View file

@ -11,8 +11,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import absolute_import, division, print_function
class Infinity:
class Infinity(object):
def __repr__(self): def __repr__(self):
return "Infinity" return "Infinity"
@ -41,11 +43,10 @@ class Infinity:
def __neg__(self): def __neg__(self):
return NegativeInfinity return NegativeInfinity
Infinity = Infinity() Infinity = Infinity()
class NegativeInfinity: class NegativeInfinity(object):
def __repr__(self): def __repr__(self):
return "-Infinity" return "-Infinity"
@ -74,5 +75,4 @@ class NegativeInfinity:
def __neg__(self): def __neg__(self):
return Infinity return Infinity
NegativeInfinity = NegativeInfinity() NegativeInfinity = NegativeInfinity()

View file

@ -11,6 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import absolute_import, division, print_function
import collections import collections
import itertools import itertools
import re import re
@ -47,7 +49,7 @@ class InvalidVersion(ValueError):
""" """
class _BaseVersion: class _BaseVersion(object):
def __hash__(self): def __hash__(self):
return hash(self._key) return hash(self._key)
@ -162,7 +164,6 @@ def _legacy_cmpkey(version):
return epoch, parts return epoch, parts
# Deliberately not anchored to the start and end of the string, to make it # Deliberately not anchored to the start and end of the string, to make it
# easier for 3rd party code to reuse # easier for 3rd party code to reuse
VERSION_PATTERN = r""" VERSION_PATTERN = r"""
@ -254,7 +255,7 @@ class Version(_BaseVersion):
# Pre-release # Pre-release
if self._version.pre is not None: if self._version.pre is not None:
parts.append("-" + "".join(str(x) for x in self._version.pre)) parts.append("".join(str(x) for x in self._version.pre))
# Post-release # Post-release
if self._version.post is not None: if self._version.post is not None:

View file

@ -14,11 +14,9 @@ def main():
except BuildozerCommandException: except BuildozerCommandException:
# don't show the exception in the command line. The log already show # don't show the exception in the command line. The log already show
# the command failed. # the command failed.
sys.exit(1) pass
except BuildozerException as error: except BuildozerException as error:
Buildozer().error('%s' % error) Buildozer().error('%s' % error)
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -21,9 +21,13 @@ from sys import stdout, stdin, exit
from select import select from select import select
from os.path import join, expanduser, realpath, exists, splitext from os.path import join, expanduser, realpath, exists, splitext
from os import makedirs, walk, getcwd from os import makedirs, walk, getcwd
from configparser import ConfigParser try:
from configparser import SafeConfigParser
except ImportError:
from ConfigParser import SafeConfigParser
try: try:
import termios import termios
import tty
has_termios = True has_termios = True
except ImportError: except ImportError:
has_termios = False has_termios = False
@ -127,7 +131,7 @@ class BuildozerRemote(Buildozer):
self.package_full_name) self.package_full_name)
self.debug('Remote build directory: {}'.format(self.remote_build_dir)) self.debug('Remote build directory: {}'.format(self.remote_build_dir))
self._ssh_mkdir(self.remote_build_dir) self._ssh_mkdir(self.remote_build_dir)
self._ssh_sync(__path__[0]) # noqa: F821 undefined name self._ssh_sync(__path__[0])
def _sync_application_sources(self): def _sync_application_sources(self):
self.info('Synchronize application sources') self.info('Synchronize application sources')
@ -135,7 +139,7 @@ class BuildozerRemote(Buildozer):
# create custom buildozer.spec # create custom buildozer.spec
self.info('Create custom buildozer.spec') self.info('Create custom buildozer.spec')
config = ConfigParser() config = SafeConfigParser()
config.read('buildozer.spec') config.read('buildozer.spec')
config.set('app', 'source.dir', 'app') config.set('app', 'source.dir', 'app')
@ -155,7 +159,7 @@ class BuildozerRemote(Buildozer):
self.remote_build_dir, self.remote_build_dir,
'--verbose' if self.log_level == 2 else '', '--verbose' if self.log_level == 2 else '',
' '.join(args), ' '.join(args),
) )
self._ssh_command(cmd) self._ssh_command(cmd)
def _ssh_mkdir(self, *args): def _ssh_mkdir(self, *args):
@ -173,10 +177,10 @@ class BuildozerRemote(Buildozer):
def _ssh_sync(self, directory, mode='put'): def _ssh_sync(self, directory, mode='put'):
self.debug('Syncing {} directory'.format(directory)) self.debug('Syncing {} directory'.format(directory))
directory = realpath(expanduser(directory)) directory = realpath(directory)
base_strip = directory.rfind('/') base_strip = directory.rfind('/')
if mode == 'get': if mode == 'get':
local_dir = join(directory, 'bin') local_dir = join(directory,'bin')
remote_dir = join(self.remote_build_dir, 'bin') remote_dir = join(self.remote_build_dir, 'bin')
if not exists(local_dir): if not exists(local_dir):
makedirs(local_dir) makedirs(local_dir)
@ -196,6 +200,9 @@ class BuildozerRemote(Buildozer):
def _ssh_command(self, command): def _ssh_command(self, command):
self.debug('Execute remote command {}'.format(command)) self.debug('Execute remote command {}'.format(command))
#shell = self._ssh_client.invoke_shell()
#shell.sendall(command)
#shell.sendall('\nexit\n')
transport = self._ssh_client.get_transport() transport = self._ssh_client.get_transport()
channel = transport.open_session() channel = transport.open_session()
try: try:
@ -213,6 +220,8 @@ class BuildozerRemote(Buildozer):
def _posix_shell(self, chan): def _posix_shell(self, chan):
oldtty = termios.tcgetattr(stdin) oldtty = termios.tcgetattr(stdin)
try: try:
#tty.setraw(stdin.fileno())
#tty.setcbreak(stdin.fileno())
chan.settimeout(0.0) chan.settimeout(0.0)
while True: while True:
@ -225,6 +234,7 @@ class BuildozerRemote(Buildozer):
break break
stdout.write(x) stdout.write(x)
stdout.flush() stdout.flush()
#print len(x), repr(x)
except socket.timeout: except socket.timeout:
pass pass
if stdin in r: if stdin in r:
@ -236,7 +246,7 @@ class BuildozerRemote(Buildozer):
termios.tcsetattr(stdin, termios.TCSADRAIN, oldtty) termios.tcsetattr(stdin, termios.TCSADRAIN, oldtty)
# thanks to Mike Looijmans for this code # thanks to Mike Looijmans for this code
def _windows_shell(self, chan): def _windows_shell(self,chan):
import threading import threading
stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
@ -264,7 +274,6 @@ class BuildozerRemote(Buildozer):
# user hit ^Z or F6 # user hit ^Z or F6
pass pass
def main(): def main():
try: try:
BuildozerRemote().run_command(sys.argv[1:]) BuildozerRemote().run_command(sys.argv[1:])
@ -273,6 +282,5 @@ def main():
except BuildozerException as error: except BuildozerException as error:
Buildozer().error('%s' % error) Buildozer().error('%s' % error)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -1,6 +1,4 @@
from sys import exit from sys import exit
import os
from os.path import join
def no_config(f): def no_config(f):
@ -8,8 +6,9 @@ def no_config(f):
return f return f
class Target: class Target(object):
def __init__(self, buildozer): def __init__(self, buildozer):
super(Target, self).__init__()
self.buildozer = buildozer self.buildozer = buildozer
self.build_mode = 'debug' self.build_mode = 'debug'
self.platform_update = False self.platform_update = False
@ -147,117 +146,3 @@ class Target:
def cmd_serve(self, *args): def cmd_serve(self, *args):
self.buildozer.cmd_serve() self.buildozer.cmd_serve()
def path_or_git_url(self, repo, owner='kivy', branch='master',
url_format='https://github.com/{owner}/{repo}.git',
platform=None,
squash_hyphen=True):
"""Get source location for a git checkout
This method will check the `buildozer.spec` for the keys:
{repo}_dir
{repo}_url
{repo}_branch
and use them to determine the source location for a git checkout.
If a `platform` is specified, {platform}.{repo} will be used
as the base for the buildozer key
`{repo}_dir` specifies a custom checkout location
(relative to `buildozer.root_dir`). If present, `path` will be
set to this value and `url`, `branch` will be set to None,
None. Otherwise, `{repo}_url` and `{repo}_branch` will be
examined.
If no keys are present, the kwargs will be used to create
a sensible default URL and branch.
:Parameters:
`repo`: str (required)
name of repository to fetch. Used both for buildozer
keys ({platform}.{repo}_dir|_url|_branch) and in building
default git URL
`branch`: str (default 'master')
Specific branch to retrieve if none specified in
buildozer.spec.
`owner`: str
owner of repo.
`platform`: str or None
platform prefix to use when retrieving `buildozer.spec`
keys. If specified, key names will be {platform}.{repo}
instead of just {repo}
`squash_hyphen`: boolean
if True, change '-' to '_' when looking for
keys in buildozer.spec. This lets us keep backwards
compatibility with old buildozer.spec files
`url_format`: format string
Used to construct default git URL.
can use {repo} {owner} and {branch} if needed.
:Returns:
A Tuple (path, url, branch) where
`path`
Path to a custom git checkout. If specified,
both `url` and `branch` will be None
`url`
URL of git repository from where code should be
checked-out
`branch`
branch name (or tag) that should be used for the
check-out.
"""
if squash_hyphen:
key = repo.replace('-', '_')
else:
key = repo
if platform:
key = "{}.{}".format(platform, key)
config = self.buildozer.config
path = config.getdefault('app', '{}_dir'.format(key), None)
if path is not None:
path = join(self.buildozer.root_dir, path)
url = None
branch = None
else:
branch = config.getdefault('app', '{}_branch'.format(key), branch)
default_url = url_format.format(owner=owner, repo=repo, branch=branch)
url = config.getdefault('app', '{}_url'.format(key), default_url)
if branch != 'master':
url = "--branch {} {}".format(branch, url)
return path, url, branch
def install_or_update_repo(self, repo, **kwargs):
"""Install or update a git repository into the platform directory.
This will clone the contents of a git repository to
`buildozer.platform_dir`. The location of this repo can be
specified via URL and branch name, or via a custom (local)
directory name.
:Parameters:
**kwargs:
Any valid arguments for :meth:`path_or_git_url`
:Returns:
fully qualified path to updated git repo
"""
cmd = self.buildozer.cmd
install_dir = join(self.buildozer.platform_dir, repo)
custom_dir, clone_url, clone_branch = self.path_or_git_url(repo, **kwargs)
if not self.buildozer.file_exists(install_dir):
if custom_dir:
cmd('mkdir -p "{}"'.format(install_dir))
cmd('cp -a "{}"/* "{}"/'.format(custom_dir, install_dir))
else:
cmd('git clone {}'.format(clone_url),
cwd=self.buildozer.platform_dir)
elif self.platform_update:
if custom_dir:
cmd('cp -a "{}"/* "{}"/'.format(custom_dir, install_dir))
else:
cmd('git clean -dxf', cwd=install_dir)
cmd('git pull origin {}'.format(clone_branch), cwd=install_dir)
return install_dir

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
# coding=utf-8
'''
Android target, based on python-for-android project
'''
import sys
from buildozer import USE_COLOR
from buildozer.targets.android import TargetAndroid
from os.path import join, expanduser, realpath
class TargetAndroidNew(TargetAndroid):
targetname = 'android'
p4a_branch = "stable"
p4a_directory = "python-for-android-master"
p4a_apk_cmd = "apk --debug --bootstrap="
extra_p4a_args = ''
def __init__(self, *args, **kwargs):
super(TargetAndroidNew, self).__init__(*args, **kwargs)
self._build_dir = join(self.buildozer.platform_dir, 'build')
executable = sys.executable or 'python'
self._p4a_cmd = '{} -m pythonforandroid.toolchain '.format(executable)
self._p4a_bootstrap = self.buildozer.config.getdefault(
'app', 'p4a.bootstrap', 'sdl2')
self.p4a_apk_cmd += self._p4a_bootstrap
color = 'always' if USE_COLOR else 'never'
self.extra_p4a_args = ' --color={} --storage-dir={}'.format(
color, self._build_dir)
hook = self.buildozer.config.getdefault("app", "p4a.hook", None)
if hook is not None:
self.extra_p4a_args += ' --hook={}'.format(realpath(hook))
def _p4a(self, cmd, **kwargs):
if not hasattr(self, "pa_dir"):
self.pa_dir = join(self.buildozer.platform_dir, self.p4a_directory)
kwargs.setdefault('cwd', self.pa_dir)
return self.buildozer.cmd(self._p4a_cmd + cmd + self.extra_p4a_args, **kwargs)
def get_available_packages(self):
return True
def compile_platform(self):
app_requirements = self.buildozer.config.getlist(
'app', 'requirements', '')
onlyname = lambda x: x.split('==')[0]
dist_name = self.buildozer.config.get('app', 'package.name')
local_recipes = self.get_local_recipes_dir()
requirements = ','.join(app_requirements)
options = []
source_dirs = {
'P4A_{}_DIR'.format(name[20:]): realpath(expanduser(value))
for name, value in self.buildozer.config.items('app')
if name.startswith('requirements.source.')
}
if source_dirs:
self.buildozer.environ.update(source_dirs)
self.buildozer.info('Using custom source dirs:\n {}'.format(
'\n '.join(['{} = {}'.format(k, v)
for k, v in source_dirs.items()])))
if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True):
options.append("--copy-libs")
# support for recipes in a local directory within the project
if local_recipes:
options.append('--local-recipes')
options.append(local_recipes)
available_modules = self._p4a(
"create --dist_name={} --bootstrap={} --requirements={} --arch {} {}".format(
dist_name, self._p4a_bootstrap, requirements,
self.buildozer.config.getdefault('app', 'android.arch', "armeabi-v7a"), " ".join(options)),
get_stdout=True)[0]
def get_dist_dir(self, dist_name):
return join(self._build_dir, 'dists', dist_name)
def get_local_recipes_dir(self):
local_recipes = self.buildozer.config.getdefault('app', 'p4a.local_recipes')
return realpath(expanduser(local_recipes)) if local_recipes else None
def execute_build_package(self, build_cmd):
# wrapper from previous old_toolchain to new toolchain
dist_name = self.buildozer.config.get('app', 'package.name')
local_recipes = self.get_local_recipes_dir()
cmd = [self.p4a_apk_cmd, "--dist_name", dist_name]
for args in build_cmd:
option, values = args[0], args[1:]
if option == "debug":
continue
elif option == "release":
cmd.append("--release")
cmd.append("--sign")
continue
if option == "--window":
cmd.append("--window")
elif option == "--sdk":
cmd.append("--android_api")
cmd.extend(values)
cmd.append("--sdk")
cmd.extend(values)
else:
cmd.extend(args)
# support for presplash background color
presplash_color = self.buildozer.config.getdefault('app', 'android.presplash_color', None)
if presplash_color:
cmd.append('--presplash-color')
cmd.append("'{}'".format(presplash_color))
# support for services
services = self.buildozer.config.getlist('app', 'services', [])
for service in services:
cmd.append("--service")
cmd.append(service)
# support for copy-libs
if self.buildozer.config.getbooldefault('app', 'android.copy_libs', True):
cmd.append("--copy-libs")
# support for recipes in a local directory within the project
if local_recipes:
cmd.append('--local-recipes')
cmd.append(local_recipes)
# support for blacklist/whitelist filename
whitelist_src = self.buildozer.config.getdefault('app', 'android.whitelist_src', None)
blacklist_src = self.buildozer.config.getdefault('app', 'android.blacklist_src', None)
if whitelist_src:
cmd.append('--whitelist')
cmd.append(realpath(whitelist_src))
if blacklist_src:
cmd.append('--blacklist')
cmd.append(realpath(blacklist_src))
# support for aars
aars = self.buildozer.config.getlist('app', 'android.add_aars', [])
for aar in aars:
cmd.append('--add-aar')
cmd.append(realpath(aar))
# support for gradle dependencies
gradle_dependencies = self.buildozer.config.getlist('app', 'android.gradle_dependencies', [])
for gradle_dependency in gradle_dependencies:
cmd.append('--depend')
cmd.append(gradle_dependency)
cmd.append('--arch')
cmd.append(self.buildozer.config.getdefault('app', 'android.arch', "armeabi-v7a"))
cmd = " ".join(cmd)
self._p4a(cmd)
def cmd_run(self, *args):
entrypoint = self.buildozer.config.getdefault(
'app', 'android.entrypoint')
if not entrypoint:
self.buildozer.config.set('app', 'android.entrypoint', 'org.kivy.android.PythonActivity')
return super(TargetAndroidNew, self).cmd_run(*args)
def cmd_p4a(self, *args):
'''
Run p4a commands. Args must come after --, or
use --alias to make an alias
'''
self.check_requirements()
self.install_platform()
args = args[0]
if args and args[0] == '--alias':
print('To set up p4a in this shell session, execute:')
print(' alias p4a=$(buildozer {} p4a --alias 2>&1 >/dev/null)'
.format(self.targetname))
sys.stderr.write('PYTHONPATH={} {}\n'.format(self.pa_dir, self._p4a_cmd))
else:
self._p4a(' '.join(args) if args else '')
def cmd_clean(self, *args):
'''
Clean the build and distribution
'''
self._p4a("clean_builds")
self._p4a("clean_dists")
def get_target(buildozer):
buildozer.targetname = "android"
return TargetAndroidNew(buildozer)

View file

@ -3,13 +3,15 @@ iOS target, based on kivy-ios project
''' '''
import sys import sys
if sys.platform != 'darwin':
raise NotImplementedError('Windows platform not yet working for Android')
import plistlib import plistlib
from buildozer import BuildozerCommandException from buildozer import BuildozerCommandException
from buildozer.target import Target, no_config from buildozer.target import Target, no_config
from os.path import join, basename, expanduser, realpath from os.path import join, basename, expanduser, realpath
from getpass import getpass from getpass import getpass
PHP_TEMPLATE = ''' PHP_TEMPLATE = '''
<?php <?php
// credits goes to http://jeffreysambells.com/2010/06/22/ios-wireless-app-distribution // credits goes to http://jeffreysambells.com/2010/06/22/ios-wireless-app-distribution
@ -56,22 +58,10 @@ li { padding: 1em; }
</html> </html>
''' '''
class TargetIos(Target): class TargetIos(Target):
targetname = "ios" targetname = "ios"
def __init__(self, buildozer):
super().__init__(buildozer)
executable = sys.executable or 'python'
self._toolchain_cmd = f"{executable} toolchain.py "
self._xcodebuild_cmd = "xcodebuild "
# set via install_platform()
self.ios_dir = None
self.ios_deploy_dir = None
def check_requirements(self): def check_requirements(self):
if sys.platform != "darwin":
raise NotImplementedError("Only macOS is supported for iOS target")
checkbin = self.buildozer.checkbin checkbin = self.buildozer.checkbin
cmd = self.buildozer.cmd cmd = self.buildozer.cmd
@ -101,36 +91,35 @@ class TargetIos(Target):
self.buildozer.debug(' -> found {0}'.format(xcode)) self.buildozer.debug(' -> found {0}'.format(xcode))
def install_platform(self): def install_platform(self):
""" cmd = self.buildozer.cmd
Clones `kivy/kivy-ios` and `phonegap/ios-deploy` then sets `ios_dir` self.ios_dir = ios_dir = join(self.buildozer.platform_dir, 'kivy-ios')
and `ios_deploy_dir` accordingly. custom_kivy_ios = self.buildozer.config.getdefault('app', 'ios.kivy_ios_dir')
""" if custom_kivy_ios:
self.ios_dir = self.install_or_update_repo('kivy-ios', platform='ios') custom_kivy_ios = join(self.buildozer.root_dir, custom_kivy_ios)
self.ios_deploy_dir = self.install_or_update_repo('ios-deploy', if not self.buildozer.file_exists(ios_dir):
platform='ios', if custom_kivy_ios:
branch='1.7.0', cmd('mkdir -p "{}"'.format(ios_dir))
owner='phonegap') cmd('cp -a "{}"/* "{}"/'.format(custom_kivy_ios, ios_dir))
else:
cmd('git clone https://github.com/kivy/kivy-ios',
cwd=self.buildozer.platform_dir)
elif self.platform_update:
if custom_kivy_ios:
cmd('cp -a "{}"/* "{}"/'.format(custom_kivy_ios, ios_dir))
else:
cmd('git clean -dxf', cwd=ios_dir)
cmd('git pull origin master', cwd=ios_dir)
def toolchain(self, cmd, **kwargs): self.ios_deploy_dir = ios_deploy_dir = join(self.buildozer.platform_dir,
kwargs.setdefault('cwd', self.ios_dir) 'ios-deploy')
return self.buildozer.cmd(self._toolchain_cmd + cmd, **kwargs) if not self.buildozer.file_exists(ios_deploy_dir):
cmd('git clone --branch 1.7.0 https://github.com/phonegap/ios-deploy',
def xcodebuild(self, *args, **kwargs): cwd=self.buildozer.platform_dir)
return self.buildozer.cmd(self._xcodebuild_cmd + ' '.join(arg for arg in args if arg is not None), **kwargs)
@property
def code_signing_allowed(self):
allowed = self.buildozer.config.getboolean("app", "ios.codesign.allowed")
allowed = "YES" if allowed else "NO"
return f"CODE_SIGNING_ALLOWED={allowed}"
@property
def code_signing_development_team(self):
team = self.buildozer.config.getdefault("app", f"ios.codesign.development_team.{self.build_mode}", None)
return f"DEVELOPMENT_TEAM={team}" if team else None
def get_available_packages(self): def get_available_packages(self):
available_modules = self.toolchain("recipes --compact", get_stdout=True)[0] available_modules = self.buildozer.cmd(
'./toolchain.py recipes --compact',
cwd=self.ios_dir, get_stdout=True)[0]
return available_modules.splitlines()[0].split() return available_modules.splitlines()[0].split()
def compile_platform(self): def compile_platform(self):
@ -142,7 +131,7 @@ class TargetIos(Target):
# we need to extract the requirements that kivy-ios knows about # we need to extract the requirements that kivy-ios knows about
available_modules = self.get_available_packages() available_modules = self.get_available_packages()
onlyname = lambda x: x.split('==')[0] # noqa: E731 do not assign a lambda expression, use a def onlyname = lambda x: x.split('==')[0]
ios_requirements = [x for x in app_requirements if onlyname(x) in ios_requirements = [x for x in app_requirements if onlyname(x) in
available_modules] available_modules]
@ -167,10 +156,11 @@ class TargetIos(Target):
return return
modules_str = ' '.join(ios_requirements) modules_str = ' '.join(ios_requirements)
self.toolchain(f"build {modules_str}") self.buildozer.cmd('./toolchain.py build {}'.format(modules_str),
cwd=self.ios_dir)
if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'): if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'):
self.xcodebuild(cwd=self.ios_deploy_dir) self.buildozer.cmd('make ios-deploy', cwd=self.ios_deploy_dir)
self.buildozer.state['ios.requirements'] = ios_requirements self.buildozer.state['ios.requirements'] = ios_requirements
self.buildozer.state.sync() self.buildozer.state.sync()
@ -190,25 +180,22 @@ class TargetIos(Target):
app_name = self.buildozer.namify(self.buildozer.config.get('app', app_name = self.buildozer.namify(self.buildozer.config.get('app',
'package.name')) 'package.name'))
ios_frameworks = self.buildozer.config.getlist('app', 'ios.frameworks', '')
frameworks_cmd = ''
for framework in ios_frameworks:
frameworks_cmd += '--add-framework={} '.format(framework)
self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower())) self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower()))
if not self.buildozer.file_exists(self.app_project_dir): if not self.buildozer.file_exists(self.app_project_dir):
cmd = f"create {frameworks_cmd}{app_name} {self.buildozer.app_dir}" self.buildozer.cmd('./toolchain.py create {0} {1}'.format(
app_name, self.buildozer.app_dir),
cwd=self.ios_dir)
else: else:
cmd = f"update {frameworks_cmd}{app_name}-ios" self.buildozer.cmd('./toolchain.py update {0}-ios'.format(
self.toolchain(cmd) app_name),
cwd=self.ios_dir)
# fix the plist # fix the plist
plist_fn = '{}-Info.plist'.format(app_name.lower()) plist_fn = '{}-Info.plist'.format(app_name.lower())
plist_rfn = join(self.app_project_dir, plist_fn) plist_rfn = join(self.app_project_dir, plist_fn)
version = self.buildozer.get_version() version = self.buildozer.get_version()
self.buildozer.info('Update Plist {}'.format(plist_fn)) self.buildozer.info('Update Plist {}'.format(plist_fn))
with open(plist_rfn, 'rb') as f: plist = plistlib.readPlist(plist_rfn)
plist = plistlib.load(f)
plist['CFBundleIdentifier'] = self._get_package() plist['CFBundleIdentifier'] = self._get_package()
plist['CFBundleShortVersionString'] = version plist['CFBundleShortVersionString'] = version
plist['CFBundleVersion'] = '{}.{}'.format(version, plist['CFBundleVersion'] = '{}.{}'.format(version,
@ -217,37 +204,12 @@ class TargetIos(Target):
# add icons # add icons
self._create_icons() self._create_icons()
# Generate OTA distribution manifest if `app_url`, `display_image_url` and `full_size_image_url` are defined.
app_url = self.buildozer.config.getdefault("app", "ios.manifest.app_url", None)
display_image_url = self.buildozer.config.getdefault("app", "ios.manifest.display_image_url", None)
full_size_image_url = self.buildozer.config.getdefault("app", "ios.manifest.full_size_image_url", None)
if any((app_url, display_image_url, full_size_image_url)):
if not all((app_url, display_image_url, full_size_image_url)):
self.buildozer.error("Options ios.manifest.app_url, ios.manifest.display_image_url"
" and ios.manifest.full_size_image_url should be defined all together")
return
plist['manifest'] = {
'appURL': app_url,
'displayImageURL': display_image_url,
'fullSizeImageURL': full_size_image_url,
}
# ok, write the modified plist. # ok, write the modified plist.
with open(plist_rfn, 'wb') as f: plistlib.writePlist(plist, plist_rfn)
plistlib.dump(plist, f)
mode = self.build_mode.capitalize() mode = 'Debug' if self.build_mode == 'debug' else 'Release'
self.xcodebuild( self.buildozer.cmd('xcodebuild -configuration {} ENABLE_BITCODE=NO clean build'.format(mode),
f'-configuration {mode}', cwd=self.app_project_dir)
'-allowProvisioningUpdates',
'ENABLE_BITCODE=NO',
self.code_signing_allowed,
self.code_signing_development_team,
'clean build',
cwd=self.app_project_dir)
ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format( ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format(
app_lower=app_name.lower(), mode=mode) app_lower=app_name.lower(), mode=mode)
self.buildozer.state['ios:latestappdir'] = ios_app_dir self.buildozer.state['ios:latestappdir'] = ios_app_dir
@ -272,24 +234,27 @@ class TargetIos(Target):
self.buildozer.rmdir(intermediate_dir) self.buildozer.rmdir(intermediate_dir)
self.buildozer.info('Creating archive...') self.buildozer.info('Creating archive...')
self.xcodebuild( self.buildozer.cmd((
'-alltargets', '/usr/bin/xcodebuild'
f'-configuration {mode}', ' -alltargets'
f'-scheme {app_name.lower()}', ' -configuration {mode}'
f'-archivePath "{xcarchive}"', ' -scheme {scheme}'
'archive', ' -archivePath "{xcarchive}"'
'ENABLE_BITCODE=NO', ' archive'
self.code_signing_development_team, ' ENABLE_BITCODE=NO'
).format(mode=mode, xcarchive=xcarchive, scheme=app_name.lower()),
cwd=build_dir) cwd=build_dir)
self.buildozer.info('Creating IPA...') self.buildozer.info('Creating IPA...')
self.xcodebuild( self.buildozer.cmd((
'-exportArchive', '/usr/bin/xcodebuild'
f'-archivePath "{xcarchive}"', ' -exportArchive'
f'-exportOptionsPlist "{plist_rfn}"', ' -exportFormat IPA'
f'-exportPath "{ipa_tmp}"', ' -archivePath "{xcarchive}"'
f'CODE_SIGN_IDENTITY={ioscodesign}', ' -exportPath "{ipa}"'
'ENABLE_BITCODE=NO', ' CODE_SIGN_IDENTITY={ioscodesign}'
' ENABLE_BITCODE=NO'
).format(xcarchive=xcarchive, ipa=ipa_tmp, ioscodesign=ioscodesign),
cwd=build_dir) cwd=build_dir)
self.buildozer.info('Moving IPA to bin...') self.buildozer.info('Moving IPA to bin...')
@ -301,12 +266,14 @@ class TargetIos(Target):
self.buildozer.state['ios:latestipa'] = ipa self.buildozer.state['ios:latestipa'] = ipa
self.buildozer.state['ios:latestmode'] = self.build_mode self.buildozer.state['ios:latestmode'] = self.build_mode
self._create_index()
def cmd_deploy(self, *args): def cmd_deploy(self, *args):
super().cmd_deploy(*args) super(TargetIos, self).cmd_deploy(*args)
self._run_ios_deploy(lldb=False) self._run_ios_deploy(lldb=False)
def cmd_run(self, *args): def cmd_run(self, *args):
super().cmd_run(*args) super(TargetIos, self).cmd_run(*args)
self._run_ios_deploy(lldb=True) self._run_ios_deploy(lldb=True)
def cmd_xcode(self, *args): def cmd_xcode(self, *args):
@ -349,13 +316,17 @@ class TargetIos(Target):
self.buildozer.error('Icon {} does not exists'.format(icon_fn)) self.buildozer.error('Icon {} does not exists'.format(icon_fn))
return return
self.toolchain(f"icon {self.app_project_dir} {icon_fn}") self.buildozer.cmd('./toolchain.py icon {} {}'.format(
self.app_project_dir, icon_fn),
cwd=self.ios_dir)
def _create_index(self):
# TODO
pass
def check_configuration_tokens(self): def check_configuration_tokens(self):
errors = [] errors = []
config = self.buildozer.config config = self.buildozer.config
if not config.getboolean('app', 'ios.codesign.allowed'):
return
identity_debug = config.getdefault('app', 'ios.codesign.debug', '') identity_debug = config.getdefault('app', 'ios.codesign.debug', '')
identity_release = config.getdefault('app', 'ios.codesign.release', identity_release = config.getdefault('app', 'ios.codesign.release',
identity_debug) identity_debug)
@ -374,7 +345,8 @@ class TargetIos(Target):
elif identity_release not in available_identities: elif identity_release not in available_identities:
errors.append('[app] identity "{}" not found. ' errors.append('[app] identity "{}" not found. '
'Check with list_identities'.format(identity_release)) 'Check with list_identities'.format(identity_release))
super().check_configuration_tokens(errors)
super(TargetIos, self).check_configuration_tokens(errors)
@no_config @no_config
def cmd_list_identities(self, *args): def cmd_list_identities(self, *args):
@ -424,10 +396,10 @@ class TargetIos(Target):
if not error: if not error:
correct = True correct = True
break break
self.buildozer.error('Invalid keychain password') self.error('Invalid keychain password')
if not correct: if not correct:
self.buildozer.error('Unable to unlock the keychain, exiting.') self.error('Unable to unlock the keychain, exiting.')
raise BuildozerCommandException() raise BuildozerCommandException()
# maybe user want to save it for further reuse? # maybe user want to save it for further reuse?
@ -438,7 +410,7 @@ class TargetIos(Target):
save = None save = None
while save is None: while save is None:
q = input('Do you want to save the password (Y/n): ') q = raw_input('Do you want to save the password (Y/n): ')
if q in ('', 'Y'): if q in ('', 'Y'):
save = True save = True
elif q == 'n': elif q == 'n':
@ -448,8 +420,7 @@ class TargetIos(Target):
if save: if save:
with open(password_file, 'wb') as fd: with open(password_file, 'wb') as fd:
fd.write(password.encode()) fd.write(password)
def get_target(buildozer): def get_target(buildozer):
return TargetIos(buildozer) return TargetIos(buildozer)

View file

@ -6,10 +6,26 @@ import sys
if sys.platform != 'darwin': if sys.platform != 'darwin':
raise NotImplementedError('This will only work on osx') raise NotImplementedError('This will only work on osx')
#Global variables
#Global imports
import traceback
import os
import io
from pipes import quote
from sys import platform, executable
from buildozer import BuildozerException
from buildozer import IS_PY3
from buildozer.target import Target from buildozer.target import Target
from os.path import exists, join, abspath, dirname from os import environ
from os.path import (exists, join, realpath, expanduser,
basename, relpath, abspath, dirname)
from shutil import copyfile
from glob import glob
from subprocess import check_call, check_output from subprocess import check_call, check_output
from buildozer.libs.version import parse
class TargetOSX(Target): class TargetOSX(Target):
targetname = "osx" targetname = "osx"
@ -17,9 +33,9 @@ class TargetOSX(Target):
def ensure_sdk(self): def ensure_sdk(self):
self.buildozer.info('Check if kivy-sdk-packager exists') self.buildozer.info('Check if kivy-sdk-packager exists')
if exists( if exists(
join(self.buildozer.platform_dir, 'kivy-sdk-packager-master')): join(self.buildozer.platform_dir, 'kivy-sdk-packager-master')):
self.buildozer.info( self.buildozer.info(
'kivy-sdk-packager found at ' 'kivy-sdk-packager found at '\
'{}'.format(self.buildozer.platform_dir)) '{}'.format(self.buildozer.platform_dir))
return return
@ -44,19 +60,12 @@ class TargetOSX(Target):
else: else:
if not exists(join(cwd, 'Kivy{}.dmg'.format(py_branch))): if not exists(join(cwd, 'Kivy{}.dmg'.format(py_branch))):
self.buildozer.info('Downloading kivy...') self.buildozer.info('Downloading kivy...')
status_code = check_output( check_call(
('curl', '-L', '--write-out', '%{http_code}', '-o', 'Kivy{}.dmg'.format(py_branch), ('curl', '-L', '-o', 'Kivy{}.dmg'.format(py_branch),
'https://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg' 'http://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'\
.format(current_kivy_vers, current_kivy_vers, py_branch)), .format(current_kivy_vers, current_kivy_vers, py_branch)),
cwd=cwd) cwd=cwd)
if status_code == "404":
self.buildozer.error(
"Unable to download the Kivy App. Check osx.kivy_version in your buildozer.spec, and verify "
"Kivy servers are accessible. https://kivy.org/downloads/")
check_call(("rm", "Kivy{}.dmg".format(py_branch)), cwd=cwd)
sys.exit(1)
self.buildozer.info('Extracting and installing Kivy...') self.buildozer.info('Extracting and installing Kivy...')
check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch))) check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch)))
check_call(('cp', '-a', '/Volumes/Kivy/Kivy.app', './Kivy.app'), cwd=cwd) check_call(('cp', '-a', '/Volumes/Kivy/Kivy.app', './Kivy.app'), cwd=cwd)
@ -76,6 +85,8 @@ class TargetOSX(Target):
else: else:
self.download_kivy(kivy_app_dir, py_branch) self.download_kivy(kivy_app_dir, py_branch)
return
def check_requirements(self): def check_requirements(self):
self.ensure_sdk() self.ensure_sdk()
self.ensure_kivyapp() self.ensure_kivyapp()
@ -88,40 +99,43 @@ class TargetOSX(Target):
len(errors))) len(errors)))
for error in errors: for error in errors:
print(error) print(error)
sys.exit(1) exit(1)
# check # check
def build_package(self): def build_package(self):
self.buildozer.info('Building package') self.buildozer.info('Building package')
kivy_app_dir = join(
self.buildozer.platform_dir,
'kivy-sdk-packager-master', 'osx', 'Kivy.app')
bc = self.buildozer.config bc = self.buildozer.config
bcg = bc.get bcg = bc.get
bcgl = bc.getlist
package_name = bcg('app', 'package.name') package_name = bcg('app', 'package.name')
domain = bcg('app', 'package.domain') domain = bcg('app', 'package.domain')
title = bcg('app', 'title') title = bcg('app', 'title')
app_deps = open('requirements.txt').read() app_deps = bcgl('app', 'requirements', '')
garden_deps = bcgl('app', 'garden_requirements', '')
icon = bc.getdefault('app', 'icon.filename', '') icon = bc.getdefault('app', 'icon.filename', '')
version = self.buildozer.get_version() version = self.buildozer.get_version()
author = bc.getdefault('app', 'author', '') author = bc.getdefault('app', 'author', '')
#print(title, package_name, domain, version,
# source_dir, app_deps, garden_deps, icon, author)
#return
self.buildozer.info('Create {}.app'.format(package_name)) self.buildozer.info('Create {}.app'.format(package_name))
cwd = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx') cwd = join(self.buildozer.platform_dir,'kivy-sdk-packager-master', 'osx')
# remove kivy from app_deps # remove kivy from app_deps
app_deps = [a for a in app_deps.split('\n') if not a.startswith('#') and a not in ['kivy', '']] app_deps = ','.join(
[word for word in app_deps if 'kivy' not in word])
cmd = [
'Kivy.app/Contents/Resources/script',
'-m', 'pip', 'install',
]
cmd.extend(app_deps)
check_output(cmd, cwd=cwd)
cmd = [ cmd = [
'python', 'package_app.py', self.buildozer.app_dir, 'python', 'package_app.py', self.buildozer.app_dir,
'--appname={}'.format(package_name), '--appname={}'.format(package_name),
'--bundlename={}'.format(title), '--bundlename={}'.format(title),
'--bundleid={}'.format(domain), '--bundleid={}'.format(domain),
'--bundleversion={}'.format(version), '--bundleversion={}'.format(version),
#'--deps={}'.format(app_deps),
'--displayname={}'.format(title) '--displayname={}'.format(title)
] ]
if icon: if icon:
@ -130,7 +144,6 @@ class TargetOSX(Target):
cmd.append('--author={}'.format(author)) cmd.append('--author={}'.format(author))
check_output(cmd, cwd=cwd) check_output(cmd, cwd=cwd)
self.buildozer.info('{}.app created.'.format(package_name)) self.buildozer.info('{}.app created.'.format(package_name))
self.buildozer.info('Creating {}.dmg'.format(package_name)) self.buildozer.info('Creating {}.dmg'.format(package_name))
check_output( check_output(
@ -139,10 +152,10 @@ class TargetOSX(Target):
self.buildozer.info('{}.dmg created'.format(package_name)) self.buildozer.info('{}.dmg created'.format(package_name))
self.buildozer.info('moving {}.dmg to bin.'.format(package_name)) self.buildozer.info('moving {}.dmg to bin.'.format(package_name))
binpath = join( binpath = join(
self.buildozer.user_build_dir or self.buildozer.build_dir or
dirname(abspath(self.buildozer.specfilename)), 'bin') dirname(abspath(self.buildozer.specfilename)), 'bin')
check_output( check_output(
('cp', '-a', package_name + '.dmg', binpath), ('cp', '-a', package_name+'.dmg', binpath),
cwd=cwd) cwd=cwd)
self.buildozer.info('All Done!') self.buildozer.info('All Done!')
@ -156,7 +169,7 @@ class TargetOSX(Target):
# #
self.buildozer.environ.update({ self.buildozer.environ.update({
'PACKAGES_PATH': self.buildozer.global_packages_dir, 'PACKAGES_PATH': self.buildozer.global_packages_dir,
}) })
def get_custom_commands(self): def get_custom_commands(self):
result = [] result = []
@ -175,7 +188,7 @@ class TargetOSX(Target):
if not args: if not args:
self.buildozer.error('Missing target command') self.buildozer.error('Missing target command')
self.buildozer.usage() self.buildozer.usage()
sys.exit(1) exit(1)
result = [] result = []
last_command = [] last_command = []
@ -189,7 +202,7 @@ class TargetOSX(Target):
if not last_command: if not last_command:
self.buildozer.error('Argument passed without a command') self.buildozer.error('Argument passed without a command')
self.buildozer.usage() self.buildozer.usage()
sys.exit(1) exit(1)
last_command.append(arg) last_command.append(arg)
if last_command: if last_command:
result.append(last_command) result.append(last_command)
@ -200,7 +213,7 @@ class TargetOSX(Target):
command, args = item[0], item[1:] command, args = item[0], item[1:]
if not hasattr(self, 'cmd_{0}'.format(command)): if not hasattr(self, 'cmd_{0}'.format(command)):
self.buildozer.error('Unknown command {0}'.format(command)) self.buildozer.error('Unknown command {0}'.format(command))
sys.exit(1) exit(1)
func = getattr(self, 'cmd_{0}'.format(command)) func = getattr(self, 'cmd_{0}'.format(command))

View file

@ -25,7 +25,7 @@ torrent:
mktorrent \ mktorrent \
-a ${TORRENT_ANNOUNCE} \ -a ${TORRENT_ANNOUNCE} \
-o output-kivy-buildozer-vm/kivy-buildozer-vm.torrent \ -o output-kivy-buildozer-vm/kivy-buildozer-vm.torrent \
-w https://txzone.net/files/torrents/${PACKAGE_FILENAME} \ -w http://txzone.net/files/torrents/${PACKAGE_FILENAME} \
-v output-kivy-buildozer-vm/${PACKAGE_FILENAME} -v output-kivy-buildozer-vm/${PACKAGE_FILENAME}
upload: upload:

View file

@ -25,7 +25,7 @@
download the Android SDK/NDK (automatically done), and during the first download the Android SDK/NDK (automatically done), and during the first
compilation. compilation.
<br/> <br/>
It is preferable to add a <a href="#sharefolder"> share a folder It is preferable to add a <a href="#sharefolder">share a folder
</a> between your host and the VM, then build from there.<br/> </a> between your host and the VM, then build from there.<br/>
By the time we shipped the VM and you using it, you may need to By the time we shipped the VM and you using it, you may need to

View file

@ -3,7 +3,7 @@
# an error when using the android sdk: # an error when using the android sdk:
# "Can't read cryptographic policy directory: unlimited" # "Can't read cryptographic policy directory: unlimited"
wget https://bootstrap.pypa.io/get-pip.py wget http://bootstrap.pypa.io/get-pip.py
python get-pip.py python get-pip.py
rm get-pip.py rm get-pip.py
@ -11,3 +11,7 @@ apt-get -y install lib32stdc++6 lib32z1 lib32ncurses5
apt-get -y install build-essential apt-get -y install build-essential
apt-get -y install git openjdk-8-jdk --no-install-recommends zlib1g-dev apt-get -y install git openjdk-8-jdk --no-install-recommends zlib1g-dev
pip install cython buildozer python-for-android pip install cython buildozer python-for-android
# latest sh is too slow, use a previous working version
# CF https://github.com/amoffat/sh/issues/378
pip install sh\<1.12.5

View file

@ -9,7 +9,7 @@ BUILDDIR = build
# User-friendly check for sphinx-build # User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://www.sphinx-doc.org/) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif endif
# Internal variables. # Internal variables.

View file

@ -56,7 +56,7 @@ if errorlevel 9009 (
echo.may add the Sphinx directory to PATH. echo.may add the Sphinx directory to PATH.
echo. echo.
echo.If you don't have Sphinx installed, grab it from echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/ echo.http://sphinx-doc.org/
exit /b 1 exit /b 1
) )

View file

@ -15,10 +15,10 @@ limitation.
To test your own recipe via Buildozer, you need to: To test your own recipe via Buildozer, you need to:
#. Fork `Python for Android <https://github.com/kivy/python-for-android>`_, and #. Fork `Python for Android <http://github.com/kivy/python-for-android>`_, and
clone your own version (this will allow easy contribution later):: clone your own version (this will allow easy contribution later)::
git clone https://github.com/YOURNAME/python-for-android git clone http://github.com/YOURNAME/python-for-android
#. Change your `buildozer.spec` to reference your version:: #. Change your `buildozer.spec` to reference your version::
@ -44,6 +44,6 @@ include it in the python-for-android project, by issuing a Pull Request:
git push origin master git push origin master
#. Go to `https://github.com/YOURNAME/python-for-android`, and you should see #. Go to `http://github.com/YOURNAME/python-for-android`, and you should see
your new branch and a button "Pull Request" on it. Use it, write a your new branch and a button "Pull Request" on it. Use it, write a
description about what you did, and Send! description about what you did, and Send!

View file

@ -1,132 +1,66 @@
Installation Installation
============ ============
Buildozer itself doesn't depend on any library Python >= 3.3. Buildozer itself doesn't depend on any library, and works on Python 2.7 and >=
Depending the platform you want to target, you might need more tools installed. 3.3. Depending the platform you want to target, you might need more tools
Buildozer tries to give you hints or tries to install few things for installed. Buildozer tries to give you hints or tries to install few things for
you, but it doesn't cover every situation. you, but it doesn't cover every situation.
First, install the buildozer project with:: First, install the buildozer project with::
pip3 install --user --upgrade buildozer pip install --upgrade buildozer
Targeting Android Targeting Android
----------------- -----------------
Android on Ubuntu 20.04 (64bit) If you target Android, you must install at least Cython, few build libs, and a
Java SDK. Some binaries of the Android SDK are still in 32 bits, so you need
few 32bits libraries available:
Android on Ubuntu 16.04 (64bit)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(expected to work as well in later version, but only regularly tested in the latest LTS) ::
sudo pip install --upgrade cython==0.21
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install build-essential ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-8-jdk unzip zlib1g-dev zlib1g:i386
Android on Ubuntu 15.10 (64bit)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: ::
sudo apt update sudo pip install --upgrade cython==0.21
sudo apt install -y git zip unzip openjdk-13-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev sudo dpkg --add-architecture i386
pip3 install --user --upgrade Cython==0.29.19 virtualenv # the --user should be removed if you do this in a venv sudo apt-get update
sudo apt-get install build-essential ccache git libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 python2.7 python2.7-dev openjdk-7-jdk unzip zlib1g-dev zlib1g:i386
# add the following line at the end of your ~/.bashrc file Android on Ubuntu 14.10 (64bit)
export PATH=$PATH:~/.local/bin/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Android on Windows 10
~~~~~~~~~~~~~~~~~~~~~
To use buildozer in Windows 10 you need first to enable Windows Subsystem for Linux (WSL) and install a Linux distribution: https://docs.microsoft.com/en-us/windows/wsl/install-win10.
These instructions were tested with WSL 1 and Ubuntu 18.04 LTS.
After installing WSL and Ubuntu in your Windows 10 machine, open Ubuntu and do this:
1) Run the commands listed on the previous section (Android in Ubuntu 18.04 (64-bit).
2) Run the following commands:
:: ::
# Use here the python version you need sudo pip install --upgrade cython==0.21
sudo apt install -y python3.7-venv sudo dpkg --add-architecture i386
# Create a folder for buildozer. For example: C:\buildozer sudo apt-get update
mkdir /mnt/c/buildozer sudo apt-get install build-essential ccache git lib32stdc++6 lib32z1 lib32z1-dev python2.7 python2.7-dev openjdk-7-jdk unzip zlib1g-dev zlib1g:i386
cd /mnt/c/buildozer
python3.7 -m venv venv-buildozer
source venv/bin/activate
python -m pip install --upgrade pip
python -m pip install --upgrade wheel
python -m pip install --upgrade cython
python -m pip install --upgrade virtualenv
python -m pip install --upgrade buildozer
# Restart your WSL terminal to enable the path change
Windows Subsystem for Linux does not have direct access to USB. Due to this, you need to install the Windows version of ADB (Android Debug Bridge): Android on Ubuntu 13.10 (64bit)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Go to https://developer.android.com/studio/releases/platform-tools and click on "Download SDK Platform-Tools for Windows".
- Unzip the downloaded file to a new folder. For example, "C:\\platform-tools".
Before Using Buildozer
~~~~~~~~~~~~~~~~~~~~~~
If you wish, clone your code to a new folder, where the build process will run.
You don't need to create a virtualenv for your code requirements. But just add these requirements to a configuration file called buildozer.spec as you will see in the following sections.
Before running buildozer in your code folder, remember to go into the buildozer folder and activate the buildozer virtualenv.
Android on macOS
~~~~~~~~~~~~~~~~
:: ::
brew install openssl sudo pip install --upgrade cython==0.21
sudo ln -sfn /usr/local/opt/openssl /usr/local/ssl sudo dpkg --add-architecture i386
brew install pkg-config autoconf automake sudo apt-get update
python3 -m pip install --user --upgrade Cython==0.29.19 virtualenv # the --user should be removed if you do this in a venv sudo apt-get install build-essential ccache git lib32z1 lib32bz2-1.0 libncurses5:i386 libstdc++6:i386 python2.7 python2.7-dev openjdk-7-jdk unzip zlib1g-dev zlib1g:i386
# add the following line at the end of your `~/.bashrc` file Android on Ubuntu 12.04 (64bit)
export PATH=$PATH:~/Library/Python/3.7/bin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TroubleShooting
~~~~~~~~~~~~~~~
Buildozer stuck on "Installing/updating SDK platform tools if necessary"
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Press "y" then enter to continue, the license acceptance system is silently waiting for your input
Aidl not found, please install it.
""""""""""""""""""""""""""""""""""
Buildozer didn't install a necessary package
:: ::
~/.buildozer/android/platform/android-sdk/tools/bin/sdkmanager "build-tools;29.0.0" sudo pip install --upgrade cython==0.21
sudo apt-get install build-essential ccache git lib32z1 lib32bz2-1.0 libncurses5:i386 libstdc++6:i386 python2.7 python2.7-dev openjdk-7-jdk unzip zlib1g-dev zlib1g:i386
Then press "y" then enter to accept the license.
python-for-android related errors
"""""""""""""""""""""""""""""""""
See the dedicated `p4a troubleshooting documentation
<https://python-for-android.readthedocs.io/en/latest/troubleshooting/>`_.
Targeting IOS
-------------
Install XCode and command line tools (through the AppStore)
Install homebrew (https://brew.sh)
::
brew install pkg-config sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer autoconf automake
Install pip and virtualenv
::
python3 -m pip install --user --upgrade pip virtualenv kivy-ios

View file

@ -60,40 +60,6 @@ To save the logcat output into a file named `my_log.txt` (the file will appear i
buildozer -v android debug deploy run logcat > my_log.txt buildozer -v android debug deploy run logcat > my_log.txt
To see your running application's print() messages and python's error messages, use:
::
buildozer -v android deploy run logcat | grep python
Run my application from Windows 10
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Plug your Android device on a USB port.
- Open Windows PowerShell, go into the folder where you installed the Windows version of ADB, and activate the ADB daemon. When the daemon is started you must see a number besides the word "device" meaning your device was correctly detected. In case of trouble, try another USB port or USB cable.
::
cd C:\platform-tools\
.\adb.exe devices
- Open the Linux distribution you installed on Windows Subsystem for Linux (WSL) and proceed with the deploy commands:
::
buildozer -v android deploy run
It is important to notice that Windows ADB and Buildozer installed ADB must be the same version. To check the versions, open PowerShell and type:
::
cd C:\platform-tools\
.\adb.exe version
wsl
cd ~/.buildozer/android/platform/android-sdk/platform-tools/
./adb version
Install on non-connected devices Install on non-connected devices
-------------------------------- --------------------------------

View file

@ -98,6 +98,16 @@ Section [app]
the compilation here. If you want to make it work, contribute to the the compilation here. If you want to make it work, contribute to the
Python-for-android project by creating a recipe. See :doc:`contribute`. Python-for-android project by creating a recipe. See :doc:`contribute`.
- `garden_requirements`: List, Garden packages to include.
Add here the list of Kivy's garden packages to include. For example::
garden_requirements = graph
Please note that if it doesn't work, it might be because of the garden
package itself. Refer to the author of the package if he already tested
it on your target platform, not us.
- `presplash.filename`: String, loading screen of your application. - `presplash.filename`: String, loading screen of your application.
Presplash is the image shown on the device during application loading. Presplash is the image shown on the device during application loading.

View file

@ -1,43 +0,0 @@
/usr/local/bin/buildozer
/usr/local/bin/buildozer-remote
/usr/local/bin/virtualenv
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/PKG-INFO
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/SOURCES.txt
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/dependency_links.txt
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/entry_points.txt
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/not-zip-safe
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/requires.txt
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/EGG-INFO/top_level.txt
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__init__.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__init__.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__main__.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/__main__.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/default.spec
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/jsonstore.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/jsonstore.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/__init__.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/__init__.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/_structures.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/_structures.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/version.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/libs/version.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/__init__.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/__init__.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/client.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/client.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/remote.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/scripts/remote.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/sitecustomize.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/sitecustomize.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/target.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/target.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/__init__.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/__init__.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android_new.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/android_new.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/ios.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/ios.pyc
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/osx.py
/usr/local/lib/python2.7/dist-packages/buildozer-0.35.dev0-py2.7.egg/buildozer/targets/osx.pyc

View file

@ -2,7 +2,6 @@
Buildozer Buildozer
''' '''
import sys
from setuptools import setup from setuptools import setup
from os.path import dirname, join from os.path import dirname, join
import codecs import codecs
@ -12,21 +11,6 @@ import io
here = os.path.abspath(os.path.dirname(__file__)) here = os.path.abspath(os.path.dirname(__file__))
CURRENT_PYTHON = sys.version_info[:2]
REQUIRED_PYTHON = (3, 6)
# This check and everything above must remain compatible with Python 2.7.
if CURRENT_PYTHON < REQUIRED_PYTHON:
sys.stderr.write("""
==========================
Unsupported Python version
==========================
This version of buildozer requires Python {}.{}, but you're trying to
install it on Python {}.{}.
""".format(*(REQUIRED_PYTHON + CURRENT_PYTHON)))
sys.exit(1)
def find_version(*file_paths): def find_version(*file_paths):
# Open in Latin-1 so that we avoid encoding errors. # Open in Latin-1 so that we avoid encoding errors.
@ -44,7 +28,7 @@ def find_version(*file_paths):
curdir = dirname(__file__) curdir = dirname(__file__)
with io.open(join(curdir, "README.md"), encoding="utf-8") as fd: with io.open(join(curdir, "README.rst"), encoding="utf-8") as fd:
readme = fd.read() readme = fd.read()
with io.open(join(curdir, "CHANGELOG.md"), encoding="utf-8") as fd: with io.open(join(curdir, "CHANGELOG.md"), encoding="utf-8") as fd:
changelog = fd.read() changelog = fd.read()
@ -54,25 +38,27 @@ setup(
version=find_version('buildozer', '__init__.py'), version=find_version('buildozer', '__init__.py'),
description='Generic Python packager for Android / iOS and Desktop', description='Generic Python packager for Android / iOS and Desktop',
long_description=readme + "\n\n" + changelog, long_description=readme + "\n\n" + changelog,
long_description_content_type='text/markdown',
author='Mathieu Virbel', author='Mathieu Virbel',
author_email='mat@kivy.org', author_email='mat@kivy.org',
url='https://github.com/kivy/buildozer', url='http://github.com/kivy/buildozer',
license='MIT', license='MIT',
packages=[ packages=[
'buildozer', 'buildozer.targets', 'buildozer.libs', 'buildozer.scripts' 'buildozer', 'buildozer.targets', 'buildozer.libs', 'buildozer.scripts'
], ],
package_data={'buildozer': ['default.spec']}, package_data={'buildozer': ['default.spec']},
include_package_data=True, include_package_data=True,
install_requires=['pexpect', 'virtualenv', 'sh'], install_requires=['pexpect', 'virtualenv'],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers',
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools', 'Topic :: Software Development :: Build Tools',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5'
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [

View file

View file

@ -1,26 +0,0 @@
import sys
import unittest
from buildozer import BuildozerCommandException
from buildozer.scripts import client
from unittest import mock
class TestClient(unittest.TestCase):
def test_run_command_called(self):
"""
Checks Buildozer.run_command() is being called with arguments from command line.
"""
with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
client.main()
assert m_run_command.call_args_list == [mock.call(sys.argv[1:])]
def test_exit_code(self):
"""
Makes sure the CLI exits with error code on BuildozerCommandException, refs #674.
"""
with mock.patch('buildozer.Buildozer.run_command') as m_run_command:
m_run_command.side_effect = BuildozerCommandException()
with self.assertRaises(SystemExit) as context:
client.main()
assert context.exception.code == 1

View file

@ -1,394 +0,0 @@
import os
import tempfile
from six import StringIO
from unittest import mock
import pytest
from buildozer.targets.android import TargetAndroid
from tests.targets.utils import (
init_buildozer,
patch_buildozer,
patch_buildozer_checkbin,
patch_buildozer_cmd,
patch_buildozer_file_exists,
)
def patch_buildozer_cmd_expect():
return patch_buildozer("cmd_expect")
def patch_buildozer_download():
return patch_buildozer("download")
def patch_buildozer_file_extract():
return patch_buildozer("file_extract")
def patch_os_isfile():
return mock.patch("os.path.isfile")
def patch_target_android(method):
return mock.patch(
"buildozer.targets.android.TargetAndroid.{method}".format(method=method)
)
def patch_platform(platform):
return mock.patch("buildozer.targets.android.platform", platform)
def init_target(temp_dir, options=None):
buildozer = init_buildozer(temp_dir, "android", options)
return TargetAndroid(buildozer)
def call_build_package(target_android):
"""
Call the build_package() method of the tested TargetAndroid instance,
patching the functions that would otherwise produce side-effects.
Return the mocked execute_build_package() method of the TargetAndroid
instance so that tests can easily check which command-line arguments
would be passed on to python-for-android's toolchain.
"""
buildozer = target_android.buildozer
expected_dist_dir = (
'{buildozer_dir}/android/platform/build-armeabi-v7a/dists/myapp__armeabi-v7a'.format(
buildozer_dir=buildozer.buildozer_dir)
)
with patch_target_android('_update_libraries_references') as m_update_libraries_references, \
patch_target_android('_generate_whitelist') as m_generate_whitelist, \
mock.patch('buildozer.targets.android.TargetAndroid.execute_build_package') as m_execute_build_package, \
mock.patch('buildozer.targets.android.copyfile') as m_copyfile, \
mock.patch('buildozer.targets.android.os.listdir') as m_listdir:
m_listdir.return_value = ['30.0.0-rc2']
target_android.build_package()
assert m_listdir.call_count == 1
assert m_update_libraries_references.call_args_list == [
mock.call(expected_dist_dir)
]
assert m_generate_whitelist.call_args_list == [mock.call(expected_dist_dir)]
assert m_copyfile.call_args_list == [
mock.call(
'{expected_dist_dir}/bin/MyApplication-0.1-debug.apk'.format(
expected_dist_dir=expected_dist_dir
),
'{bin_dir}/myapp-0.1-armeabi-v7a-debug.apk'.format(bin_dir=buildozer.bin_dir),
)
]
return m_execute_build_package
class TestTargetAndroid:
def setup_method(self):
"""
Create a temporary directory that will contain the spec file and will
serve as the root_dir.
"""
self.temp_dir = tempfile.TemporaryDirectory()
def tear_method(self):
"""
Remove the temporary directory created in self.setup_method.
"""
self.temp_dir.cleanup()
def test_init(self):
"""Tests init defaults."""
target_android = init_target(self.temp_dir)
buildozer = target_android.buildozer
assert target_android._arch == "armeabi-v7a"
assert target_android._build_dir.endswith(
".buildozer/android/platform/build-armeabi-v7a"
)
assert target_android._p4a_bootstrap == "sdl2"
assert target_android._p4a_cmd.endswith(
"python -m pythonforandroid.toolchain "
)
assert target_android.build_mode == "debug"
assert (
target_android.extra_p4a_args == (
' --color=always'
' --storage-dir="{buildozer_dir}/android/platform/build-armeabi-v7a" --ndk-api=21 --ignore-setup-py'.format(
buildozer_dir=buildozer.buildozer_dir)
)
)
assert target_android.p4a_apk_cmd == "apk --debug --bootstrap=sdl2"
assert target_android.platform_update is False
def test_init_positional_buildozer(self):
"""Positional `buildozer` argument is required."""
with pytest.raises(TypeError) as ex_info:
TargetAndroid()
assert ex_info.value.args == (
"__init__() missing 1 required positional argument: 'buildozer'",
)
def test_sdkmanager(self):
"""Tests the _sdkmanager() method."""
target_android = init_target(self.temp_dir)
kwargs = {}
with patch_buildozer_cmd() as m_cmd, patch_buildozer_cmd_expect() as m_cmd_expect, patch_os_isfile() as m_isfile:
m_isfile.return_value = True
assert m_cmd.return_value == target_android._sdkmanager(**kwargs)
assert m_cmd.call_count == 1
assert m_cmd_expect.call_count == 0
assert m_isfile.call_count == 1
kwargs = {"return_child": True}
with patch_buildozer_cmd() as m_cmd, patch_buildozer_cmd_expect() as m_cmd_expect, patch_os_isfile() as m_isfile:
m_isfile.return_value = True
assert m_cmd_expect.return_value == target_android._sdkmanager(
**kwargs
)
assert m_cmd.call_count == 0
assert m_cmd_expect.call_count == 1
assert m_isfile.call_count == 1
def test_check_requirements(self):
"""Basic tests for the check_requirements() method."""
target_android = init_target(self.temp_dir)
buildozer = target_android.buildozer
assert not hasattr(target_android, "adb_cmd")
assert not hasattr(target_android, "javac_cmd")
assert "PATH" not in buildozer.environ
with patch_buildozer_checkbin() as m_checkbin:
target_android.check_requirements()
assert m_checkbin.call_args_list == [
mock.call("Git (git)", "git"),
mock.call("Cython (cython)", "cython"),
mock.call("Java compiler (javac)", "javac"),
mock.call("Java keytool (keytool)", "keytool"),
]
assert target_android.adb_cmd.endswith(
".buildozer/android/platform/android-sdk/platform-tools/adb"
)
assert target_android.javac_cmd == "javac"
assert target_android.keytool_cmd == "keytool"
assert "PATH" in buildozer.environ
def test_check_configuration_tokens(self):
"""Basic tests for the check_configuration_tokens() method."""
target_android = init_target(self.temp_dir)
with mock.patch(
"buildozer.targets.android.Target.check_configuration_tokens"
) as m_check_configuration_tokens:
target_android.check_configuration_tokens()
assert m_check_configuration_tokens.call_args_list == [mock.call([])]
@pytest.mark.parametrize("platform", ["linux", "darwin"])
def test_install_android_sdk(self, platform):
"""Basic tests for the _install_android_sdk() method."""
target_android = init_target(self.temp_dir)
with patch_buildozer_file_exists() as m_file_exists, patch_buildozer_download() as m_download:
m_file_exists.return_value = True
sdk_dir = target_android._install_android_sdk()
assert m_file_exists.call_args_list == [
mock.call(target_android.android_sdk_dir)
]
assert m_download.call_args_list == []
assert sdk_dir.endswith(".buildozer/android/platform/android-sdk")
with patch_buildozer_file_exists() as m_file_exists, \
patch_buildozer_download() as m_download, \
patch_buildozer_file_extract() as m_file_extract, \
patch_platform(platform):
m_file_exists.return_value = False
sdk_dir = target_android._install_android_sdk()
assert m_file_exists.call_args_list == [
mock.call(target_android.android_sdk_dir)
]
platform_map = {"linux": "linux", "darwin": "mac"}
platform = platform_map[platform]
archive = "commandlinetools-{platform}-6514223_latest.zip".format(platform=platform)
assert m_download.call_args_list == [
mock.call(
"https://dl.google.com/android/repository/",
archive,
cwd=mock.ANY,
)
]
assert m_file_extract.call_args_list == [mock.call(archive, cwd=mock.ANY)]
assert sdk_dir.endswith(".buildozer/android/platform/android-sdk")
def test_build_package(self):
"""Basic tests for the build_package() method."""
target_android = init_target(self.temp_dir)
buildozer = target_android.buildozer
m_execute_build_package = call_build_package(target_android)
assert m_execute_build_package.call_args_list == [
mock.call(
[
("--name", "'My Application'"),
("--version", "0.1"),
("--package", "org.test.myapp"),
("--minsdk", "21"),
("--ndk-api", "21"),
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
("--android-entrypoint", "org.kivy.android.PythonActivity"),
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
("--orientation", "portrait"),
("--window",),
("debug",),
]
)
]
def test_numeric_version(self):
"""The `android.numeric_version` config should be passed to `build_package()`."""
target_android = init_target(self.temp_dir, {
"android.numeric_version": "1234"
})
buildozer = target_android.buildozer
m_execute_build_package = call_build_package(target_android)
assert m_execute_build_package.call_args_list == [
mock.call(
[
("--name", "'My Application'"),
("--version", "0.1"),
("--package", "org.test.myapp"),
("--minsdk", "21"),
("--ndk-api", "21"),
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
("--android-entrypoint", "org.kivy.android.PythonActivity"),
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
("--orientation", "portrait"),
("--window",),
("--numeric-version", "1234"),
("debug",),
]
)
]
def test_build_package_intent_filters(self):
"""
The build_package() method should honour the manifest.intent_filters
config option.
"""
filters_path = os.path.join(self.temp_dir.name, 'filters.xml')
with open(filters_path, 'w') as f:
f.write('<?xml version="1.0" encoding="utf-8"?>')
target_android = init_target(self.temp_dir, {
'android.manifest.intent_filters': 'filters.xml'
})
buildozer = target_android.buildozer
m_execute_build_package = call_build_package(target_android)
assert m_execute_build_package.call_args_list == [
mock.call(
[
('--name', "'My Application'"),
('--version', '0.1'),
('--package', 'org.test.myapp'),
('--minsdk', '21'),
('--ndk-api', '21'),
('--private', '{buildozer_dir}/android/app'.format(buildozer_dir=buildozer.buildozer_dir)),
('--android-entrypoint', 'org.kivy.android.PythonActivity'),
('--android-apptheme', '@android:style/Theme.NoTitleBar'),
('--orientation', 'portrait'),
('--window',),
('--intent-filters', os.path.realpath(filters_path)),
('debug',),
]
)
]
def test_allow_backup(self):
"""The `android.allow_backup` config should be passed to `build_package()`."""
target_android = init_target(self.temp_dir, {
"android.allow_backup": "false"
})
buildozer = target_android.buildozer
m_execute_build_package = call_build_package(target_android)
assert m_execute_build_package.call_args_list == [
mock.call(
[
("--name", "'My Application'"),
("--version", "0.1"),
("--package", "org.test.myapp"),
("--minsdk", "21"),
("--ndk-api", "21"),
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
("--android-entrypoint", "org.kivy.android.PythonActivity"),
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
("--orientation", "portrait"),
("--window",),
("--allow-backup", "false"),
("debug",),
]
)
]
def test_backup_rules(self):
"""The `android.backup_rules` config should be passed to `build_package()`."""
target_android = init_target(self.temp_dir, {
"android.backup_rules": "backup_rules.xml"
})
buildozer = target_android.buildozer
m_execute_build_package = call_build_package(target_android)
assert m_execute_build_package.call_args_list == [
mock.call(
[
("--name", "'My Application'"),
("--version", "0.1"),
("--package", "org.test.myapp"),
("--minsdk", "21"),
("--ndk-api", "21"),
("--private", "{buildozer_dir}/android/app".format(buildozer_dir=buildozer.buildozer_dir)),
("--android-entrypoint", "org.kivy.android.PythonActivity"),
("--android-apptheme", "@android:style/Theme.NoTitleBar"),
("--orientation", "portrait"),
("--window",),
("--backup-rules", "{root_dir}/backup_rules.xml".format(root_dir=buildozer.root_dir)),
("debug",),
]
)
]
def test_install_platform_p4a_clone_url(self):
"""The `p4a.url` config should be used for cloning p4a before the `p4a.fork` option."""
target_android = init_target(self.temp_dir, {
'p4a.url': 'https://custom-p4a-url/p4a.git',
'p4a.fork': 'myfork',
})
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
target_android._install_p4a()
assert mock.call(
'git clone -b master --single-branch https://custom-p4a-url/p4a.git python-for-android',
cwd=mock.ANY) in m_cmd.call_args_list
def test_install_platform_p4a_clone_fork(self):
"""The `p4a.fork` config should be used for cloning p4a."""
target_android = init_target(self.temp_dir, {
'p4a.fork': 'fork'
})
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
target_android._install_p4a()
assert mock.call(
'git clone -b master --single-branch https://github.com/fork/python-for-android.git python-for-android',
cwd=mock.ANY) in m_cmd.call_args_list
def test_install_platform_p4a_clone_default(self):
"""The default URL should be used for cloning p4a if no config options `p4a.url` and `p4a.fork` are set."""
target_android = init_target(self.temp_dir)
with patch_buildozer_cmd() as m_cmd, mock.patch('buildozer.targets.android.open') as m_open:
m_open.return_value = StringIO('install_reqs = []') # to stub setup.py parsing
target_android._install_p4a()
assert mock.call(
'git clone -b master --single-branch https://github.com/kivy/python-for-android.git python-for-android',
cwd=mock.ANY) in m_cmd.call_args_list

View file

@ -1,215 +0,0 @@
import sys
import tempfile
from unittest import mock
import pytest
from buildozer import BuildozerCommandException
from buildozer.targets.ios import TargetIos
from tests.targets.utils import (
init_buildozer,
patch_buildozer_checkbin,
patch_buildozer_cmd,
patch_buildozer_error,
patch_buildozer_file_exists,
)
def patch_target_ios(method):
return mock.patch("buildozer.targets.ios.TargetIos.{method}".format(method=method))
def init_target(temp_dir, options=None):
buildozer = init_buildozer(temp_dir, "ios", options)
return TargetIos(buildozer)
@pytest.mark.skipif(
sys.platform != "darwin", reason="Only macOS is supported for target iOS"
)
class TestTargetIos:
def setup_method(self):
"""
Create a temporary directory that will contain the spec file and will
serve as the root_dir.
"""
self.temp_dir = tempfile.TemporaryDirectory()
def tear_method(self):
"""
Remove the temporary directory created in self.setup_method.
"""
self.temp_dir.cleanup()
def test_init(self):
"""Tests init defaults."""
target = init_target(self.temp_dir)
assert target.targetname == "ios"
assert target.code_signing_allowed == "CODE_SIGNING_ALLOWED=NO"
assert target.build_mode == "debug"
assert target.platform_update is False
def test_check_requirements(self):
"""Basic tests for the check_requirements() method."""
target = init_target(self.temp_dir)
buildozer = target.buildozer
assert not hasattr(target, "adb_cmd")
assert not hasattr(target, "javac_cmd")
assert "PATH" not in buildozer.environ
with patch_buildozer_checkbin() as m_checkbin:
target.check_requirements()
assert m_checkbin.call_args_list == [
mock.call("Xcode xcodebuild", "xcodebuild"),
mock.call("Xcode xcode-select", "xcode-select"),
mock.call("Git git", "git"),
mock.call("Cython cython", "cython"),
mock.call("pkg-config", "pkg-config"),
mock.call("autoconf", "autoconf"),
mock.call("automake", "automake"),
mock.call("libtool", "libtool"),
]
assert target._toolchain_cmd.endswith("toolchain.py ")
assert target._xcodebuild_cmd == "xcodebuild "
def test_check_configuration_tokens(self):
"""Basic tests for the check_configuration_tokens() method."""
target = init_target(self.temp_dir, {"ios.codesign.allowed": "yes"})
with mock.patch(
"buildozer.targets.android.Target.check_configuration_tokens"
) as m_check_configuration_tokens, mock.patch(
"buildozer.targets.ios.TargetIos._get_available_identities"
) as m_get_available_identities:
target.check_configuration_tokens()
assert m_get_available_identities.call_args_list == [mock.call()]
assert m_check_configuration_tokens.call_args_list == [
mock.call(
[
'[app] "ios.codesign.debug" key missing, you must give a certificate name to use.',
'[app] "ios.codesign.release" key missing, you must give a certificate name to use.',
]
)
]
def test_get_available_packages(self):
"""Checks the toolchain `recipes --compact` output is parsed correctly to return recipe list."""
target = init_target(self.temp_dir)
with patch_target_ios("toolchain") as m_toolchain:
m_toolchain.return_value = ("hostpython3 kivy pillow python3 sdl2", None, 0)
available_packages = target.get_available_packages()
assert m_toolchain.call_args_list == [
mock.call("recipes --compact", get_stdout=True)
]
assert available_packages == [
"hostpython3",
"kivy",
"pillow",
"python3",
"sdl2",
]
def test_install_platform(self):
"""Checks `install_platform()` calls clone commands and sets `ios_dir` and `ios_deploy_dir` attributes."""
target = init_target(self.temp_dir)
assert target.ios_dir is None
assert target.ios_deploy_dir is None
with patch_buildozer_cmd() as m_cmd:
target.install_platform()
assert m_cmd.call_args_list == [
mock.call("git clone https://github.com/kivy/kivy-ios", cwd=mock.ANY),
mock.call(
"git clone --branch 1.10.0 https://github.com/phonegap/ios-deploy",
cwd=mock.ANY,
),
]
assert target.ios_dir.endswith(".buildozer/ios/platform/kivy-ios")
assert target.ios_deploy_dir.endswith(".buildozer/ios/platform/ios-deploy")
def test_compile_platform(self):
"""Checks the `toolchain build` command is called on the ios requirements."""
target = init_target(self.temp_dir)
target.ios_deploy_dir = "/ios/deploy/dir"
# fmt: off
with patch_target_ios("get_available_packages") as m_get_available_packages, \
patch_target_ios("toolchain") as m_toolchain, \
patch_buildozer_file_exists() as m_file_exists:
m_get_available_packages.return_value = ["hostpython3", "python3"]
m_file_exists.return_value = True
target.compile_platform()
# fmt: on
assert m_get_available_packages.call_args_list == [mock.call()]
assert m_toolchain.call_args_list == [mock.call("build python3")]
assert m_file_exists.call_args_list == [
mock.call(target.ios_deploy_dir, "ios-deploy")
]
def test_get_package(self):
"""Checks default package values and checks it can be overridden."""
# default value
target = init_target(self.temp_dir)
package = target._get_package()
assert package == "org.test.myapp"
# override
target = init_target(
self.temp_dir,
{"package.domain": "com.github.kivy", "package.name": "buildozer"},
)
package = target._get_package()
assert package == "com.github.kivy.buildozer"
def test_unlock_keychain_wrong_password(self):
"""A `BuildozerCommandException` should be raised on wrong password 3 times."""
target = init_target(self.temp_dir)
# fmt: off
with mock.patch("buildozer.targets.ios.getpass") as m_getpass, \
patch_buildozer_cmd() as m_cmd, \
pytest.raises(BuildozerCommandException):
m_getpass.return_value = "password"
# the `security unlock-keychain` command returned an error
# hence we'll get prompted to enter the password
m_cmd.return_value = (None, None, 123)
target._unlock_keychain()
# fmt: on
assert m_getpass.call_args_list == [
mock.call("Password to unlock the default keychain:"),
mock.call("Password to unlock the default keychain:"),
mock.call("Password to unlock the default keychain:"),
]
def test_build_package_no_signature(self):
"""Code signing is currently required to go through final `xcodebuild` steps."""
target = init_target(self.temp_dir)
target.ios_dir = "/ios/dir"
# fmt: off
with patch_target_ios("_unlock_keychain") as m_unlock_keychain, \
patch_buildozer_error() as m_error, \
mock.patch("buildozer.targets.ios.plistlib.readPlist") as m_readplist, \
mock.patch("buildozer.targets.ios.plistlib.writePlist") as m_writeplist, \
patch_buildozer_cmd() as m_cmd:
m_readplist.return_value = {}
target.build_package()
# fmt: on
assert m_unlock_keychain.call_args_list == [mock.call()]
assert m_error.call_args_list == [
mock.call(
"Cannot create the IPA package without signature. "
'You must fill the "ios.codesign.debug" token.'
)
]
assert m_readplist.call_args_list == [
mock.call("/ios/dir/myapp-ios/myapp-Info.plist")
]
assert m_writeplist.call_args_list == [
mock.call(
{
"CFBundleIdentifier": "org.test.myapp",
"CFBundleShortVersionString": "0.1",
"CFBundleVersion": "0.1.None",
},
"/ios/dir/myapp-ios/myapp-Info.plist",
)
]
assert m_cmd.call_args_list == [mock.call(mock.ANY, cwd=target.ios_dir), mock.call(
"xcodebuild -configuration Debug -allowProvisioningUpdates ENABLE_BITCODE=NO "
"CODE_SIGNING_ALLOWED=NO clean build",
cwd="/ios/dir/myapp-ios",
)]

View file

@ -1,66 +0,0 @@
import os
import re
from unittest import mock
import buildozer as buildozer_module
from buildozer import Buildozer
def patch_buildozer(method):
return mock.patch("buildozer.Buildozer.{method}".format(method=method))
def patch_buildozer_cmd():
return patch_buildozer("cmd")
def patch_buildozer_checkbin():
return patch_buildozer("checkbin")
def patch_buildozer_file_exists():
return patch_buildozer("file_exists")
def patch_buildozer_error():
return patch_buildozer("error")
def default_specfile_path():
return os.path.join(os.path.dirname(buildozer_module.__file__), "default.spec")
def init_buildozer(temp_dir, target, options=None):
"""
Create a buildozer.spec file in the temporary directory and init the
Buildozer instance.
The optional argument can be used to overwrite the config options in
the buildozer.spec file, e.g.:
init_buildozer({'title': 'Test App'})
will replace line 4 of the default spec file.
"""
if options is None:
options = {}
spec_path = os.path.join(temp_dir.name, "buildozer.spec")
with open(default_specfile_path()) as f:
default_spec = f.readlines()
spec = []
for line in default_spec:
if line.strip():
match = re.search(r"[#\s]?([0-9a-z_.]+)", line)
key = match and match.group(1)
if key in options:
line = "{} = {}\n".format(key, options[key])
spec.append(line)
with open(spec_path, "w") as f:
f.writelines(spec)
return Buildozer(filename=spec_path, target=target)

View file

@ -1,243 +0,0 @@
import re
import os
import codecs
import unittest
import buildozer as buildozer_module
from buildozer import Buildozer
from six import StringIO
import tempfile
from unittest import mock
from buildozer.targets.android import (
TargetAndroid, DEFAULT_ANDROID_NDK_VERSION, MSG_P4A_RECOMMENDED_NDK_ERROR
)
class TestBuildozer(unittest.TestCase):
def setUp(self):
"""
Creates a temporary spec file containing the content of the default.spec.
"""
self.specfile = tempfile.NamedTemporaryFile(suffix='.spec', delete=False)
self.specfilename = self.specfile.name
default_spec = codecs.open(self.default_specfile_path(), encoding='utf-8')
self.specfile.write(default_spec.read().encode('utf-8'))
self.specfile.close()
def tearDown(self):
"""
Deletes the temporary spec file.
"""
os.unlink(self.specfile.name)
@staticmethod
def default_specfile_path():
return os.path.join(
os.path.dirname(buildozer_module.__file__),
'default.spec')
@staticmethod
def file_re_sub(filepath, pattern, replace):
"""
Helper method for inplace file regex editing.
"""
with open(filepath) as f:
file_content = f.read()
file_content = re.sub(pattern, replace, file_content)
with open(filepath, 'w') as f:
f.write(file_content)
@classmethod
def set_specfile_log_level(cls, specfilename, log_level):
"""
Helper method for setting `log_level` in a given `specfilename`.
"""
pattern = 'log_level = [0-9]'
replace = 'log_level = {}'.format(log_level)
cls.file_re_sub(specfilename, pattern, replace)
buildozer = Buildozer(specfilename)
assert buildozer.log_level == log_level
def test_buildozer_base(self):
"""
Basic test making sure the Buildozer object can be instantiated.
"""
buildozer = Buildozer()
assert buildozer.specfilename == 'buildozer.spec'
# spec file doesn't have to exist
assert os.path.exists(buildozer.specfilename) is False
def test_buildozer_read_spec(self):
"""
Initializes Buildozer object from existing spec file.
"""
buildozer = Buildozer(filename=self.default_specfile_path())
assert os.path.exists(buildozer.specfilename) is True
def test_buildozer_help(self):
"""
Makes sure the help gets display with no error, refs:
https://github.com/kivy/buildozer/issues/813
"""
buildozer = Buildozer()
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
buildozer.usage()
assert 'Usage:' in mock_stdout.getvalue()
def test_log_get_set(self):
"""
Tests reading and setting log level from spec file.
"""
# the default log level value is known
buildozer = Buildozer('does_not_exist.spec')
assert buildozer.log_level == 2
# sets log level to 1 on the spec file
self.set_specfile_log_level(self.specfile.name, 1)
buildozer = Buildozer(self.specfile.name)
assert buildozer.log_level == 1
def test_log_print(self):
"""
Checks logger prints different info depending on log level.
"""
# sets log level to 1 in the spec file
self.set_specfile_log_level(self.specfile.name, 1)
buildozer = Buildozer(self.specfile.name)
assert buildozer.log_level == 1
# at this level, debug messages shouldn't not be printed
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
buildozer.debug('debug message')
buildozer.info('info message')
buildozer.error('error message')
# using `in` keyword rather than `==` because of bash color prefix/suffix
assert 'debug message' not in mock_stdout.getvalue()
assert 'info message' in mock_stdout.getvalue()
assert 'error message' in mock_stdout.getvalue()
# sets log level to 2 in the spec file
self.set_specfile_log_level(self.specfile.name, 2)
buildozer = Buildozer(self.specfile.name)
assert buildozer.log_level == 2
# at this level all message types should be printed
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
buildozer.debug('debug message')
buildozer.info('info message')
buildozer.error('error message')
assert 'debug message' in mock_stdout.getvalue()
assert 'info message' in mock_stdout.getvalue()
assert 'error message' in mock_stdout.getvalue()
def test_run_command_unknown(self):
"""
Makes sure the unknown command/target is handled gracefully, refs:
https://github.com/kivy/buildozer/issues/812
"""
buildozer = Buildozer()
command = 'foobar'
args = [command, 'debug']
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
with self.assertRaises(SystemExit):
buildozer.run_command(args)
assert mock_stdout.getvalue() == 'Unknown command/target {}\n'.format(command)
def test_android_ant_path(self):
"""
Verify that the selected ANT path is being used from the spec file
"""
my_ant_path = '/my/ant/path'
buildozer = Buildozer(filename=self.default_specfile_path(), target='android')
buildozer.config.set('app', 'android.ant_path', my_ant_path) # Set ANT path
target = TargetAndroid(buildozer=buildozer)
# Mock first run
with mock.patch('buildozer.Buildozer.download') as download, \
mock.patch('buildozer.Buildozer.file_extract') as m_file_extract, \
mock.patch('os.makedirs'):
ant_path = target._install_apache_ant()
assert m_file_extract.call_args_list == [mock.call(mock.ANY, cwd='/my/ant/path')]
assert ant_path == my_ant_path
assert download.call_args_list == [
mock.call("https://archive.apache.org/dist/ant/binaries/", mock.ANY, cwd=my_ant_path)]
# Mock ant already installed
with mock.patch.object(Buildozer, 'file_exists', return_value=True):
ant_path = target._install_apache_ant()
assert ant_path == my_ant_path
def test_cmd_unicode_decode(self):
"""
Verifies Buildozer.cmd() can properly handle non-unicode outputs.
refs: https://github.com/kivy/buildozer/issues/857
"""
buildozer = Buildozer()
command = 'uname'
kwargs = {
'show_output': True,
'get_stdout': True,
'get_stderr': True,
}
command_output = b'\x80 cannot decode \x80'
# showing the point that we can't decode it
with self.assertRaises(UnicodeDecodeError):
command_output.decode('utf-8')
with mock.patch('buildozer.Popen') as m_popen, \
mock.patch('buildozer.select') as m_select, \
mock.patch('buildozer.stdout') as m_stdout:
m_select.select().__getitem__.return_value = [0]
# makes sure fcntl.fcntl() gets what it expects so it doesn't crash
m_popen().stdout.fileno.return_value = 0
m_popen().stderr.fileno.return_value = 2
# Buildozer.cmd() is iterating through command output "chunk" until
# one chunk is None
m_popen().stdout.read.side_effect = [command_output, None]
m_popen().returncode = 0
stdout, stderr, returncode = buildozer.cmd(command, **kwargs)
# when get_stdout is True, the command output also gets returned
assert stdout == command_output.decode('utf-8', 'ignore')
assert stderr is None
assert returncode == 0
# Python2 and Python3 have different approaches for decoding the output
assert m_stdout.write.call_args_list == [
mock.call(command_output.decode('utf-8', 'replace'))
]
def test_p4a_recommended_ndk_version_default_value(self):
self.set_specfile_log_level(self.specfile.name, 1)
buildozer = Buildozer(self.specfile.name, 'android')
assert buildozer.target.p4a_recommended_ndk_version is None
def test_p4a_recommended_android_ndk_error(self):
self.set_specfile_log_level(self.specfile.name, 1)
buildozer = Buildozer(self.specfile.name, 'android')
with mock.patch('sys.stdout', new_callable=StringIO) as mock_stdout:
ndk_version = buildozer.target.p4a_recommended_android_ndk
assert MSG_P4A_RECOMMENDED_NDK_ERROR in mock_stdout.getvalue()
# and we should get the default android's ndk version of buildozer
assert ndk_version == DEFAULT_ANDROID_NDK_VERSION
@mock.patch('buildozer.targets.android.os.path.isfile')
@mock.patch('buildozer.targets.android.os.path.exists')
@mock.patch('buildozer.targets.android.open', create=True)
def test_p4a_recommended_android_ndk_found(
self, mock_open, mock_exists, mock_isfile
):
self.set_specfile_log_level(self.specfile.name, 1)
buildozer = Buildozer(self.specfile.name, 'android')
expected_ndk = '19b'
recommended_line = 'RECOMMENDED_NDK_VERSION = {expected_ndk}\n'.format(
expected_ndk=expected_ndk)
mock_open.return_value = StringIO(recommended_line)
ndk_version = buildozer.target.p4a_recommended_android_ndk
p4a_dir = os.path.join(
buildozer.platform_dir, buildozer.target.p4a_directory_name)
mock_open.assert_called_once_with(
os.path.join(p4a_dir, "pythonforandroid", "recommendations.py"), 'r'
)
assert ndk_version == expected_ndk
# now test that we only read one time p4a file, so we call again to
# `p4a_recommended_android_ndk` and we should still have one call to `open`
# file, the performed above
ndk_version = buildozer.target.p4a_recommended_android_ndk
mock_open.assert_called_once()

32
tox.ini
View file

@ -1,32 +0,0 @@
[tox]
envlist = pep8,py3
[testenv]
deps =
pytest
py3: coverage
commands = pytest tests/
[testenv:py3]
# for py3 env we will get code coverage
commands =
coverage run --branch --source=buildozer -m pytest {posargs:tests/}
coverage report -m
[testenv:pep8]
deps = flake8
commands = flake8 buildozer/ tests/
[flake8]
ignore =
E121, # continuation line under-indented for hanging indent
E122, # continuation line missing indentation or outdented
E126, # continuation line over-indented for hanging indent
E127, # continuation line over-indented for visual indent
E128, # continuation line under-indented for visual indent
E131, # continuation line unaligned for hanging indent
E402, # module level import not at top of file
E501, # line too long
E722, # do not use bare 'except'
W503, # line break before binary operator
W504 # line break after binary operator