Compare commits

..

26 commits

Author SHA1 Message Date
Akinwale Ariwodola
fd57c7dcbc cffi==1.14.6 2021-08-22 12:03:39 +01:00
Akinwale Ariwodola
99c60c715e experiment with Python optimisations 2021-08-22 11:48:09 +01:00
Akinwale Ariwodola
9c7a722cb9 don't copy Android.mk for openssl recipe if it already exists 2021-08-22 11:48:09 +01:00
Akinwale Ariwodola
637cab527c enable sqlite3 options for performance improvements 2021-08-22 11:48:09 +01:00
Akinwale Ariwodola
3f43579b89 fix sqlite3 includes in python3 recipe 2021-08-22 11:48:09 +01:00
Akinwale Ariwodola
2770f62b1b openssl==1.1.1k, sqlite3==3.36.0 2021-08-22 11:48:07 +01:00
Akinwale Ariwodola
76db2fa5c2 fix netifaces recipe 2021-08-22 11:44:08 +01:00
Akinwale Ariwodola
34571792b8 restore netifaces recipe 2021-08-22 11:44:01 +01:00
Akinwale Ariwodola
8e601d789e protobuf==3.11.0 2021-08-21 22:07:09 +01:00
Akinwale Ariwodola
5db6a512c0 fix netifaces recipe 2021-08-21 21:25:29 +01:00
Akinwale Ariwodola
fc797d9b20 restore netifaces recipe 2021-08-21 21:11:32 +01:00
Akinwale Ariwodola
b301bcad82 keyring==21.0.0. Remove netifaces. 2021-08-21 20:55:37 +01:00
Akinwale Ariwodola
bc251c9fac add python 3.10 to loadLibraries check 2021-08-21 20:31:33 +01:00
Akinwale Ariwodola
70128b640f remove unused .gitsecret folder 2021-08-21 20:12:43 +01:00
Akinwale Ariwodola
d7999e3b22 update Python 3.9 Dockerfile 2021-08-21 20:10:41 +01:00
Akinwale Ariwodola
6ccca10fe7 update Python 3.10 Dockerfile 2021-08-21 20:09:07 +01:00
Akinwale Ariwodola
f1ee1966cb update gitlab ci artifact names 2021-08-21 20:08:19 +01:00
Akinwale Ariwodola
c7252a1fe6 fix gitlab ci 2021-08-21 19:22:07 +01:00
Akinwale Ariwodola
cc3cdbfda1 skip buildozer sdkmanager update 2021-08-21 19:12:18 +01:00
Akinwale Ariwodola
3ffdfb6e21 update Docker build and Gitlab CI 2021-08-21 18:46:34 +01:00
Akinwale Ariwodola
ed31d64e72 use correct hostpython for pure python recipes 2021-08-21 14:43:18 +01:00
Akinwale Ariwodola
678a7739a0 define Py_BUILD_CORE for unicodedata module 2021-08-21 13:45:10 +01:00
Akinwale Ariwodola
f093b2d521 add missing C files to makefile 2021-08-21 13:39:58 +01:00
Akinwale Ariwodola
5576c3f76c use Python 3.10 docker for CI 2021-08-21 13:29:38 +01:00
Akinwale Ariwodola
6db440a97c Python 3.10 Dockerfile 2021-08-21 13:28:01 +01:00
Akinwale Ariwodola
7585e64559 Python 3.10.0rc1 build 2021-08-21 13:24:58 +01:00
26 changed files with 188 additions and 219 deletions

View file

