diff --git a/.gitignore b/.gitignore index ad33c954a..b12728167 100644 --- a/.gitignore +++ b/.gitignore @@ -19,10 +19,6 @@ bin/ electrum_data .DS_Store -# icons -electrum/gui/kivy/theming/atlas/*.png -electrum/gui/kivy/theming/atlas/*.atlas - # tests/tox .tox/ .cache/ diff --git a/.gitmodules b/.gitmodules index bf2df0362..9f1c76c1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "electrum/www"] path = electrum/www url = https://github.com/spesmilo/electrum-http.git +[submodule "electrum/gui/kivy/theming/atlas"] + path = electrum/gui/kivy/theming/atlas + url = https://github.com/spesmilo/electrum-kivy-atlas diff --git a/.travis.yml b/.travis.yml index 1673eba77..5907a4632 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,9 +70,7 @@ jobs: services: - docker install: - - pip install requests && ./contrib/pull_locale - - ./contrib/make_packages - - sudo docker build --no-cache -t electrum-android-builder-img contrib/android + - ./contrib/android/build_docker_image.sh script: - sudo chown -R 1000:1000 . # Output something every minute or Travis kills the job diff --git a/contrib/android/Dockerfile b/contrib/android/Dockerfile index 3442e593b..6401a7002 100644 --- a/contrib/android/Dockerfile +++ b/contrib/android/Dockerfile @@ -1,6 +1,6 @@ # based on https://github.com/kivy/python-for-android/blob/master/Dockerfile -FROM ubuntu:20.04 +FROM ubuntu:20.04@sha256:86ac87f73641c920fb42cc9612d4fb57b5626b56ea2a19b894d0673fd5b4f2e9 ENV DEBIAN_FRONTEND=noninteractive @@ -20,7 +20,8 @@ RUN apt -y update -qq \ ENV ANDROID_NDK_HOME="${ANDROID_HOME}/android-ndk" -ENV ANDROID_NDK_VERSION="19c" +ENV ANDROID_NDK_VERSION="22b" +ENV ANDROID_NDK_HASH="ac3a0421e76f71dd330d0cd55f9d99b9ac864c4c034fc67e0d671d022d4e806b" ENV ANDROID_NDK_HOME_V="${ANDROID_NDK_HOME}-r${ANDROID_NDK_VERSION}" # get the latest version from https://developer.android.com/ndk/downloads/index.html @@ -31,6 +32,7 @@ ENV ANDROID_NDK_DL_URL="https://dl.google.com/android/repository/${ANDROID_NDK_A RUN curl --location --progress-bar \ "${ANDROID_NDK_DL_URL}" \ --output "${ANDROID_NDK_ARCHIVE}" \ + && echo "${ANDROID_NDK_HASH} ${ANDROID_NDK_ARCHIVE}" | sha256sum -c - \ && mkdir --parents "${ANDROID_NDK_HOME_V}" \ && unzip -q "${ANDROID_NDK_ARCHIVE}" -d "${ANDROID_HOME}" \ && ln -sfn "${ANDROID_NDK_HOME_V}" "${ANDROID_NDK_HOME}" \ @@ -42,6 +44,7 @@ ENV ANDROID_SDK_HOME="${ANDROID_HOME}/android-sdk" # get the latest version from https://developer.android.com/studio/index.html ENV ANDROID_SDK_TOOLS_VERSION="6514223" ENV ANDROID_SDK_BUILD_TOOLS_VERSION="29.0.3" +ENV ANDROID_SDK_HASH="ef319a5afdb41822cb1c88d93bc7c23b0af4fc670abca89ff0346ee6688da797" ENV ANDROID_SDK_TOOLS_ARCHIVE="commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip" ENV ANDROID_SDK_TOOLS_DL_URL="https://dl.google.com/android/repository/${ANDROID_SDK_TOOLS_ARCHIVE}" ENV ANDROID_SDK_MANAGER="${ANDROID_SDK_HOME}/tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_HOME}" @@ -50,6 +53,7 @@ ENV ANDROID_SDK_MANAGER="${ANDROID_SDK_HOME}/tools/bin/sdkmanager --sdk_root=${A RUN curl --location --progress-bar \ "${ANDROID_SDK_TOOLS_DL_URL}" \ --output "${ANDROID_SDK_TOOLS_ARCHIVE}" \ + && echo "${ANDROID_SDK_HASH} ${ANDROID_SDK_TOOLS_ARCHIVE}" | sha256sum -c - \ && mkdir --parents "${ANDROID_SDK_HOME}" \ && unzip -q "${ANDROID_SDK_TOOLS_ARCHIVE}" -d "${ANDROID_SDK_HOME}" \ && rm -rf "${ANDROID_SDK_TOOLS_ARCHIVE}" @@ -61,7 +65,8 @@ RUN mkdir --parents "${ANDROID_SDK_HOME}/.android/" \ # accept Android licenses (JDK necessary!) RUN apt -y update -qq \ - && apt -y install -qq --no-install-recommends openjdk-13-jdk \ + && apt -y install -qq --no-install-recommends \ + openjdk-11-jdk-headless \ && apt -y autoremove RUN yes | ${ANDROID_SDK_MANAGER} --licenses > /dev/null @@ -74,14 +79,16 @@ RUN ${ANDROID_SDK_MANAGER} "platforms;android-24" > /dev/null && \ # download ANT ENV APACHE_ANT_VERSION="1.9.4" +ENV APACHE_ANT_HASH="66d3edcbb0eba11387705cd89178ffb65e55cd53f13ca35c1bb983c0f9992540" ENV APACHE_ANT_ARCHIVE="apache-ant-${APACHE_ANT_VERSION}-bin.tar.gz" -ENV APACHE_ANT_DL_URL="http://archive.apache.org/dist/ant/binaries/${APACHE_ANT_ARCHIVE}" +ENV APACHE_ANT_DL_URL="https://archive.apache.org/dist/ant/binaries/${APACHE_ANT_ARCHIVE}" ENV APACHE_ANT_HOME="${ANDROID_HOME}/apache-ant" ENV APACHE_ANT_HOME_V="${APACHE_ANT_HOME}-${APACHE_ANT_VERSION}" RUN curl --location --progress-bar \ "${APACHE_ANT_DL_URL}" \ --output "${APACHE_ANT_ARCHIVE}" \ + && echo "${APACHE_ANT_HASH} ${APACHE_ANT_ARCHIVE}" | sha256sum -c - \ && tar -xf "${APACHE_ANT_ARCHIVE}" -C "${ANDROID_HOME}" \ && ln -sfn "${APACHE_ANT_HOME_V}" "${APACHE_ANT_HOME}" \ && rm -rf "${APACHE_ANT_ARCHIVE}" @@ -94,6 +101,7 @@ ENV WORK_DIR="${HOME_DIR}/wspace" \ # install system/build dependencies # https://github.com/kivy/buildozer/blob/master/docs/source/installation.rst#android-on-ubuntu-2004-64bit +# TODO probably need to pin versions of at least some of these for over-time reproducibility? RUN apt -y update -qq \ && apt -y install -qq --no-install-recommends \ python3 \ @@ -110,7 +118,6 @@ RUN apt -y update -qq \ unzip \ build-essential \ ccache \ - openjdk-13-jdk \ autoconf \ libtool \ pkg-config \ @@ -144,15 +151,9 @@ RUN chown ${USER} /opt USER ${USER} -RUN python3 -m pip install --user --upgrade pip -RUN python3 -m pip install --user --upgrade wheel -RUN python3 -m pip install --user --upgrade cython==0.29.19 -RUN python3 -m pip install --user --pre kivy -RUN python3 -m pip install --user image - -# prepare git -RUN git config --global user.name "John Doe" \ - && git config --global user.email johndoe@example.com +COPY requirements-build-android.txt /opt/deterministic-build/ +RUN python3 -m pip install --no-dependencies --user \ + -r /opt/deterministic-build/requirements-build-android.txt # install buildozer RUN cd /opt \ @@ -161,8 +162,8 @@ RUN cd /opt \ && git remote add sombernight https://github.com/SomberNight/buildozer \ && git fetch --all \ # commit: from branch sombernight/electrum_20210421 - && git checkout "c17ac3618334c9936253e8f5b88dce43dc4da75b^{commit}" \ - && python3 -m pip install --user -e . + && git checkout "d570116e88184b0eca0c6b59a25edd49d977da23^{commit}" \ + && python3 -m pip install --no-dependencies --user -e . # install python-for-android RUN cd /opt \ @@ -170,9 +171,9 @@ RUN cd /opt \ && cd python-for-android \ && git remote add sombernight https://github.com/SomberNight/python-for-android \ && git fetch --all \ - # commit: from branch sombernight/electrum_20210421 - && git checkout "5356bc7838b03c8c174c91fe01539c91d1b40b9f^{commit}" \ - && python3 -m pip install --user -e . + # commit: from branch sombernight/electrum_20210421b + && git checkout "cdee188f0ef28ff8452207da409912da19e917ca^{commit}" \ + && python3 -m pip install --no-dependencies --user -e . # build env vars ENV USE_SDK_WRAPPER=1 diff --git a/contrib/android/Makefile b/contrib/android/Makefile index b5ddbc34c..9768d6b2d 100644 --- a/contrib/android/Makefile +++ b/contrib/android/Makefile @@ -1,5 +1,14 @@ +SHELL := /bin/bash PYTHON = python3 +# for reproducible builds +export LC_ALL := C +export TZ := UTC +export SOURCE_DATE_EPOCH := $(shell git log -1 --pretty=%ct) +export PYTHONHASHSEED := $(SOURCE_DATE_EPOCH) +export BUILD_DATE := $(shell LC_ALL=C TZ=UTC date +'%b %e %Y' -d @$(SOURCE_DATE_EPOCH)) +export BUILD_TIME := $(shell LC_ALL=C TZ=UTC date +'%H:%M:%S' -d @$(SOURCE_DATE_EPOCH)) + # needs kivy installed or in PYTHONPATH .PHONY: theming apk clean diff --git a/contrib/android/Readme.md b/contrib/android/Readme.md index d7632fbba..5281cfbf8 100644 --- a/contrib/android/Readme.md +++ b/contrib/android/Readme.md @@ -5,8 +5,8 @@ To generate an APK file, follow these instructions. ## Android binary with Docker -✗ _This script does not produce reproducible output (yet!). - Please help us remedy this._ +✓ _These binaries should be reproducible, meaning you should be able to generate + binaries that match the official releases._ This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another similar system. The docker commands should be executed in the project's root @@ -24,24 +24,27 @@ folder. 2. Build image ``` - $ sudo docker build -t electrum-android-builder-img contrib/android + $ ./contrib/android/build_docker_image.sh ``` -3. Build locale files +3. Build binaries - ``` - $ ./contrib/pull_locale - ``` - -4. Prepare pure python dependencies + It's recommended to build from a fresh clone + (but you can skip this if reproducibility is not necessary). ``` - $ ./contrib/make_packages + $ FRESH_CLONE=contrib/android/fresh_clone && \ + sudo rm -rf $FRESH_CLONE && \ + umask 0022 && \ + mkdir -p $FRESH_CLONE && \ + cd $FRESH_CLONE && \ + git clone https://github.com/spesmilo/electrum.git && \ + cd electrum ``` -5. Build binaries - + And then build from this directory: ``` + $ git checkout $REV $ mkdir --parents $PWD/.buildozer/.gradle $ sudo docker run -it --rm \ --name electrum-android-builder-cont \ @@ -52,6 +55,10 @@ folder. electrum-android-builder-img \ ./contrib/android/make_apk ``` + + Note: this builds a debug apk. `make_apk` takes an optional parameter + which can be either `release` or `release-unsigned`. + This mounts the project dir inside the container, and so the modifications will affect it, e.g. `.buildozer` folder will be created. @@ -59,6 +66,25 @@ folder. 5. The generated binary is in `./bin`. +## Verifying reproducibility and comparing against official binary + +Every user can verify that the official binary was created from the source code in this +repository. + +1. Build your own binary as described above. + Make sure you don't build in `debug` mode (which is the default!), + instead use either of `release` or `release-unsigned`. + If you build in `release` mode, the apk will be signed, which requires a keystore + that you need to create manually (see source of `make_apk` for an example). +2. Note that the binaries are not going to be byte-for-byte identical, as the official + release is signed by a keystore that only the project maintainers have. + You can use the `apkdiff.py` python script (written by the Signal developers) to compare + the two binaries. + ``` + $ python3 contrib/android/apkdiff.py Electrum_apk_that_you_built.apk Electrum_apk_official_release.apk + ``` + This should output `APKs match!`. + ## FAQ @@ -125,3 +151,22 @@ $ adb shell $ run-as org.electrum.electrum ls /data/data/org.electrum.electrum/files/data $ run-as org.electrum.electrum cp /data/data/org.electrum.electrum/files/data/wallets/my_wallet /sdcard/some_path/my_wallet ``` + +### How to investigate diff between binaries if reproducibility fails? +``` +cd bin/ +unzip Electrum-*.apk1 -d apk1 +mkdir apk1/assets/private_mp3/ +tar -xzvf apk1/assets/private.mp3 --directory apk1/assets/private_mp3/ + +unzip Electrum-*.apk2 -d apk2 +mkdir apk2/assets/private_mp3/ +tar -xzvf apk2/assets/private.mp3 --directory apk2/assets/private_mp3/ + +sudo chown --recursive "$(id -u -n)" apk1/ apk2/ +chmod -R +Xr apk1/ apk2/ +$(cd apk1; find -type f -exec sha256sum '{}' \; > ./../sha256sum1) +$(cd apk2; find -type f -exec sha256sum '{}' \; > ./../sha256sum2) +diff sha256sum1 sha256sum2 > d +cat d +``` diff --git a/contrib/android/apkdiff.py b/contrib/android/apkdiff.py new file mode 100644 index 000000000..802222a9c --- /dev/null +++ b/contrib/android/apkdiff.py @@ -0,0 +1,78 @@ +#! /usr/bin/env python3 +# from https://github.com/signalapp/Signal-Android/blob/2029ea378f249a70983c1fc3d55b9a63588bc06c/reproducible-builds/apkdiff/apkdiff.py + +import sys +from zipfile import ZipFile + +class ApkDiff: + IGNORE_FILES = ["META-INF/MANIFEST.MF", "META-INF/CERT.RSA", "META-INF/CERT.SF"] + + def compare(self, sourceApk, destinationApk): + sourceZip = ZipFile(sourceApk, 'r') + destinationZip = ZipFile(destinationApk, 'r') + + if self.compareManifests(sourceZip, destinationZip) and self.compareEntries(sourceZip, destinationZip) == True: + print("APKs match!") + else: + print("APKs don't match!") + + def compareManifests(self, sourceZip, destinationZip): + sourceEntrySortedList = sorted(sourceZip.namelist()) + destinationEntrySortedList = sorted(destinationZip.namelist()) + + for ignoreFile in self.IGNORE_FILES: + while ignoreFile in sourceEntrySortedList: sourceEntrySortedList.remove(ignoreFile) + while ignoreFile in destinationEntrySortedList: destinationEntrySortedList.remove(ignoreFile) + + if len(sourceEntrySortedList) != len(destinationEntrySortedList): + print("Manifest lengths differ!") + + for (sourceEntryName, destinationEntryName) in zip(sourceEntrySortedList, destinationEntrySortedList): + if sourceEntryName != destinationEntryName: + print("Sorted manifests don't match, %s vs %s" % (sourceEntryName, destinationEntryName)) + return False + + return True + + def compareEntries(self, sourceZip, destinationZip): + sourceInfoList = list(filter(lambda sourceInfo: sourceInfo.filename not in self.IGNORE_FILES, sourceZip.infolist())) + destinationInfoList = list(filter(lambda destinationInfo: destinationInfo.filename not in self.IGNORE_FILES, destinationZip.infolist())) + + if len(sourceInfoList) != len(destinationInfoList): + print("APK info lists of different length!") + return False + + for sourceEntryInfo in sourceInfoList: + for destinationEntryInfo in list(destinationInfoList): + if sourceEntryInfo.filename == destinationEntryInfo.filename: + sourceEntry = sourceZip.open(sourceEntryInfo, 'r') + destinationEntry = destinationZip.open(destinationEntryInfo, 'r') + + if self.compareFiles(sourceEntry, destinationEntry) != True: + print("APK entry %s does not match %s!" % (sourceEntryInfo.filename, destinationEntryInfo.filename)) + return False + + destinationInfoList.remove(destinationEntryInfo) + break + + return True + + def compareFiles(self, sourceFile, destinationFile): + sourceChunk = sourceFile.read(1024) + destinationChunk = destinationFile.read(1024) + + while sourceChunk != b"" or destinationChunk != b"": + if sourceChunk != destinationChunk: + return False + + sourceChunk = sourceFile.read(1024) + destinationChunk = destinationFile.read(1024) + + return True + +if __name__ == '__main__': + if len(sys.argv) != 3: + print("Usage: apkdiff ") + sys.exit(1) + + ApkDiff().compare(sys.argv[1], sys.argv[2]) diff --git a/contrib/android/build_docker_image.sh b/contrib/android/build_docker_image.sh new file mode 100755 index 000000000..3eae956c5 --- /dev/null +++ b/contrib/android/build_docker_image.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +CONTRIB_ANDROID="$(dirname "$(readlink -e "$0")")" +CONTRIB="$CONTRIB_ANDROID"/.. + +cp "$CONTRIB/deterministic-build/requirements-build-android.txt" "$CONTRIB_ANDROID/requirements-build-android.txt" +sudo docker build -t electrum-android-builder-img "$CONTRIB_ANDROID" +rm "$CONTRIB_ANDROID/requirements-build-android.txt" diff --git a/contrib/android/buildozer.spec b/contrib/android/buildozer.spec index 16bee6519..43d505352 100644 --- a/contrib/android/buildozer.spec +++ b/contrib/android/buildozer.spec @@ -26,7 +26,9 @@ source.exclude_dirs = bin, build, dist, contrib, packages/qdarkstyle, packages/qtpy # (list) List of exclusions using pattern matching -source.exclude_patterns = Makefile,setup* +source.exclude_patterns = Makefile,setup*, + # not reproducible: + packages/aiohttp-*.dist-info/* # (str) Application versioning (method 1) version.regex = APK_VERSION = '(.*)' @@ -36,14 +38,14 @@ version.filename = %(source.dir)s/electrum/version.py #version = 1.9.8 # (list) Application requirements +# note: versions and hashes are pinned in ./p4a_recipes/* requirements = - hostpython3==3.8.8, - python3==3.8.8, + hostpython3, + python3, android, openssl, plyer, - # kivy master 2020-12-10 (2.0.0 plus a few bugfixes) - kivy==2debbc3b1484b14824112986cb03b1072a60fbfc, + kivy, libffi, libsecp256k1, cryptography @@ -79,7 +81,7 @@ android.api = 29 android.minapi = 21 # (str) Android NDK version to use -android.ndk = 19c +android.ndk = 22b # (int) Android NDK API to use (optional). This is the minimum API your app will support. android.ndk_api = 21 @@ -96,6 +98,18 @@ android.sdk_path = /opt/android/android-sdk # (str) ANT directory (if empty, it will be automatically downloaded.) android.ant_path = /opt/android/apache-ant +# (bool) If True, then skip trying to update the Android sdk +# This can be useful to avoid excess Internet downloads or save time +# when an update is due and you just want to test/build your package +# note(ghost43): probably needed for reproducibility. versions pinned in Dockerfile. +android.skip_update = True + +# (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 = True + # (str) Android entry point, default is ok for Kivy-based app #android.entrypoint = org.renpy.android.PythonActivity @@ -162,7 +176,7 @@ android.allow_backup = False p4a.source_dir = /opt/python-for-android # (str) The directory in which python-for-android should look for your own build recipes (if any) -#p4a.local_recipes = +p4a.local_recipes = %(source.dir)s/contrib/android/p4a_recipes/ # (str) Filename to the hook for p4a #p4a.hook = diff --git a/contrib/android/make_apk b/contrib/android/make_apk index c7a9a2415..788bd5656 100755 --- a/contrib/android/make_apk +++ b/contrib/android/make_apk @@ -3,25 +3,42 @@ set -e CONTRIB_ANDROID="$(dirname "$(readlink -e "$0")")" -ROOT_FOLDER="$CONTRIB_ANDROID"/../.. -PACKAGES="$ROOT_FOLDER"/packages/ -LOCALE="$ROOT_FOLDER"/electrum/locale/ +CONTRIB="$CONTRIB_ANDROID"/.. +PROJECT_ROOT="$CONTRIB"/.. +PACKAGES="$PROJECT_ROOT"/packages/ +LOCALE="$PROJECT_ROOT"/electrum/locale/ -if [ ! -d "$LOCALE" ]; then - echo "Run pull_locale first!" - exit 1 -fi +. "$CONTRIB"/build_tools_util.sh if [ ! -d "$PACKAGES" ]; then - echo "Run make_packages first!" - exit 1 + "$CONTRIB"/make_packages || fail "make_packages failed" fi -pushd ./contrib/android +pushd "$PROJECT_ROOT" +git submodule update --init +popd -make theming +# update locale +info "preparing electrum-locale." +( + cd "$CONTRIB"/deterministic-build/electrum-locale + if ! which msgfmt > /dev/null 2>&1; then + fail "Please install gettext" + fi + # we want the binary to have only compiled (.mo) locale files; not source (.po) files + rm -rf "$PROJECT_ROOT/electrum/locale/" + for i in ./locale/*; do + dir="$PROJECT_ROOT/electrum/$i/LC_MESSAGES" + mkdir -p $dir + msgfmt --output-file="$dir/electrum.mo" "$i/electrum.po" || true + done +) +pushd "$CONTRIB_ANDROID" + +info "apk building phase starts." if [[ -n "$1" && "$1" == "release" ]] ; then + # do release build, and sign the APKs. echo -n Keystore Password: read -s password export P4A_RELEASE_KEYSTORE=~/.keystore @@ -33,7 +50,15 @@ if [[ -n "$1" && "$1" == "release" ]] ; then make release export APP_ANDROID_ARCH=arm64-v8a make release +elif [[ -n "$1" && "$1" == "release-unsigned" ]] ; then + # do release build, but do not sign the APKs. + # build two apks + export APP_ANDROID_ARCH=armeabi-v7a + make release + export APP_ANDROID_ARCH=arm64-v8a + make release else + # do debug build; the default. export P4A_DEBUG_KEYSTORE="$CONTRIB_ANDROID"/android_debug.keystore export P4A_DEBUG_KEYSTORE_PASSWD=unsafepassword export P4A_DEBUG_KEYALIAS_PASSWD=unsafepassword diff --git a/contrib/android/p4a_recipes/README.md b/contrib/android/p4a_recipes/README.md new file mode 100644 index 000000000..3c4067909 --- /dev/null +++ b/contrib/android/p4a_recipes/README.md @@ -0,0 +1,10 @@ +python-for-android local recipes +-------------------------------- + +These folders are recipes (build scripts) for most of our direct and transitive +dependencies for the Android app. python-for-android has recipes built-in for +many packages but it also allows users to specify their "local" recipes. +Local recipes have precedence over the built-in recipes. + +The local recipes we have here are mostly just used to pin down specific +versions and hashes for reproducibility. The hashes are updated manually. diff --git a/contrib/android/p4a_recipes/certifi/__init__.py b/contrib/android/p4a_recipes/certifi/__init__.py new file mode 100644 index 000000000..94b7d4ce4 --- /dev/null +++ b/contrib/android/p4a_recipes/certifi/__init__.py @@ -0,0 +1,15 @@ +from pythonforandroid.recipe import PythonRecipe + + +assert PythonRecipe.depends == ['python3'] +assert PythonRecipe.python_depends == [] + + +class CertifiRecipePinned(PythonRecipe): + version = "2020.12.5" + sha512sum = "3425d98f19025e70d885458629071c8531271d93d1461fadea6afbaafc763881a42b3c05be391a938d84a0d1ab729c3ac5df4f3328e8ef63a7b56ead1445bddd" + url = "https://pypi.python.org/packages/source/c/certifi/certifi-{version}.tar.gz" + depends = ["setuptools"] + + +recipe = CertifiRecipePinned() diff --git a/contrib/android/p4a_recipes/cffi/__init__.py b/contrib/android/p4a_recipes/cffi/__init__.py new file mode 100644 index 000000000..a32b1c2e8 --- /dev/null +++ b/contrib/android/p4a_recipes/cffi/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.cffi import CffiRecipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert CffiRecipe._version == "1.13.2" +assert CffiRecipe.depends == ['setuptools', 'pycparser', 'libffi', 'python3'] +assert CffiRecipe.python_depends == [] + + +class CffiRecipePinned(util.InheritedRecipeMixin, CffiRecipe): + sha512sum = "2c57d9c06c39e95498a54408dc39940427190f3c03e1b8f1a3584140db08a5775dd12e6e67b03093429c130af579d01519b0fc868b99ba7a530068ed22d38522" + + +recipe = CffiRecipePinned() diff --git a/contrib/android/p4a_recipes/cryptography/__init__.py b/contrib/android/p4a_recipes/cryptography/__init__.py new file mode 100644 index 000000000..5c6bd1bf2 --- /dev/null +++ b/contrib/android/p4a_recipes/cryptography/__init__.py @@ -0,0 +1,13 @@ +from pythonforandroid.recipes.cryptography import CryptographyRecipe + + +assert CryptographyRecipe._version == "2.8" +assert CryptographyRecipe.depends == ['openssl', 'six', 'setuptools', 'cffi', 'python3'] +assert CryptographyRecipe.python_depends == [] + + +class CryptographyRecipePinned(CryptographyRecipe): + sha512sum = "000816a5513691bfbb01c5c65d96fb3567a5ff25300da4b485e716b6d4dc789aec05ed0fe65df9c5e3e60127aa9110f04e646407db5b512f88882b0659f7123f" + + +recipe = CryptographyRecipePinned() diff --git a/contrib/android/p4a_recipes/hostpython3/__init__.py b/contrib/android/p4a_recipes/hostpython3/__init__.py new file mode 100644 index 000000000..6c9cf5a17 --- /dev/null +++ b/contrib/android/p4a_recipes/hostpython3/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.hostpython3 import HostPython3Recipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert HostPython3Recipe.depends == [] +assert HostPython3Recipe.python_depends == [] + + +class HostPython3RecipePinned(util.InheritedRecipeMixin, HostPython3Recipe): + version = "3.8.8" + sha512sum = "1c6742cdc92ba6d3c03c63fd025bc348462517a503343685a42e22838aedc94ab2e438f1d1623b91ca1be5f39f327d76385d66b785ff93f0f3737b9870e9a003" + + +recipe = HostPython3RecipePinned() diff --git a/contrib/android/p4a_recipes/kivy/__init__.py b/contrib/android/p4a_recipes/kivy/__init__.py new file mode 100644 index 000000000..2f8fb2670 --- /dev/null +++ b/contrib/android/p4a_recipes/kivy/__init__.py @@ -0,0 +1,18 @@ +from pythonforandroid.recipes.kivy import KivyRecipe + + +assert KivyRecipe.depends == ['sdl2', 'pyjnius', 'setuptools', 'python3'] +assert KivyRecipe.python_depends == ['certifi'] + + +class KivyRecipePinned(KivyRecipe): + # kivy master 2020-12-10 (2.0.0 plus a few bugfixes) + version = "2debbc3b1484b14824112986cb03b1072a60fbfc" + sha512sum = "6cabb77860e63059ab4b0663b87f6396fa9133839b42db754628fc9a55f10b8d759466110e0763fd8dac40a49a03af276cb93b05076471d12db796e679f33d1d" + + # mv "python_depends" into "depends" to ensure we can control what versions get installed + depends = [*KivyRecipe.depends, *KivyRecipe.python_depends] + python_depends = [] + + +recipe = KivyRecipePinned() diff --git a/contrib/android/p4a_recipes/libffi/__init__.py b/contrib/android/p4a_recipes/libffi/__init__.py new file mode 100644 index 000000000..4867cc031 --- /dev/null +++ b/contrib/android/p4a_recipes/libffi/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.libffi import LibffiRecipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert LibffiRecipe._version == "v3.3" +assert LibffiRecipe.depends == [] +assert LibffiRecipe.python_depends == [] + + +class LibffiRecipePinned(util.InheritedRecipeMixin, LibffiRecipe): + sha512sum = "62798fb31ba65fa2a0e1f71dd3daca30edcf745dc562c6f8e7126e54db92572cc63f5aa36d927dd08375bb6f38a2380ebe6c5735f35990681878fc78fc9dbc83" + + +recipe = LibffiRecipePinned() diff --git a/contrib/android/p4a_recipes/libsecp256k1/__init__.py b/contrib/android/p4a_recipes/libsecp256k1/__init__.py new file mode 100644 index 000000000..df703f177 --- /dev/null +++ b/contrib/android/p4a_recipes/libsecp256k1/__init__.py @@ -0,0 +1,14 @@ +from pythonforandroid.recipes.libsecp256k1 import LibSecp256k1Recipe + + +assert LibSecp256k1Recipe.depends == [] +assert LibSecp256k1Recipe.python_depends == [] + + +class LibSecp256k1RecipePinned(LibSecp256k1Recipe): + version = "dbd41db16a0e91b2566820898a3ab2d7dad4fe00" + url = "https://github.com/bitcoin-core/secp256k1/archive/{version}.zip" + sha512sum = "9012586149fb952309f0a1eb9f41dcd668f839eb38bfa9e942b53b1974b793dfe7616879766837f3d98d1523c826a49ead966bca35aee11d734c81a2f6fd9bf9" + + +recipe = LibSecp256k1RecipePinned() diff --git a/contrib/android/p4a_recipes/openssl/__init__.py b/contrib/android/p4a_recipes/openssl/__init__.py new file mode 100644 index 000000000..17e29d6dc --- /dev/null +++ b/contrib/android/p4a_recipes/openssl/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.openssl import OpenSSLRecipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert OpenSSLRecipe.url_version == "1.1.1k" +assert OpenSSLRecipe.depends == [] +assert OpenSSLRecipe.python_depends == [] + + +class OpenSSLRecipePinned(util.InheritedRecipeMixin, OpenSSLRecipe): + sha512sum = "73cd042d4056585e5a9dd7ab68e7c7310a3a4c783eafa07ab0b560e7462b924e4376436a6d38a155c687f6942a881cfc0c1b9394afcde1d8c46bf396e7d51121" + + +recipe = OpenSSLRecipePinned() diff --git a/contrib/android/p4a_recipes/plyer/__init__.py b/contrib/android/p4a_recipes/plyer/__init__.py new file mode 100644 index 000000000..731dc22e8 --- /dev/null +++ b/contrib/android/p4a_recipes/plyer/__init__.py @@ -0,0 +1,15 @@ +from pythonforandroid.recipe import PythonRecipe + + +assert PythonRecipe.depends == ['python3'] +assert PythonRecipe.python_depends == [] + + +class PlyerRecipePinned(PythonRecipe): + version = "2.0.0" + sha512sum = "8088eeb41aac753435ff5be9835be74d57a55cf557ad76cbad8026352647e554571fae6172754e39882ea7ef07cc1e97fac16556a4426456de99daebe5cd01cf" + url = "https://pypi.python.org/packages/source/p/plyer/plyer-{version}.tar.gz" + depends = ["setuptools"] + + +recipe = PlyerRecipePinned() diff --git a/contrib/android/p4a_recipes/pycparser/__init__.py b/contrib/android/p4a_recipes/pycparser/__init__.py new file mode 100644 index 000000000..aebfd988f --- /dev/null +++ b/contrib/android/p4a_recipes/pycparser/__init__.py @@ -0,0 +1,13 @@ +from pythonforandroid.recipes.pycparser import PycparserRecipe + + +assert PycparserRecipe._version == "2.14" +assert PycparserRecipe.depends == ['setuptools', 'python3'] +assert PycparserRecipe.python_depends == [] + + +class PycparserRecipePinned(PycparserRecipe): + sha512sum = "d5b9ab434a8944898ac23a4f51189db77b02b993bf3e3ca018852b117fc0eb43e460b156beaa5c1d631ad71c81e1649113e9fff7e33506b1e7d4de24d8b464c6" + + +recipe = PycparserRecipePinned() diff --git a/contrib/android/p4a_recipes/pyjnius/__init__.py b/contrib/android/p4a_recipes/pyjnius/__init__.py new file mode 100644 index 000000000..2321b14b3 --- /dev/null +++ b/contrib/android/p4a_recipes/pyjnius/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.pyjnius import PyjniusRecipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert PyjniusRecipe._version == "1.3.0" +assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2'), 'six', 'python3'] +assert PyjniusRecipe.python_depends == [] + + +class PyjniusRecipePinned(util.InheritedRecipeMixin, PyjniusRecipe): + sha512sum = "5a3475afcda5afbef6e1a67bab508e3c24bd564efda5ac38ae7669d39b4bfdbfaaa83f435f26d39b3d849d3a167a9c136c9ac6b2bfcc0bda09ef1c00aa66cf25" + + +recipe = PyjniusRecipePinned() diff --git a/contrib/android/p4a_recipes/python3/__init__.py b/contrib/android/p4a_recipes/python3/__init__.py new file mode 100644 index 000000000..7611d5bf1 --- /dev/null +++ b/contrib/android/p4a_recipes/python3/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.python3 import Python3Recipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert Python3Recipe.depends == ['hostpython3', 'sqlite3', 'openssl', 'libffi'] +assert Python3Recipe.python_depends == [] + + +class Python3RecipePinned(util.InheritedRecipeMixin, Python3Recipe): + version = "3.8.8" + sha512sum = "1c6742cdc92ba6d3c03c63fd025bc348462517a503343685a42e22838aedc94ab2e438f1d1623b91ca1be5f39f327d76385d66b785ff93f0f3737b9870e9a003" + + +recipe = Python3RecipePinned() diff --git a/contrib/android/p4a_recipes/sdl2/__init__.py b/contrib/android/p4a_recipes/sdl2/__init__.py new file mode 100644 index 000000000..07dc059b8 --- /dev/null +++ b/contrib/android/p4a_recipes/sdl2/__init__.py @@ -0,0 +1,19 @@ +import os + +from pythonforandroid.recipes.sdl2 import LibSDL2Recipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert LibSDL2Recipe._version == "2.0.9" +assert LibSDL2Recipe.depends == ['sdl2_image', 'sdl2_mixer', 'sdl2_ttf'] +assert LibSDL2Recipe.python_depends == [] + + +class LibSDL2RecipePinned(util.InheritedRecipeMixin, LibSDL2Recipe): + md5sum = None + sha512sum = "a78a4708b2bb5b35a7c7b7501eb3bd60a9aa3bb95a3d84e57763df4a377185e7312a94b66321eef7ca0d17255e4b402fc950e83ef0dbbd08f14ff1194107dc10" + + +recipe = LibSDL2RecipePinned() diff --git a/contrib/android/p4a_recipes/sdl2_image/__init__.py b/contrib/android/p4a_recipes/sdl2_image/__init__.py new file mode 100644 index 000000000..3feed45d1 --- /dev/null +++ b/contrib/android/p4a_recipes/sdl2_image/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.sdl2_image import LibSDL2Image +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert LibSDL2Image._version == "2.0.4" +assert LibSDL2Image.depends == [] +assert LibSDL2Image.python_depends == [] + + +class LibSDL2ImageRecipePinned(util.InheritedRecipeMixin, LibSDL2Image): + sha512sum = "7320a5c9111908d402fbb0c12a49eb359a6db645c0c86839793ebb1a5b75eaca7c85eb96851f3a0b4a68a2f06363c8189555afd4f1048a4a41447370eddd7e6a" + + +recipe = LibSDL2ImageRecipePinned() diff --git a/contrib/android/p4a_recipes/sdl2_mixer/__init__.py b/contrib/android/p4a_recipes/sdl2_mixer/__init__.py new file mode 100644 index 000000000..d018783a2 --- /dev/null +++ b/contrib/android/p4a_recipes/sdl2_mixer/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.sdl2_mixer import LibSDL2Mixer +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert LibSDL2Mixer._version == "2.0.4" +assert LibSDL2Mixer.depends == [] +assert LibSDL2Mixer.python_depends == [] + + +class LibSDL2MixerPinned(util.InheritedRecipeMixin, LibSDL2Mixer): + sha512sum = "98c56069640668aaececa63748de21fc8f243c7d06386c45c43d0ee472bbb2595ccda644d9886ce5b95c3a3dee3c0a96903cf9a89ddc18d38f041133470699a3" + + +recipe = LibSDL2MixerPinned() diff --git a/contrib/android/p4a_recipes/sdl2_ttf/__init__.py b/contrib/android/p4a_recipes/sdl2_ttf/__init__.py new file mode 100644 index 000000000..6803e8558 --- /dev/null +++ b/contrib/android/p4a_recipes/sdl2_ttf/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.sdl2_ttf import LibSDL2TTF +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert LibSDL2TTF._version == "2.0.15" +assert LibSDL2TTF.depends == [] +assert LibSDL2TTF.python_depends == [] + + +class LibSDL2TTFPinned(util.InheritedRecipeMixin, LibSDL2TTF): + sha512sum = "30d685932c3dd6f2c94e2778357a5c502f0421374293d7102a64d92f9c7861229bf36bedf51c1a698b296a58c858ca442d97afb908b7df1592fc8d4f8ae8ddfd" + + +recipe = LibSDL2TTFPinned() diff --git a/contrib/android/p4a_recipes/setuptools/__init__.py b/contrib/android/p4a_recipes/setuptools/__init__.py new file mode 100644 index 000000000..10a26f398 --- /dev/null +++ b/contrib/android/p4a_recipes/setuptools/__init__.py @@ -0,0 +1,13 @@ +from pythonforandroid.recipes.setuptools import SetuptoolsRecipe + + +assert SetuptoolsRecipe._version == "51.3.3" +assert SetuptoolsRecipe.depends == ['python3'] +assert SetuptoolsRecipe.python_depends == [] + + +class SetuptoolsRecipePinned(SetuptoolsRecipe): + sha512sum = "5a3572466a68c6f650111448ce3343f64c62044650bb8635edbff97e2bc7b216b8bbe3b4e3bccf34e6887f3bedc911b27ca5f9a515201cae49cf44fbacf03345" + + +recipe = SetuptoolsRecipePinned() diff --git a/contrib/android/p4a_recipes/six/__init__.py b/contrib/android/p4a_recipes/six/__init__.py new file mode 100644 index 000000000..68eaa2792 --- /dev/null +++ b/contrib/android/p4a_recipes/six/__init__.py @@ -0,0 +1,13 @@ +from pythonforandroid.recipes.six import SixRecipe + + +assert SixRecipe._version == "1.15.0" +assert SixRecipe.depends == ['setuptools', 'python3'] +assert SixRecipe.python_depends == [] + + +class SixRecipePinned(SixRecipe): + sha512sum = "eb840ac17f433f1fc4af56de75cfbfe0b54e6a737bb23c453bf09a4a13d768d153e46064880dc763f4c5cc2785b78ea6d3d3b4a41fed181cb9064837e3f699a9" + + +recipe = SixRecipePinned() diff --git a/contrib/android/p4a_recipes/sqlite3/__init__.py b/contrib/android/p4a_recipes/sqlite3/__init__.py new file mode 100644 index 000000000..70b6bd932 --- /dev/null +++ b/contrib/android/p4a_recipes/sqlite3/__init__.py @@ -0,0 +1,18 @@ +import os + +from pythonforandroid.recipes.sqlite3 import Sqlite3Recipe +from pythonforandroid.util import load_source + +util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py')) + + +assert Sqlite3Recipe._version == "3.34.1" +assert Sqlite3Recipe.depends == [] +assert Sqlite3Recipe.python_depends == [] + + +class Sqlite3RecipePinned(util.InheritedRecipeMixin, Sqlite3Recipe): + sha512sum = "8a936f1c34fc9036cadf5bd53f9ee594135c2efdef1d2c82bd4fdf3e0218afde710fc4c436cfc992687d008e6086a697da0487352ed88809d677e05d824940dd" + + +recipe = Sqlite3RecipePinned() diff --git a/contrib/android/p4a_recipes/util.py b/contrib/android/p4a_recipes/util.py new file mode 100644 index 000000000..ffdd3ff73 --- /dev/null +++ b/contrib/android/p4a_recipes/util.py @@ -0,0 +1,12 @@ +import os + + +class InheritedRecipeMixin: + + def get_recipe_dir(self): + """This is used to replace pythonforandroid.recipe.Recipe.get_recipe_dir. + If one of our local recipes inherits from a built-in p4a recipe, this override + ensures that potential patches and other local files used by the recipe will + be looked for in the built-in recipe's folder. + """ + return os.path.join(self.ctx.root_dir, 'recipes', self.name) diff --git a/contrib/build-linux/sdist/make_tgz b/contrib/build-linux/sdist/make_tgz index 81b672f91..b61bbbbbc 100755 --- a/contrib/build-linux/sdist/make_tgz +++ b/contrib/build-linux/sdist/make_tgz @@ -36,9 +36,6 @@ git submodule update --init ( cd "$ROOT_FOLDER" - # we could build the kivy atlas potentially? - #(cd contrib/android/; make theming) || echo "building kivy atlas failed! skipping." - find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} + # note: .zip sdists would not be reproducible due to https://bugs.python.org/issue40963 diff --git a/contrib/deterministic-build/requirements-build-android.txt b/contrib/deterministic-build/requirements-build-android.txt new file mode 100644 index 000000000..a2f742f1e --- /dev/null +++ b/contrib/deterministic-build/requirements-build-android.txt @@ -0,0 +1,153 @@ +appdirs==1.4.4 \ + --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \ + --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 +colorama==0.4.4 \ + --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b \ + --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 +Cython==0.29.23 \ + --hash=sha256:0c4b9f7e3aa004cf3f364e3e772f55fec5740485bafea99d1f13bdc9bbd8a545 \ + --hash=sha256:20402ef316393168909926ab21848aa6e08e39bed5003b657139774e66166cd0 \ + --hash=sha256:20cb50d9fede8029bdb50875458f07a27f909289aeed4cdb9c19544dd9a9bc45 \ + --hash=sha256:2365f3b5e6451b6bc6dcd262230656f4ade1d862ec2f6c22154deebef37c08b6 \ + --hash=sha256:266459c7e48fe3c6c492b297e4033e42d4c6863cc1a1ff7cc4034949fc574fa6 \ + --hash=sha256:282263628c5d601b313d5920f7b6d7e08c7fedbddacd080c4858aa04d86b6b4b \ + --hash=sha256:2a3bbce689a2fddb85aa66712d93875c99bf7f64ac82b1d149ecce522a7a4e0c \ + --hash=sha256:2af52d312e96b38ded38b34d06e22685c226b1b0e58278bd27209f5d2385d115 \ + --hash=sha256:355a6e768d91e21fbf477b61881bab64b7a2da386a166898997bccefd532cf5d \ + --hash=sha256:37ff66039e3d138ec968ee1d1e12441fa5fb4e6a9c5458bc3c3a232f01be4a7d \ + --hash=sha256:3b29224eb62309a10819d923dc6262f769e4f3facfee3cd06372c355e5b38b33 \ + --hash=sha256:3ef530f975e3a760e7282fce2a25f900fa63f96d17321b4aa5f5542eb9859cdf \ + --hash=sha256:41cd0dd2ff5d78466e73409db509887a84449b400074d4f217980cedbb18e4be \ + --hash=sha256:474c1a29ab43e29d990df279e2cf6aa96baa9208f5cd4bc76ac87ffcdf1e2945 \ + --hash=sha256:4858043ac5f96a8f0277cf63760bb39b9521c1f897678cf1d22423f3e758f4ed \ + --hash=sha256:4b0bcf2e06a9063fc78c3243ed4003228375d532ef13b9e5d7183be8f0a52cf5 \ + --hash=sha256:4b6824b58d4373224fc76ee8bee6b35c2d17c91a1ed0fa67b88440f63daebe50 \ + --hash=sha256:4d7c3b0882d8757c601eaf288fc0d321d5c7ac6c3afb8c42eddf9325a3419cf5 \ + --hash=sha256:519fccf526d26b377e1db22f22aa44889b28bc5833ec106588cb13557e8ba2da \ + --hash=sha256:58dc06871bfdb0592542d779714fe9f918e11ba20ac07757dd63b198bdc704fe \ + --hash=sha256:5a6792153b728a0240e55bbb5b643f4f7e45c76319e03abf15bf367471ea1d1a \ + --hash=sha256:5be3ae3189cf7d0e9bbeafb854496dc7030c6f6a5602d809435fab8223543a41 \ + --hash=sha256:625a16103770fd92b487b701fb0c07e5790b080f40fa11ce572a2d56d9e9fcca \ + --hash=sha256:6a0d31452f0245daacb14c979c77e093eb1a546c760816b5eed0047686baad8e \ + --hash=sha256:794e3df0b57e16bce7583ac909126f4cb381fe566adadb20484d89095855eedb \ + --hash=sha256:7b7a766726d207d7cd57aff0fcb4b35ce042d3cc88a421fcdb45eeb61a5b9d12 \ + --hash=sha256:7d6a33c8a11f05f698e215bfdb837f32c27f63c20f3af863557ed91c748dc2be \ + --hash=sha256:a8eed9c82e8fe07b8a8ffbd36018871a17458903fc25c9d015f37b54513a3efd \ + --hash=sha256:aa3bb0928fb2aa3a8828801eb8b29af2261c199f805ae835467489e2bdd00372 \ + --hash=sha256:b0699f0dc90181f2458fdb8170455e7798a309e18f41379eda7a2dc8c7aadee0 \ + --hash=sha256:c4b82461edbbcf90f19b319006345b77474a2d7514e1476d49a14bbd55d6b797 \ + --hash=sha256:ceccc03b633113ede1f14ad914a6db5c278ce108c8ddb308a5c01c1567d8a02a \ + --hash=sha256:ef21c51350462160456eb71df31b0869e5141e940f22c61c358bdb6e3ebc3388 \ + --hash=sha256:f4aca6bffb1c1c3c4ada3347d0b162a699c18a66e097ee08b63b3a35118fdfcc \ + --hash=sha256:ff885f18d169759b57f116d3956e45cd2b9cba989fde348bba091544c668dc11 +distlib==0.3.1 \ + --hash=sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb \ + --hash=sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1 +filelock==3.0.12 \ + --hash=sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59 \ + --hash=sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836 +importlib-metadata==4.0.1 \ + --hash=sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581 \ + --hash=sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d +importlib-resources==5.1.2 \ + --hash=sha256:642586fc4740bd1cad7690f836b3321309402b20b332529f25617ff18e8e1370 \ + --hash=sha256:ebab3efe74d83b04d6bf5cd9a17f0c5c93e60fb60f30c90f56265fce4682a469 +Jinja2==2.11.3 \ + --hash=sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419 \ + --hash=sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6 +MarkupSafe==1.1.1 \ + --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ + --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \ + --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \ + --hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \ + --hash=sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42 \ + --hash=sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f \ + --hash=sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39 \ + --hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \ + --hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b \ + --hash=sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014 \ + --hash=sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f \ + --hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \ + --hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \ + --hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \ + --hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \ + --hash=sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b \ + --hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \ + --hash=sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15 \ + --hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \ + --hash=sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85 \ + --hash=sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1 \ + --hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \ + --hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \ + --hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \ + --hash=sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850 \ + --hash=sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0 \ + --hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \ + --hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \ + --hash=sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb \ + --hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \ + --hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \ + --hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \ + --hash=sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1 \ + --hash=sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2 \ + --hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \ + --hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \ + --hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \ + --hash=sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7 \ + --hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \ + --hash=sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8 \ + --hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \ + --hash=sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193 \ + --hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \ + --hash=sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b \ + --hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \ + --hash=sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2 \ + --hash=sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5 \ + --hash=sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c \ + --hash=sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032 \ + --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \ + --hash=sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be \ + --hash=sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621 +pep517==0.6.0 \ + --hash=sha256:273345f4538306f6e4056d8bbced566e186ab4defc188cb3be3e413b5d255912 \ + --hash=sha256:dde535e9a42de94f4cd941dbaa6feb0a4b5143ffd3906efea091c3826cb7d33d +pexpect==4.8.0 \ + --hash=sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937 \ + --hash=sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c +pip==21.1 \ + --hash=sha256:a810bf07c3723a28621c29abe8e34429fa082c337f89aea9a795865416b66d3e \ + --hash=sha256:ea9f2668484893e90149fd5a6124e04651ffedd67203a8aaf030d31406b937a4 +ptyprocess==0.7.0 \ + --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \ + --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220 +pytoml==0.1.21 \ + --hash=sha256:57a21e6347049f73bfb62011ff34cd72774c031b9828cb628a752225136dfc33 \ + --hash=sha256:8eecf7c8d0adcff3b375b09fe403407aa9b645c499e5ab8cac670ac4a35f61e7 +setuptools==56.0.0 \ + --hash=sha256:08a1c0f99455307c48690f00d5c2ac2c1ccfab04df00454fef854ec145b81302 \ + --hash=sha256:7430499900e443375ba9449a9cc5d78506b801e929fef4a186496012f93683b5 +sh==1.14.1 \ + --hash=sha256:39aa9af22f6558a0c5d132881cf43e34828ca03e4ae11114852ca6a55c7c1d8e \ + --hash=sha256:75e86a836f47de095d4531718fe8489e6f7446c75ddfa5596f632727b919ffae +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f +virtualenv==20.4.4 \ + --hash=sha256:09c61377ef072f43568207dc8e46ddeac6bcdcaf288d49011bda0e7f4d38c4a2 \ + --hash=sha256:a935126db63128861987a7d5d30e23e8ec045a73840eeccb467c148514e29535 +wheel==0.36.2 \ + --hash=sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e \ + --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e +zipp==3.4.1 \ + --hash=sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76 \ + --hash=sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098 +pathlib2==2.3.5 \ + --hash=sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db \ + --hash=sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868 \ No newline at end of file diff --git a/contrib/freeze_packages.sh b/contrib/freeze_packages.sh index 8782056fe..c265345f9 100755 --- a/contrib/freeze_packages.sh +++ b/contrib/freeze_packages.sh @@ -20,7 +20,7 @@ which virtualenv > /dev/null 2>&1 || { echo "Please install virtualenv" && exit ${SYSTEM_PYTHON} -m hashin -h > /dev/null 2>&1 || { ${SYSTEM_PYTHON} -m pip install hashin; } -for i in '' '-hw' '-binaries' '-binaries-mac' '-build-wine' '-build-mac' '-build-sdist' '-build-appimage'; do +for i in '' '-hw' '-binaries' '-binaries-mac' '-build-wine' '-build-mac' '-build-sdist' '-build-appimage' '-build-android'; do rm -rf "$venv_dir" virtualenv -p ${SYSTEM_PYTHON} $venv_dir diff --git a/contrib/make_packages b/contrib/make_packages index 26441447d..6d29044fe 100755 --- a/contrib/make_packages +++ b/contrib/make_packages @@ -1,11 +1,39 @@ #!/bin/bash +# This script installs our pure python dependencies into the 'packages' folder. + +set -e + +CONTRIB="$(dirname "$(readlink -e "$0")")" +PROJECT_ROOT="$CONTRIB"/.. +PACKAGES="$PROJECT_ROOT"/packages/ -CONTRIB="$(dirname "$0")" test -n "$CONTRIB" -a -d "$CONTRIB" || exit -rm "$CONTRIB"/../packages/ -r +if [ -d "$PACKAGES" ]; then + rm -r "$PACKAGES" +fi + +# opt out of compiling C extensions +# FIXME aiohttp opt-out is not released yet: https://github.com/aio-libs/aiohttp/pull/3828 +export AIOHTTP_NO_EXTENSIONS=1 +export YARL_NO_EXTENSIONS=1 +export MULTIDICT_NO_EXTENSIONS=1 + +# if we end up having to compile something, at least give reproducibility a fighting chance +export LC_ALL=C +export TZ=UTC +export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)" +export PYTHONHASHSEED="$SOURCE_DATE_EPOCH" +export BUILD_DATE="$(LC_ALL=C TZ=UTC date +'%b %e %Y' -d @$SOURCE_DATE_EPOCH)" +export BUILD_TIME="$(LC_ALL=C TZ=UTC date +'%H:%M:%S' -d @$SOURCE_DATE_EPOCH)" -#Install pure python modules in electrum directory -python3 -m pip install --no-dependencies --no-binary :all: \ +# FIXME aiohttp will compile some .so files using distutils +# (until https://github.com/aio-libs/aiohttp/pull/4079 gets released), +# which are not reproducible unless using at least python 3.9 +# (as it needs https://github.com/python/cpython/commit/0d30ae1a03102de07758650af9243fd31211325a). +# Hence "aiohttp-*.dist-info/" is not reproducible either. +# All this means that downstream users of this script, such as the sdist build +# and the android apk build need to make sure these files get excluded. +python3 -m pip install --no-compile --no-dependencies --no-binary :all: \ -r "$CONTRIB"/deterministic-build/requirements.txt -t "$CONTRIB"/../packages diff --git a/contrib/requirements/requirements-build-android.txt b/contrib/requirements/requirements-build-android.txt new file mode 100644 index 000000000..2f579ede2 --- /dev/null +++ b/contrib/requirements/requirements-build-android.txt @@ -0,0 +1,18 @@ +pip +setuptools +wheel +cython + +# needed by buildozer: +pexpect +virtualenv +sh + +# needed by python-for-android: +appdirs +colorama>=0.3.3 +jinja2 +six +sh>=1.10 +pep517<0.7.0 +toml diff --git a/electrum/gui/kivy/theming/atlas b/electrum/gui/kivy/theming/atlas new file mode 160000 index 000000000..a608a3672 --- /dev/null +++ b/electrum/gui/kivy/theming/atlas @@ -0,0 +1 @@ +Subproject commit a608a36722ee5765009322fe6765507e2c6e6efe diff --git a/electrum/gui/kivy/theming/atlas/.gitkeep b/electrum/gui/kivy/theming/atlas/.gitkeep deleted file mode 100644 index e69de29bb..000000000