Browse Source

Merge pull request #7263 from SomberNight/202104_android

reproducible build for Android apk
patch-4
ghost43 4 years ago
committed by GitHub
parent
commit
c43896fe6a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .gitignore
  2. 3
      .gitmodules
  3. 4
      .travis.yml
  4. 39
      contrib/android/Dockerfile
  5. 9
      contrib/android/Makefile
  6. 69
      contrib/android/Readme.md
  7. 78
      contrib/android/apkdiff.py
  8. 10
      contrib/android/build_docker_image.sh
  9. 28
      contrib/android/buildozer.spec
  10. 47
      contrib/android/make_apk
  11. 10
      contrib/android/p4a_recipes/README.md
  12. 15
      contrib/android/p4a_recipes/certifi/__init__.py
  13. 18
      contrib/android/p4a_recipes/cffi/__init__.py
  14. 13
      contrib/android/p4a_recipes/cryptography/__init__.py
  15. 18
      contrib/android/p4a_recipes/hostpython3/__init__.py
  16. 18
      contrib/android/p4a_recipes/kivy/__init__.py
  17. 18
      contrib/android/p4a_recipes/libffi/__init__.py
  18. 14
      contrib/android/p4a_recipes/libsecp256k1/__init__.py
  19. 18
      contrib/android/p4a_recipes/openssl/__init__.py
  20. 15
      contrib/android/p4a_recipes/plyer/__init__.py
  21. 13
      contrib/android/p4a_recipes/pycparser/__init__.py
  22. 18
      contrib/android/p4a_recipes/pyjnius/__init__.py
  23. 18
      contrib/android/p4a_recipes/python3/__init__.py
  24. 19
      contrib/android/p4a_recipes/sdl2/__init__.py
  25. 18
      contrib/android/p4a_recipes/sdl2_image/__init__.py
  26. 18
      contrib/android/p4a_recipes/sdl2_mixer/__init__.py
  27. 18
      contrib/android/p4a_recipes/sdl2_ttf/__init__.py
  28. 13
      contrib/android/p4a_recipes/setuptools/__init__.py
  29. 13
      contrib/android/p4a_recipes/six/__init__.py
  30. 18
      contrib/android/p4a_recipes/sqlite3/__init__.py
  31. 12
      contrib/android/p4a_recipes/util.py
  32. 3
      contrib/build-linux/sdist/make_tgz
  33. 153
      contrib/deterministic-build/requirements-build-android.txt
  34. 2
      contrib/freeze_packages.sh
  35. 36
      contrib/make_packages
  36. 18
      contrib/requirements/requirements-build-android.txt
  37. 1
      electrum/gui/kivy/theming/atlas
  38. 0
      electrum/gui/kivy/theming/atlas/.gitkeep

4
.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/

3
.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

4
.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

39
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

9
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

69
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
```

78
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 <pathToFirstApk> <pathToSecondApk>")
sys.exit(1)
ApkDiff().compare(sys.argv[1], sys.argv[2])

10
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"

28
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 =

47
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

10
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.

15
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()

18
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()

13
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()

18
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()

18
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()

18
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()

14
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()

18
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()

15
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()

13
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()

18
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()

18
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()

19
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()

18
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()

18
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()

18
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()

13
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()

13
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()

18
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()

12
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)

3
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

153
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

2
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

36
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

18
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

1
electrum/gui/kivy/theming/atlas

@ -0,0 +1 @@
Subproject commit a608a36722ee5765009322fe6765507e2c6e6efe

0
electrum/gui/kivy/theming/atlas/.gitkeep

Loading…
Cancel
Save