@ -1,117 +0,0 @@
name: Publish Assets
on:
push:
branches: [master]
jobs:
build_arm64_aar:
runs-on: ubuntu-latest
container: lbry/android-base:python39
steps:
- name: checkout
uses: actions/checkout@v3
- name: hacky copy # docker image runs ~ as /root, but github actions uses ~=/github/home
run: |
cp -r /root/.buildozer ~/.buildozer/
- name: setup
run: |
export B_VERSION=$(cat $GITHUB_WORKSPACE/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
echo "NEXUS_SIGNING_KEYRING_FILE=$GITHUB_WORKSPACE/signing2.pgp" >> $GITHUB_ENV
echo "BUILD_VERSION=${B_VERSION}" >> $GITHUB_ENV
export PATH=/usr/bin:$PATH
wget -q 'https://eu.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P ~/.buildozer/android/
tar -xf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C ~/.buildozer/android/
rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
ln -s ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
cp -f $GITHUB_WORKSPACE/scripts/build-target-python.sh ~/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
cp -f $GITHUB_WORKSPACE/scripts/mangled-glibc-syscalls__arm64.h ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21/arch-arm64/usr/include/crystax/bionic/libc/include/sys/mangled-glibc-syscalls.h
cp -f $GITHUB_WORKSPACE/scripts/build-binary.mk ~/.buildozer/android/crystax-ndk-10.3.2/build/core/build-binary.mk
rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/sources/sqlite
cp -Rf $GITHUB_WORKSPACE/scripts/crystax-sources/sqlite ~/.buildozer/android/crystax-ndk-10.3.2/sources/sqlite
rm ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz
mv buildozer.spec.arm64.ci buildozer.spec
chmod u+x ./build-release.sh
- name: build release
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
NEXUS_SIGNING_KEY_PASSWORD: ${{ secrets.NEXUS_SIGNING_KEY_PASSWORD }}
NEXUS_SIGNING_KEY_ID: ${{ secrets.NEXUS_SIGNING_KEY_ID }}
run: ./build-release.sh
# - name: debug bin
# run : ls -al ./bin
# - name: upload to build_lbry_io
# run : |
# pip install awscli
# export PR_NUMBER=${{ github.event.number }}
# export BUILD_APK_FILENAME__64=lbrysdk-${{ env.BUILD_VERSION }}-arm64-v8a-release.aar
# aws s3 cp ./bin/${BUILD_APK_FILENAME__64} s3://build.lbry.io/android/sdk-build-${PR_NUMBER}_commit-${{ github.sha }}/${BUILD_APK_FILENAME__64}
# env:
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
# - name: github release
# if: startsWith(github.ref, 'refs/tags/v')
# run: |
# pip install githubrelease
# export GITHUB_TOKEN=${{ github.token }}
# githubrelease release lbryio/lbry-android-sdk create ${{ github.ref_name }} --publish bin/${BUILD_APK_FILENAME__64}
build_arm_aar:
runs-on: ubuntu-latest
container: lbry/android-base:python39
needs: [build_arm64_aar]
steps:
- name: checkout
uses: actions/checkout@v3
- name: hacky copy # docker image runs ~ as /root, but github actions uses ~=/github/home
run: |
cp -r /root/.buildozer ~/.buildozer/
- name: setup
run: |
export B_VERSION=$(cat $GITHUB_WORKSPACE/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
echo "BUILD_VERSION=${B_VERSION}" >> $GITHUB_ENV
echo "NEXUS_SIGNING_KEYRING_FILE=$GITHUB_WORKSPACE/signing2.pgp" >> $GITHUB_ENV
export PATH=/usr/bin:$PATH
wget -q 'https://eu.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz' -P ~/.buildozer/android/
tar -xf ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz -C ~/.buildozer/android/
rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
ln -s ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21 ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-9
cp -f $GITHUB_WORKSPACE/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle.arm $GITHUB_WORKSPACE/p4a/pythonforandroid/bootstraps/lbry/build/templates/build.tmpl.gradle
cp -f $GITHUB_WORKSPACE/scripts/build-target-python.sh ~/.buildozer/android/crystax-ndk-10.3.2/build/tools/build-target-python.sh
cp -f $GITHUB_WORKSPACE/scripts/mangled-glibc-syscalls.h ~/.buildozer/android/crystax-ndk-10.3.2/platforms/android-21/arch-arm/usr/include/crystax/bionic/libc/include/sys/mangled-glibc-syscalls.h
cp -f $GITHUB_WORKSPACE/scripts/build-binary.mk ~/.buildozer/android/crystax-ndk-10.3.2/build/core/build-binary.mk
rm -rf ~/.buildozer/android/crystax-ndk-10.3.2/sources/sqlite
cp -Rf $GITHUB_WORKSPACE/scripts/crystax-sources/sqlite ~/.buildozer/android/crystax-ndk-10.3.2/sources/sqlite
rm ~/.buildozer/android/crystax-ndk-10.3.2-linux-x86_64.tar.xz
mv buildozer.spec.arm64.ci buildozer.spec
chmod u+x ./build-release.sh
- name: build release
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
NEXUS_SIGNING_KEY_PASSWORD: ${{ secrets.NEXUS_SIGNING_KEY_PASSWORD }}
NEXUS_SIGNING_KEY_ID: ${{ secrets.NEXUS_SIGNING_KEY_ID }}
run: ./build-release.sh
# - name: upload to build_lbry_io
# run : |
# pip install awscli
# export PR_NUMBER=${{ github.event.number }}
# export BUILD_APK_FILENAME__32=lbrysdk-${{ env.BUILD_VERSION }}-armeabi-v7a-release.aar
# aws s3 cp bin/${BUILD_APK_FILENAME__32} s3://build.lbry.io/android/sdk-build-{$PR_NUMBER}_commit-${{ github.sha }}/${BUILD_APK_FILENAME__32}
# env:
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
# - name: github upload binary
# if: startsWith(github.ref, 'refs/tags/v')
# uses: skx/github-action-publish-binaries@release-1.3
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# BUILD_VERSION: ${{ env.BUILD_VERSION }}
# with:
# args: bin/${BUILD_APK_FILENAME__32}

1
.gitignore vendored
View file

@ -11,7 +11,6 @@ src/main/assets/index.android.bundle
src/main/assets/index.android.bundle.meta
*.log
.vagrant
.vscode
lbry-android.keystore
p4a/pythonforandroid/bootstraps/lbry/build/templates/google-services.json

View file

@ -6,7 +6,7 @@ stages:
build arm64 aar:
stage: build
image: lbry/android-base:python39
image: lbry/android-base:python3.10
before_script:
- export BUILD_VERSION=$(cat $CI_PROJECT_DIR/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
artifacts:
@ -33,7 +33,7 @@ build arm64 aar:
build arm aar:
stage: build2
image: lbry/android-base:python39
image: lbry/android-base:python3.10
before_script:
- export BUILD_VERSION=$(cat $CI_PROJECT_DIR/src/main/python/main.py | grep --color=never -oP '([0-9]+\.?)+')
artifacts:

View file

@ -135,17 +135,3 @@ If you already installed `Android SDK` and `adb`
Note: You need to have your device connected with USB debugging.
Once the bundler is ready, run the LBRY Browser app on your device and then shake the device violently until you see the React Native dev menu. You can enable "Live Reloading" and "Hot Reloading" from this menu, so any changes you make to the React Native code will be visible as you save. This will only reload React Native Javascript files. Native Java code needs to be redeployed by running the command `./deploy.sh`
## Update LBRY SDK Version
### Update the `requirements` section following files
* buildozer.spec.arm.ci
* buildozer.spec.arm64.ci
* buildozer.spec.sample
* buildozer.spec.vagrant
### Update LBRY_SDK_VERSION in `src/main/java/io/lbry/lbrysdk/LbrynetService.java`
### Update the version in `src/main/python/main.py`
## Github Actions CI

View file

@ -39,7 +39,7 @@ version.filename = %(source.dir)s/main.py
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.112.0#egg=lbry"
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.11.0, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes

View file

@ -39,7 +39,7 @@ version.filename = %(source.dir)s/main.py
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.112.0#egg=lbry"
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.11.0, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes

View file

@ -39,7 +39,7 @@ version.filename = %(source.dir)s/main.py
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.112.0#egg=lbry"
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.11.0, keyring==21.0.0, defusedxml, netifaces, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes

View file

@ -39,7 +39,7 @@ version.filename = %(source.dir)s/main.py
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==10.4.0, defusedxml, netifaces, git+https://github.com/lbryio/aioupnp.git@ab7ef0048bbce6404e463d20e8a15046ea6941f0#egg=aioupnp, asn1crypto, mock, netifaces, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.7.1, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2021.5.30, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.11.0, keyring==10.4.0, defusedxml, netifaces, git+https://github.com/lbryio/aioupnp.git@ab7ef0048bbce6404e463d20e8a15046ea6941f0#egg=aioupnp, asn1crypto, mock, cryptography, aiohttp==3.6.0, multidict==4.5.2, idna, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.7.1, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes
@ -275,4 +275,4 @@ warn_on_root = 1
# Then, invoke the command line with the "demo" profile:
#
#buildozer --profile demo android debug
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2020.12.5, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==21.0.0, defusedxml, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.5.4, multidict==4.5.2, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.112.0#egg=lbry"
requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro==1.4.0, pyjnius, certifi==2020.12.5, appdirs==1.4.3, docopt==0.6.2, base58==1.0.0, colorama==0.3.7, ecdsa==0.13.3, jsonschema==2.6.0, pbkdf2==1.3, pyyaml, protobuf==3.6.1, keyring==21.0.0, defusedxml, aioupnp==0.0.17, asn1crypto, mock, cryptography, aiohttp==3.5.4, multidict==4.5.2, yarl==1.3.0, chardet==3.0.4, async_timeout==3.0.1, coincurve, msgpack==0.6.1, six, attrs==18.2.0, pylru, hachoir, prometheus_client==0.8.0, "git+https://github.com/lbryio/lbry-sdk@v0.102.0#egg=lbry"

View file

@ -0,0 +1,47 @@
FROM ubuntu:20.04
RUN export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
RUN dpkg --add-architecture i386
RUN apt-get -y update && apt-get -y install curl ca-certificates software-properties-common gpg-agent wget
RUN add-apt-repository ppa:deadsnakes/ppa -y
RUN apt-get -y update && DEBIAN_FRONTEND=noninteractive apt-get -y install autoconf autogen automake \
libtool libffi-dev build-essential python3.10 python3.10-dev python3.10-venv ccache git \
libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 \
libidn11:i386 openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 m4 libc6-dev-i386 gawk
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.10 /usr/bin/python3
RUN rm -f /usr/bin/python && ln -s /usr/bin/python3.10 /usr/bin/python
RUN wget https://bootstrap.pypa.io/pip/get-pip.py && python3 get-pip.py
RUN pip install --upgrade cython==0.29.24 setuptools zipp importlib-resources importlib-metadata virtualenv appdirs sh colorama\>=0.3.3 jinja2 six pep517\<0.7.0 toml
RUN mkdir -p cd ~/.buildozer/android/platform/
RUN wget 'https://dl.google.com/android/android-sdk_r23-linux.tgz' -P ~/.buildozer/android/platform/ && \
wget 'https://dl.google.com/android/repository/platform-28_r06.zip' -P ~/.buildozer/android/platform/ && \
wget 'https://dl.google.com/android/repository/build-tools_r28.0.3-linux.zip' -P ~/.buildozer/android/platform/ && \
wget 'https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip' -P ~/.buildozer/android/platform
RUN tar -xvf ~/.buildozer/android/platform/android-sdk_r23-linux.tgz -C ~/.buildozer/android/platform/ && \
mv ~/.buildozer/android/platform/android-sdk-linux ~/.buildozer/android/platform/android-sdk && \
unzip ~/.buildozer/android/platform/platform-28_r06.zip -d ~/.buildozer/android/platform/android-sdk/platforms && \
mv ~/.buildozer/android/platform/android-sdk/platforms/android-9 ~/.buildozer/android/platform/android-sdk/platforms/android-28 && \
mkdir -p ~/.buildozer/android/platform/android-sdk/build-tools && \
unzip ~/.buildozer/android/platform/build-tools_r28.0.3-linux.zip -d ~/.buildozer/android/platform/android-sdk/build-tools && \
mv ~/.buildozer/android/platform/android-sdk/build-tools/android-9 ~/.buildozer/android/platform/android-sdk/build-tools/28.0.3 && \
mkdir -p ~/.buildozer/android/platform/android-sdk/cmdline-tools && \
unzip ~/.buildozer/android/platform/commandlinetools-linux-7583922_latest.zip -d ~/.buildozer/android/platform/android-sdk/cmdline-tools && \
mv ~/.buildozer/android/platform/android-sdk/cmdline-tools/cmdline-tools ~/.buildozer/android/platform/android-sdk/cmdline-tools/5.0 && \
cp -Rf ~/.buildozer/android/platform/android-sdk/cmdline-tools/5.0/* ~/.buildozer/android/platform/android-sdk/tools
RUN rm ~/.buildozer/android/platform/android-sdk_r23-linux.tgz && \
rm ~/.buildozer/android/platform/platform-28_r06.zip && \
rm ~/.buildozer/android/platform/build-tools_r28.0.3-linux.zip && \
rm ~/.buildozer/android/platform/commandlinetools-linux-7583922_latest.zip
RUN mkdir -p ~/.buildozer/android/platform/android-sdk/licenses && \
echo $'\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e\n24333f8a63b6825ea9c5514f83c2829b004d1fee' > ~/.buildozer/android/platform/android-sdk/licenses/android-sdk-license
RUN git clone https://github.com/lbryio/buildozer.git
RUN cd buildozer && python setup.py install && cd ..
CMD ["/bin/bash"]

View file

@ -83,7 +83,7 @@ class Arch(object):
env['CFLAGS'] += ' -isysroot {} '.format(sysroot)
env['CFLAGS'] += '-I' + join(self.ctx.get_python_install_dir(),
'include/python{}'.format(
self.ctx.python_recipe.version[0:3])
self.ctx.python_recipe.version)
)
env['LDFLAGS'] += '--sysroot={} '.format(self.ctx.ndk_platform)
@ -157,7 +157,7 @@ class Arch(object):
if self.ctx.python_recipe and self.ctx.python_recipe.from_crystax:
# For crystax python, we can't use the host python headers:
env["CFLAGS"] += ' -I{}/sources/python/{}/include/python/'.\
format(self.ctx.ndk_dir, self.ctx.python_recipe.version[0:3])
format(self.ctx.ndk_dir, self.ctx.python_recipe.version)
env['STRIP'] = '{}-strip --strip-unneeded'.format(command_prefix)
env['MAKE'] = 'make -j5'
env['READELF'] = '{}-readelf'.format(command_prefix)

View file

@ -33,6 +33,7 @@ public class PythonUtil {
libsList.add("python3.7m");
libsList.add("python3.8");
libsList.add("python3.9");
libsList.add("python3.10");
libsList.add("main");
return libsList;
}
@ -52,7 +53,7 @@ public class PythonUtil {
// load, and it has failed, give a more
// general error
Log.v(TAG, "Library loading error: " + e.getMessage());
if (lib.startsWith("python3.9") && !foundPython) {
if (lib.startsWith("python3.10") && !foundPython) {
throw new RuntimeException("Could not load any libpythonXXX.so");
} else if (lib.startsWith("python")) {
continue;

View file

@ -749,8 +749,9 @@ class PythonRecipe(Recipe):
host_build = Recipe.get_recipe(host_name, self.ctx).get_build_dir()
if host_name in ['hostpython2', 'hostpython3']:
return join(host_build, 'native-build', 'python')
elif host_name in ['hostpython3crystax', 'hostpython2legacy']:
return join(host_build, 'hostpython')
elif host_name in ['hostpython3crystax']:
python_recipe = Recipe.get_recipe(host_name, self.ctx)
return python_recipe.python_exe
else:
python_recipe = self.ctx.python_recipe
return 'python{}'.format(python_recipe.version)

View file

@ -45,7 +45,7 @@ class CffiRecipe(CompiledComponentsPythonRecipe):
])
if self.ctx.ndk == 'crystax':
# only keeps major.minor (discards patch)
python_version = self.ctx.python_recipe.version[0:3]
python_version = self.ctx.python_recipe.version
ndk_dir_python = os.path.join(self.ctx.ndk_dir, 'sources/python/', python_version)
env['LDFLAGS'] += ' -L{}'.format(os.path.join(ndk_dir_python, 'libs', arch.arch))
env['LDFLAGS'] += ' -lpython{}'.format(python_version)

View file

@ -21,7 +21,7 @@ class CoincurveRecipe(CompiledComponentsPythonRecipe):
env['LDFLAGS'] += ' -L{}'.format(os.path.join(libsecp256k1_dir, '.libs'))
env['CFLAGS'] += ' -I' + os.path.join(libsecp256k1_dir, 'include')
# only keeps major.minor (discards patch)
python_version = self.ctx.python_recipe.version[0:3]
python_version = self.ctx.python_recipe.version
# required additional library and path for Crystax
if self.ctx.ndk == 'crystax':
ndk_dir_python = os.path.join(self.ctx.ndk_dir, 'sources/python/', python_version)

View file

@ -23,7 +23,7 @@ class CryptographyRecipe(CompiledComponentsPythonRecipe):
if self.ctx.ndk == 'crystax':
# only keeps major.minor (discards patch)
python_version = self.ctx.python_recipe.version[0:3]
python_version = self.ctx.python_recipe.version
ndk_dir_python = os.path.join(self.ctx.ndk_dir, 'sources/python/', python_version)
env['LDFLAGS'] += ' -L{}'.format(os.path.join(ndk_dir_python, 'libs', arch.arch))
env['LDFLAGS'] += ' -lpython{}'.format(python_version)

View file

@ -42,5 +42,9 @@ class Hostpython3Recipe(Recipe):
link_dest = join(self.get_build_dir(), 'hostpython')
shprint(sh.ln, '-sf', system_python, link_dest)
@property
def python_exe(self):
return join(self.get_build_dir(), 'hostpython')
recipe = Hostpython3Recipe()

View file

@ -34,7 +34,8 @@ LATEST_FULL_VERSION = {
'3.5': '3.5.1',
'3.6': '3.6.6',
'3.7': '3.7.1',
'3.9': '3.9.6'
'3.9': '3.9.6',
'3.10': '3.10.0'
}
def realpath(fname):
@ -62,7 +63,7 @@ def realpath(fname):
return os.sep.join(abs_path)
class Python3Recipe(TargetPythonRecipe):
version = '3.9'
version = '3.10'
url = ''
name = 'python3crystax'
@ -72,9 +73,12 @@ class Python3Recipe(TargetPythonRecipe):
from_crystax = True
def download_if_necessary(self):
if 'openssl' in self.ctx.recipe_build_order or self.version in ('3.6', '3.7', '3.9'):
if 'openssl' in self.ctx.recipe_build_order or self.version in ('3.6', '3.7', '3.9', '3.10'):
full_version = LATEST_FULL_VERSION[self.version]
Python3Recipe.url = 'https://www.python.org/ftp/python/{0}.{1}.{2}/Python-{0}.{1}.{2}.tgz'.format(*full_version.split('.'))
version_suffix = 'rc1'
version_params = full_version.split('.')
version_params.append(version_suffix)
Python3Recipe.url = 'https://www.python.org/ftp/python/{0}.{1}.{2}/Python-{0}.{1}.{2}{3}.tgz'.format(*version_params)
super(Python3Recipe, self).download_if_necessary()
def get_dir_name(self):
@ -203,34 +207,43 @@ class Python3Recipe(TargetPythonRecipe):
def prebuild_arch(self, arch):
super(Python3Recipe, self).prebuild_arch(arch)
if self.version in ('3.6', '3.7', '3.9'):
Python3Recipe.patches = [
'patch/patch_python3.6.patch',
'patch/remove_android_api_check.patch',
'patch/selectors.patch'
if self.version in ('3.6', '3.7', '3.9', '3.10'):
patches = ['remove_android_api_check{}'.format('_3.10' if self.version == '3.10' else '')]
if self.version in ('3.6', '3.7'):
patches += [
'patch_python3.6',
'selectors'
]
if self.version in ('3.9'):
Python3Recipe.patches = [
'patch/remove_android_api_check.patch',
'patch/patch_python3.9.patch',
'patch/platlibdir.patch',
'patch/strdup.patch',
if self.version in ('3.9', '3.10'):
if self.version == '3.9':
patches += ['strdup']
if self.version == '3.10':
patches += ['py3.10.0_posixmodule']
patches += [
'patch_python3.9',
'platlibdir',
# from https://github.com/kivy/python-for-android/blob/develop/pythonforandroid/recipes/python3/__init__.py#L63
'patch/pyconfig_detection.patch',
'patch/reproducible-buildinfo.diff',
'patch/py3.8.1.patch'
'pyconfig_detection',
'reproducible-buildinfo',
'py3.8.1'
]
if sh.which('lld') is not None:
Python3Recipe.patches += ['patch/py3.8.1_fix_cortex_a8.patch']
patches += ['py3.8.1_fix_cortex_a8']
Python3Recipe.patches = []
for patch_name in patches:
Python3Recipe.patches.append('patch/{}.patch'.format(patch_name))
build_dir = self.get_build_dir(arch.arch)
# copy bundled libffi to _ctypes
sh.cp("-r", join(self.get_recipe_dir(), 'libffi'), join(build_dir, 'Modules', '_ctypes'))
print #####Copied bundle####'
shprint(sh.ln, '-sf',
realpath(join(build_dir, 'Lib/site-packages/README.txt')),

View file

@ -25,7 +25,6 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Python/getopt.c \
$(MY_PYTHON_SRC_ROOT)/Python/getplatform.c \
$(MY_PYTHON_SRC_ROOT)/Python/getversion.c \
$(MY_PYTHON_SRC_ROOT)/Python/graminit.c \
$(MY_PYTHON_SRC_ROOT)/Python/hamt.c \
$(MY_PYTHON_SRC_ROOT)/Python/hashtable.c \
$(MY_PYTHON_SRC_ROOT)/Python/import.c \
@ -36,7 +35,6 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Python/mysnprintf.c \
$(MY_PYTHON_SRC_ROOT)/Python/mystrtoul.c \
$(MY_PYTHON_SRC_ROOT)/Python/pathconfig.c \
$(MY_PYTHON_SRC_ROOT)/Python/peephole.c \
$(MY_PYTHON_SRC_ROOT)/Python/preconfig.c \
$(MY_PYTHON_SRC_ROOT)/Python/pyarena.c \
$(MY_PYTHON_SRC_ROOT)/Python/pyctype.c \
@ -51,27 +49,21 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Python/Python-ast.c \
$(MY_PYTHON_SRC_ROOT)/Python/pythonrun.c \
$(MY_PYTHON_SRC_ROOT)/Python/pytime.c \
$(MY_PYTHON_SRC_ROOT)/Python/strdup.c \
$(MY_PYTHON_SRC_ROOT)/Python/structmember.c \
$(MY_PYTHON_SRC_ROOT)/Python/suggestions.c \
$(MY_PYTHON_SRC_ROOT)/Python/symtable.c \
$(MY_PYTHON_SRC_ROOT)/Python/sysmodule.c \
$(MY_PYTHON_SRC_ROOT)/Python/thread.c \
$(MY_PYTHON_SRC_ROOT)/Python/traceback.c \
$(MY_PYTHON_SRC_ROOT)/Python/_warnings.c \
\
$(MY_PYTHON_SRC_ROOT)/Parser/acceler.c \
$(MY_PYTHON_SRC_ROOT)/Parser/grammar1.c \
$(MY_PYTHON_SRC_ROOT)/Parser/listnode.c \
$(MY_PYTHON_SRC_ROOT)/Parser/myreadline.c \
$(MY_PYTHON_SRC_ROOT)/Parser/node.c \
$(MY_PYTHON_SRC_ROOT)/Parser/parser.c \
$(MY_PYTHON_SRC_ROOT)/Parser/parsetok.c \
$(MY_PYTHON_SRC_ROOT)/Parser/peg_api.c \
$(MY_PYTHON_SRC_ROOT)/Parser/pegen.c \
$(MY_PYTHON_SRC_ROOT)/Parser/string_parser.c \
$(MY_PYTHON_SRC_ROOT)/Parser/token.c \
$(MY_PYTHON_SRC_ROOT)/Parser/tokenizer.c \
$(MY_PYTHON_SRC_ROOT)/Parser/pegen/parse.c \
$(MY_PYTHON_SRC_ROOT)/Parser/pegen/parse_string.c \
$(MY_PYTHON_SRC_ROOT)/Parser/pegen/peg_api.c \
$(MY_PYTHON_SRC_ROOT)/Parser/pegen/pegen.c \
\
$(MY_PYTHON_SRC_ROOT)/Objects/abstract.c \
$(MY_PYTHON_SRC_ROOT)/Objects/accu.c \
@ -115,6 +107,7 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Objects/typeobject.c \
$(MY_PYTHON_SRC_ROOT)/Objects/unicodectype.c \
$(MY_PYTHON_SRC_ROOT)/Objects/unicodeobject.c \
$(MY_PYTHON_SRC_ROOT)/Objects/unionobject.c \
$(MY_PYTHON_SRC_ROOT)/Objects/weakrefobject.c \
\
$(MY_PYTHON_SRC_ROOT)/Modules/_abc.c \
@ -150,8 +143,6 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_opcode.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_operator.c \
$(MY_PYTHON_SRC_ROOT)/Modules/ossaudiodev.c \
$(MY_PYTHON_SRC_ROOT)/Modules/parsermodule.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_peg_parser.c \
$(MY_PYTHON_SRC_ROOT)/Modules/posixmodule.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_posixsubprocess.c \
$(MY_PYTHON_SRC_ROOT)/Modules/pwdmodule.c \
@ -180,6 +171,7 @@ LOCAL_SRC_FILES := config.c \
$(MY_PYTHON_SRC_ROOT)/Modules/unicodedata.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_weakref.c \
$(MY_PYTHON_SRC_ROOT)/Modules/xxlimited.c \
$(MY_PYTHON_SRC_ROOT)/Modules/xxlimited_35.c \
$(MY_PYTHON_SRC_ROOT)/Modules/xxmodule.c \
$(MY_PYTHON_SRC_ROOT)/Modules/_xxsubinterpretersmodule.c \
$(MY_PYTHON_SRC_ROOT)/Modules/xxsubtype.c \

View file

@ -36,7 +36,6 @@ extern PyObject* PyInit__symtable(void);
extern PyObject* PyInit_mmap(void);
extern PyObject* PyInit__csv(void);
extern PyObject* PyInit__sre(void);
extern PyObject* PyInit_parser(void);
extern PyObject* PyInit__struct(void);
extern PyObject* PyInit__datetime(void);
extern PyObject* PyInit__functools(void);
@ -97,7 +96,6 @@ struct _inittab _PyImport_Inittab[] = {
{"mmap", PyInit_mmap},
{"_csv", PyInit__csv},
{"_sre", PyInit__sre},
{"parser", PyInit_parser},
{"_struct", PyInit__struct},
{"_datetime", PyInit__datetime},
{"_functools", PyInit__functools},

View file

@ -9,7 +9,7 @@
#define PYTHON3_STDLIB_REL_PATH "stdlib.zip"
#define PYTHON3_MODULES_REL_PATH "modules"
#define PYTHON3_DLL_REL_PATH "libpython3.9.so"
#define PYTHON3_DLL_REL_PATH "libpython3.10.so"
#define SYS_PATH_BUFFER_SIZE (2*(PATH_MAX + 1))

View file

@ -0,0 +1,12 @@
--- a/Modules/posixmodule.c 2021-08-02 20:53:59.000000000 +0100
+++ b/Modules/posixmodule.c 2021-08-21 12:06:16.897465398 +0100
@@ -15384,6 +15384,9 @@
#ifdef HAVE_EVENTFD
if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1;
if (PyModule_AddIntMacro(m, EFD_NONBLOCK)) return -1;
+# ifndef EFD_SEMAPHORE
+# define EFD_SEMAPHORE (1 << 0)
+# endif
if (PyModule_AddIntMacro(m, EFD_SEMAPHORE)) return -1;
#endif

View file

@ -0,0 +1,36 @@
--- a/configure 2021-08-02 20:53:59.000000000 +0100
+++ b/configure 2021-08-21 11:13:50.508648380 +0100
@@ -6241,33 +6241,6 @@
#endif
EOF
-if $CPP $CPPFLAGS conftest.c >conftest.out 2>/dev/null; then
- ANDROID_API_LEVEL=`sed -n -e '/__ANDROID_API__/d' -e 's/^android_api = //p' conftest.out`
- _arm_arch=`sed -n -e '/__ARM_ARCH/d' -e 's/^arm_arch = //p' conftest.out`
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ANDROID_API_LEVEL" >&5
-printf "%s\n" "$ANDROID_API_LEVEL" >&6; }
- if test -z "$ANDROID_API_LEVEL"; then
- echo 'Fatal: you must define __ANDROID_API__'
- exit 1
- fi
-
-printf "%s\n" "#define ANDROID_API_LEVEL $ANDROID_API_LEVEL" >>confdefs.h
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Android arm ABI" >&5
-printf %s "checking for the Android arm ABI... " >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $_arm_arch" >&5
-printf "%s\n" "$_arm_arch" >&6; }
- if test "$_arm_arch" = 7; then
- BASECFLAGS="${BASECFLAGS} -mfloat-abi=softfp -mfpu=vfpv3-d16"
- LDFLAGS="${LDFLAGS} -march=armv7-a -Wl,--fix-cortex-a8"
- fi
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not Android" >&5
-printf "%s\n" "not Android" >&6; }
-fi
-rm -f conftest.c conftest.out
-
# Check for unsupported systems
case $ac_sys_system/$ac_sys_release in
atheos*|Linux*/1*)

Binary file not shown.

View file

@ -56,7 +56,7 @@ import org.renpy.android.ResourceManager;
*/
public final class LbrynetService extends PythonService {
public static final String LBRY_SDK_VERSION = "0.112.0";
public static final String LBRY_SDK_VERSION = "0.102.0";
public static final int SERVICE_NOTIFICATION_GROUP_ID = 5;
public static final String ACTION_STOP_SERVICE = "io.lbry.browser.ACTION_STOP_SERVICE";
@ -143,7 +143,8 @@ public final class LbrynetService extends PythonService {
// update the notification with the context intent
Notification notification = buildNotification();
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
}
@ -172,7 +173,8 @@ public final class LbrynetService extends PythonService {
@Override
protected void doStartForeground(Bundle extras) {
downloadManager = new DownloadManager(this);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "LBRY Browser", NotificationManager.IMPORTANCE_LOW);
@ -219,8 +221,7 @@ public final class LbrynetService extends PythonService {
JSONObject result = status.getJSONObject("result");
if (result.has("startup_status")) {
JSONObject startupStatus = result.getJSONObject("startup_status");
fileManagerReady = startupStatus.has("file_manager")
&& startupStatus.getBoolean("file_manager");
fileManagerReady = startupStatus.has("file_manager") && startupStatus.getBoolean("file_manager");
}
}
}
@ -231,10 +232,8 @@ public final class LbrynetService extends PythonService {
params.put("page_size", 100);
params.put("reverse", true);
params.put("sort", "added_on");
/*
* params.put("status", "stopped");
* params.put("comparison", "ne");
*/
/*params.put("status", "stopped");
params.put("comparison", "ne");*/
String fileList = Utils.sdkCall("file_list", params);
if (fileList != null) {
@ -274,8 +273,7 @@ public final class LbrynetService extends PythonService {
if (fileItems != null && fileItems.length() > 0) {
// TODO: Create Java FileItem class
JSONObject item = fileItems.getJSONObject(0);
String downloadPath = item.isNull("download_path") ? null
: item.getString("download_path");
String downloadPath = item.isNull("download_path") ? null : item.getString("download_path");
if (downloadPath == null || downloadPath.trim().length() == 0) {
return;
}
@ -283,8 +281,7 @@ public final class LbrynetService extends PythonService {
String claimName = item.getString("claim_name");
String uri = String.format("lbry://%s#%s", claimName, claimId);
if (!downloadManager.isDownloadActive(uri)
&& !downloadManager.isDownloadCompleted(uri)) {
if (!downloadManager.isDownloadActive(uri) && !downloadManager.isDownloadCompleted(uri)) {
downloadManager.clearWrittenBytesForDownload(uri);
File file = new File(downloadPath);
Intent intent = createDownloadEventIntent(uri, outpoint, item.toString());
@ -446,6 +443,7 @@ public final class LbrynetService extends PythonService {
}
}
private static Intent createDownloadEventIntent(String uri, String outpoint, String fileInfo) {
Intent intent = new Intent();
intent.setAction(DownloadManager.ACTION_DOWNLOAD_EVENT);
@ -479,8 +477,7 @@ public final class LbrynetService extends PythonService {
Intent startedIntent = new Intent(LBRY_SDK_SERVICE_STARTED);
sendBroadcast(startedIntent);
// no need to iterate the checks repeatedly here, because this is service
// startup
// no need to iterate the checks repeatedly here, because this is service startup
checkDownloads();
return super.onStartCommand(intent, flags, startId);
@ -499,8 +496,8 @@ public final class LbrynetService extends PythonService {
}
Context context = getApplicationContext();
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
super.onDestroy();

View file

@ -1,5 +1,5 @@
# going forward, this should match sdk version
__version__ = "0.112.0"
__version__ = "0.102.0"
class ServiceApp(App):
def build(self):