first commit
This commit is contained in:
commit
417e54da96
5696 changed files with 900003 additions and 0 deletions
1243
kivy_venv/lib/python3.11/site-packages/buildozer/__init__.py
Normal file
1243
kivy_venv/lib/python3.11/site-packages/buildozer/__init__.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,4 @@
|
|||
from buildozer.scripts.client import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
452
kivy_venv/lib/python3.11/site-packages/buildozer/default.spec
Normal file
452
kivy_venv/lib/python3.11/site-packages/buildozer/default.spec
Normal file
|
@ -0,0 +1,452 @@
|
|||
[app]
|
||||
|
||||
# (str) Title of your application
|
||||
title = My Application
|
||||
|
||||
# (str) Package name
|
||||
package.name = myapp
|
||||
|
||||
# (str) Package domain (needed for android/ios packaging)
|
||||
package.domain = org.test
|
||||
|
||||
# (str) Source code where the main.py live
|
||||
source.dir = .
|
||||
|
||||
# (list) Source files to include (let empty to include all the files)
|
||||
source.include_exts = py,png,jpg,kv,atlas
|
||||
|
||||
# (list) List of inclusions using pattern matching
|
||||
#source.include_patterns = assets/*,images/*.png
|
||||
|
||||
# (list) Source files to exclude (let empty to not exclude anything)
|
||||
#source.exclude_exts = spec
|
||||
|
||||
# (list) List of directory to exclude (let empty to not exclude anything)
|
||||
#source.exclude_dirs = tests, bin, venv
|
||||
|
||||
# (list) List of exclusions using pattern matching
|
||||
# Do not prefix with './'
|
||||
#source.exclude_patterns = license,images/*/*.jpg
|
||||
|
||||
# (str) Application versioning (method 1)
|
||||
version = 0.1
|
||||
|
||||
# (str) Application versioning (method 2)
|
||||
# version.regex = __version__ = ['"](.*)['"]
|
||||
# version.filename = %(source.dir)s/main.py
|
||||
|
||||
# (list) Application requirements
|
||||
# comma separated e.g. requirements = sqlite3,kivy
|
||||
requirements = python3,kivy
|
||||
|
||||
# (str) Custom source folders for requirements
|
||||
# Sets custom source for any requirements with recipes
|
||||
# requirements.source.kivy = ../../kivy
|
||||
|
||||
# (str) Presplash of the application
|
||||
#presplash.filename = %(source.dir)s/data/presplash.png
|
||||
|
||||
# (str) Icon of the application
|
||||
#icon.filename = %(source.dir)s/data/icon.png
|
||||
|
||||
# (list) Supported orientations
|
||||
# Valid options are: landscape, portrait, portrait-reverse or landscape-reverse
|
||||
orientation = portrait
|
||||
|
||||
# (list) List of service to declare
|
||||
#services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY
|
||||
|
||||
#
|
||||
# OSX Specific
|
||||
#
|
||||
|
||||
#
|
||||
# author = © Copyright Info
|
||||
|
||||
# change the major version of python used by the app
|
||||
osx.python_version = 3
|
||||
|
||||
# Kivy version to use
|
||||
osx.kivy_version = 1.9.1
|
||||
|
||||
#
|
||||
# Android specific
|
||||
#
|
||||
|
||||
# (bool) Indicate if the application should be fullscreen or not
|
||||
fullscreen = 0
|
||||
|
||||
# (string) Presplash background color (for android toolchain)
|
||||
# Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
|
||||
# red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,
|
||||
# darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,
|
||||
# olive, purple, silver, teal.
|
||||
#android.presplash_color = #FFFFFF
|
||||
|
||||
# (string) Presplash animation using Lottie format.
|
||||
# see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/
|
||||
# for general documentation.
|
||||
# Lottie files can be created using various tools, like Adobe After Effect or Synfig.
|
||||
#android.presplash_lottie = "path/to/lottie/file.json"
|
||||
|
||||
# (str) Adaptive icon of the application (used if Android API level is 26+ at runtime)
|
||||
#icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png
|
||||
#icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
|
||||
|
||||
# (list) Permissions
|
||||
# (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)
|
||||
#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)
|
||||
|
||||
# (list) features (adds uses-feature -tags to manifest)
|
||||
#android.features = android.hardware.usb.host
|
||||
|
||||
# (int) Target Android API, should be as high as possible.
|
||||
#android.api = 31
|
||||
|
||||
# (int) Minimum API your APK / AAB will support.
|
||||
#android.minapi = 21
|
||||
|
||||
# (int) Android SDK version to use
|
||||
#android.sdk = 20
|
||||
|
||||
# (str) Android NDK version to use
|
||||
#android.ndk = 23b
|
||||
|
||||
# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
|
||||
#android.ndk_api = 21
|
||||
|
||||
# (bool) Use --private data storage (True) or --dir public storage (False)
|
||||
#android.private_storage = True
|
||||
|
||||
# (str) Android NDK directory (if empty, it will be automatically downloaded.)
|
||||
#android.ndk_path =
|
||||
|
||||
# (str) Android SDK directory (if empty, it will be automatically downloaded.)
|
||||
#android.sdk_path =
|
||||
|
||||
# (str) ANT directory (if empty, it will be automatically downloaded.)
|
||||
#android.ant_path =
|
||||
|
||||
# (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
|
||||
# android.skip_update = False
|
||||
|
||||
# (bool) If True, then automatically accept SDK license
|
||||
# agreements. This is intended for automation only. If set to False,
|
||||
# the default, you will be shown the license when first running
|
||||
# buildozer.
|
||||
# android.accept_sdk_license = False
|
||||
|
||||
# (str) Android entry point, default is ok for Kivy-based app
|
||||
#android.entrypoint = org.kivy.android.PythonActivity
|
||||
|
||||
# (str) Full name including package path of the Java class that implements Android Activity
|
||||
# use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity
|
||||
#android.activity_class_name = org.kivy.android.PythonActivity
|
||||
|
||||
# (str) Extra xml to write directly inside the <manifest> element of AndroidManifest.xml
|
||||
# use that parameter to provide a filename from where to load your custom XML code
|
||||
#android.extra_manifest_xml = ./src/android/extra_manifest.xml
|
||||
|
||||
# (str) Extra xml to write directly inside the <manifest><application> tag of AndroidManifest.xml
|
||||
# use that parameter to provide a filename from where to load your custom XML arguments:
|
||||
#android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml
|
||||
|
||||
# (str) Full name including package path of the Java class that implements Python Service
|
||||
# use that parameter to set custom Java class which extends PythonService
|
||||
#android.service_class_name = org.kivy.android.PythonService
|
||||
|
||||
# (str) Android app theme, default is ok for Kivy-based app
|
||||
# android.apptheme = "@android:style/Theme.NoTitleBar"
|
||||
|
||||
# (list) Pattern to whitelist for the whole project
|
||||
#android.whitelist =
|
||||
|
||||
# (str) Path to a custom whitelist file
|
||||
#android.whitelist_src =
|
||||
|
||||
# (str) Path to a custom blacklist file
|
||||
#android.blacklist_src =
|
||||
|
||||
# (list) List of Java .jar files to add to the libs so that pyjnius can access
|
||||
# their classes. Don't add jars that you do not need, since extra jars can slow
|
||||
# down the build process. Allows wildcards matching, for example:
|
||||
# OUYA-ODK/libs/*.jar
|
||||
#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
|
||||
|
||||
# (list) List of Java files to add to the android project (can be java or a
|
||||
# directory containing the files)
|
||||
#android.add_src =
|
||||
|
||||
# (list) Android AAR archives to add
|
||||
#android.add_aars =
|
||||
|
||||
# (list) Put these files or directories in the apk assets directory.
|
||||
# Either form may be used, and assets need not be in 'source.include_exts'.
|
||||
# 1) android.add_assets = source_asset_relative_path
|
||||
# 2) android.add_assets = source_asset_path:destination_asset_relative_path
|
||||
#android.add_assets =
|
||||
|
||||
# (list) Put these files or directories in the apk res directory.
|
||||
# The option may be used in three ways, the value may contain one or zero ':'
|
||||
# Some examples:
|
||||
# 1) A file to add to resources, legal resource names contain ['a-z','0-9','_']
|
||||
# android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png
|
||||
# 2) A directory, here 'legal_icons' must contain resources of one kind
|
||||
# android.add_resources = legal_icons:drawable
|
||||
# 3) A directory, here 'legal_resources' must contain one or more directories,
|
||||
# each of a resource kind: drawable, xml, etc...
|
||||
# android.add_resources = legal_resources
|
||||
#android.add_resources =
|
||||
|
||||
# (list) Gradle dependencies to add
|
||||
#android.gradle_dependencies =
|
||||
|
||||
# (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies'
|
||||
# contains an 'androidx' package, or any package from Kotlin source.
|
||||
# android.enable_androidx requires android.api >= 28
|
||||
#android.enable_androidx = True
|
||||
|
||||
# (list) add java compile options
|
||||
# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
|
||||
# see https://developer.android.com/studio/write/java8-support for further information
|
||||
# android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"
|
||||
|
||||
# (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}
|
||||
# please enclose in double quotes
|
||||
# e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"
|
||||
#android.add_gradle_repositories =
|
||||
|
||||
# (list) packaging options to add
|
||||
# see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
|
||||
# can be necessary to solve conflicts in gradle_dependencies
|
||||
# please enclose in double quotes
|
||||
# e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"
|
||||
#android.add_packaging_options =
|
||||
|
||||
# (list) Java classes to add as activities to the manifest.
|
||||
#android.add_activities = com.example.ExampleActivity
|
||||
|
||||
# (str) OUYA Console category. Should be one of GAME or APP
|
||||
# If you leave this blank, OUYA support will not be enabled
|
||||
#android.ouya.category = GAME
|
||||
|
||||
# (str) Filename of OUYA Console icon. It must be a 732x412 png image.
|
||||
#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
|
||||
|
||||
# (str) XML file to include as an intent filters in <activity> tag
|
||||
#android.manifest.intent_filters =
|
||||
|
||||
# (list) Copy these files to src/main/res/xml/ (used for example with intent-filters)
|
||||
#android.res_xml = PATH_TO_FILE,
|
||||
|
||||
# (str) launchMode to set for the main activity
|
||||
#android.manifest.launch_mode = standard
|
||||
|
||||
# (str) screenOrientation to set for the main activity.
|
||||
# Valid values can be found at https://developer.android.com/guide/topics/manifest/activity-element
|
||||
#android.manifest.orientation = fullSensor
|
||||
|
||||
# (list) Android additional libraries to copy into libs/armeabi
|
||||
#android.add_libs_armeabi = libs/android/*.so
|
||||
#android.add_libs_armeabi_v7a = libs/android-v7/*.so
|
||||
#android.add_libs_arm64_v8a = libs/android-v8/*.so
|
||||
#android.add_libs_x86 = libs/android-x86/*.so
|
||||
#android.add_libs_mips = libs/android-mips/*.so
|
||||
|
||||
# (bool) Indicate whether the screen should stay on
|
||||
# Don't forget to add the WAKE_LOCK permission if you set this to True
|
||||
#android.wakelock = False
|
||||
|
||||
# (list) Android application meta-data to set (key=value format)
|
||||
#android.meta_data =
|
||||
|
||||
# (list) Android library project to add (will be added in the
|
||||
# project.properties automatically.)
|
||||
#android.library_references =
|
||||
|
||||
# (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag
|
||||
#android.uses_library =
|
||||
|
||||
# (str) Android logcat filters to use
|
||||
#android.logcat_filters = *:S python:D
|
||||
|
||||
# (bool) Android logcat only display log for activity's pid
|
||||
#android.logcat_pid_only = False
|
||||
|
||||
# (str) Android additional adb arguments
|
||||
#android.adb_args = -H host.docker.internal
|
||||
|
||||
# (bool) Copy library instead of making a libpymodules.so
|
||||
#android.copy_libs = 1
|
||||
|
||||
# (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
|
||||
# In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time.
|
||||
android.archs = arm64-v8a, armeabi-v7a
|
||||
|
||||
# (int) overrides automatic versionCode computation (used in build.gradle)
|
||||
# this is not the same as app version and should only be edited if you know what you're doing
|
||||
# android.numeric_version = 1
|
||||
|
||||
# (bool) enables Android auto backup feature (Android API >=23)
|
||||
android.allow_backup = True
|
||||
|
||||
# (str) XML file for custom backup rules (see official auto backup documentation)
|
||||
# android.backup_rules =
|
||||
|
||||
# (str) If you need to insert variables into your AndroidManifest.xml file,
|
||||
# you can do so with the manifestPlaceholders property.
|
||||
# This property takes a map of key-value pairs. (via a string)
|
||||
# Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]
|
||||
# android.manifest_placeholders = [:]
|
||||
|
||||
# (bool) Skip byte compile for .py files
|
||||
# android.no-byte-compile-python = False
|
||||
|
||||
# (str) The format used to package the app for release mode (aab or apk or aar).
|
||||
# android.release_artifact = aab
|
||||
|
||||
# (str) The format used to package the app for debug mode (apk or aar).
|
||||
# android.debug_artifact = apk
|
||||
|
||||
#
|
||||
# Python for android (p4a) specific
|
||||
#
|
||||
|
||||
# (str) python-for-android URL to use for checkout
|
||||
#p4a.url =
|
||||
|
||||
# (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)
|
||||
#p4a.fork = kivy
|
||||
|
||||
# (str) python-for-android branch to use, defaults to master
|
||||
#p4a.branch = master
|
||||
|
||||
# (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch
|
||||
#p4a.commit = HEAD
|
||||
|
||||
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
|
||||
#p4a.source_dir =
|
||||
|
||||
# (str) The directory in which python-for-android should look for your own build recipes (if any)
|
||||
#p4a.local_recipes =
|
||||
|
||||
# (str) Filename to the hook for p4a
|
||||
#p4a.hook =
|
||||
|
||||
# (str) Bootstrap to use for android builds
|
||||
# p4a.bootstrap = sdl2
|
||||
|
||||
# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)
|
||||
#p4a.port =
|
||||
|
||||
# Control passing the --use-setup-py vs --ignore-setup-py to p4a
|
||||
# "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not
|
||||
# Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py
|
||||
# NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate
|
||||
# setup.py if you're using Poetry, but you need to add "toml" to source.include_exts.
|
||||
#p4a.setup_py = false
|
||||
|
||||
# (str) extra command line arguments to pass when invoking pythonforandroid.toolchain
|
||||
#p4a.extra_args =
|
||||
|
||||
|
||||
|
||||
#
|
||||
# iOS specific
|
||||
#
|
||||
|
||||
# (str) Path to a custom kivy-ios folder
|
||||
#ios.kivy_ios_dir = ../kivy-ios
|
||||
# Alternately, specify the URL and branch of a git checkout:
|
||||
ios.kivy_ios_url = https://github.com/kivy/kivy-ios
|
||||
ios.kivy_ios_branch = master
|
||||
|
||||
# Another platform dependency: ios-deploy
|
||||
# Uncomment to use a custom checkout
|
||||
#ios.ios_deploy_dir = ../ios_deploy
|
||||
# Or specify URL and branch
|
||||
ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
|
||||
ios.ios_deploy_branch = 1.10.0
|
||||
|
||||
# (bool) Whether or not to sign the code
|
||||
ios.codesign.allowed = false
|
||||
|
||||
# (str) Name of the certificate to use for signing the debug version
|
||||
# Get a list of available identities: buildozer ios list_identities
|
||||
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
|
||||
|
||||
# (str) The development team to use for signing the debug version
|
||||
#ios.codesign.development_team.debug = <hexstring>
|
||||
|
||||
# (str) Name of the certificate to use for signing the release version
|
||||
#ios.codesign.release = %(ios.codesign.debug)s
|
||||
|
||||
# (str) The development team to use for signing the release version
|
||||
#ios.codesign.development_team.release = <hexstring>
|
||||
|
||||
# (str) URL pointing to .ipa file to be installed
|
||||
# This option should be defined along with `display_image_url` and `full_size_image_url` options.
|
||||
#ios.manifest.app_url =
|
||||
|
||||
# (str) URL pointing to an icon (57x57px) to be displayed during download
|
||||
# This option should be defined along with `app_url` and `full_size_image_url` options.
|
||||
#ios.manifest.display_image_url =
|
||||
|
||||
# (str) URL pointing to a large icon (512x512px) to be used by iTunes
|
||||
# This option should be defined along with `app_url` and `display_image_url` options.
|
||||
#ios.manifest.full_size_image_url =
|
||||
|
||||
|
||||
[buildozer]
|
||||
|
||||
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
|
||||
log_level = 2
|
||||
|
||||
# (int) Display warning if buildozer is run as root (0 = False, 1 = True)
|
||||
warn_on_root = 1
|
||||
|
||||
# (str) Path to build artifact storage, absolute or relative to spec file
|
||||
# build_dir = ./.buildozer
|
||||
|
||||
# (str) Path to build output (i.e. .apk, .aab, .ipa) storage
|
||||
# bin_dir = ./bin
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# List as sections
|
||||
#
|
||||
# You can define all the "list" as [section:key].
|
||||
# Each line will be considered as a option to the list.
|
||||
# Let's take [app] / source.exclude_patterns.
|
||||
# Instead of doing:
|
||||
#
|
||||
#[app]
|
||||
#source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
|
||||
#
|
||||
# This can be translated into:
|
||||
#
|
||||
#[app:source.exclude_patterns]
|
||||
#license
|
||||
#data/audio/*.wav
|
||||
#data/images/original/*
|
||||
#
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Profiles
|
||||
#
|
||||
# You can extend section / key with a profile
|
||||
# For example, you want to deploy a demo version of your application without
|
||||
# HD content. You could first change the title to add "(demo)" in the name
|
||||
# and extend the excluded directories to remove the HD content.
|
||||
#
|
||||
#[app@demo]
|
||||
#title = My Application (demo)
|
||||
#
|
||||
#[app:source.exclude_patterns@demo]
|
||||
#images/hd/*
|
||||
#
|
||||
# Then, invoke the command line with the "demo" profile:
|
||||
#
|
||||
#buildozer --profile demo android debug
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
Replacement for shelve, using json.
|
||||
This was needed to correctly support db between Python 2 and 3.
|
||||
"""
|
||||
|
||||
__all__ = ["JsonStore"]
|
||||
|
||||
import io
|
||||
from json import load, dump
|
||||
from os.path import exists
|
||||
|
||||
|
||||
class JsonStore:
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.data = {}
|
||||
if exists(filename):
|
||||
try:
|
||||
with io.open(filename, encoding='utf-8') as fd:
|
||||
self.data = load(fd)
|
||||
except ValueError:
|
||||
print("Unable to read the state.db, content will be replaced.")
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.data[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.data[key] = value
|
||||
self.sync()
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self.data[key]
|
||||
self.sync()
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.data
|
||||
|
||||
def get(self, item, default=None):
|
||||
return self.data.get(item, default)
|
||||
|
||||
def keys(self):
|
||||
return self.data.keys()
|
||||
|
||||
def sync(self):
|
||||
with open(self.filename, 'w') as fd:
|
||||
dump(self.data, fd, ensure_ascii=False)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,78 @@
|
|||
# Copyright 2014 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
class Infinity:
|
||||
|
||||
def __repr__(self):
|
||||
return "Infinity"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __lt__(self, other):
|
||||
return False
|
||||
|
||||
def __le__(self, other):
|
||||
return False
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not isinstance(other, self.__class__)
|
||||
|
||||
def __gt__(self, other):
|
||||
return True
|
||||
|
||||
def __ge__(self, other):
|
||||
return True
|
||||
|
||||
def __neg__(self):
|
||||
return NegativeInfinity
|
||||
|
||||
|
||||
Infinity = Infinity()
|
||||
|
||||
|
||||
class NegativeInfinity:
|
||||
|
||||
def __repr__(self):
|
||||
return "-Infinity"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __lt__(self, other):
|
||||
return True
|
||||
|
||||
def __le__(self, other):
|
||||
return True
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not isinstance(other, self.__class__)
|
||||
|
||||
def __gt__(self, other):
|
||||
return False
|
||||
|
||||
def __ge__(self, other):
|
||||
return False
|
||||
|
||||
def __neg__(self):
|
||||
return Infinity
|
||||
|
||||
|
||||
NegativeInfinity = NegativeInfinity()
|
400
kivy_venv/lib/python3.11/site-packages/buildozer/libs/version.py
Normal file
400
kivy_venv/lib/python3.11/site-packages/buildozer/libs/version.py
Normal file
|
@ -0,0 +1,400 @@
|
|||
# Copyright 2014 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import collections
|
||||
import itertools
|
||||
import re
|
||||
|
||||
from ._structures import Infinity
|
||||
|
||||
|
||||
__all__ = [
|
||||
"parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
|
||||
]
|
||||
|
||||
|
||||
_Version = collections.namedtuple(
|
||||
"_Version",
|
||||
["epoch", "release", "dev", "pre", "post", "local"],
|
||||
)
|
||||
|
||||
|
||||
def parse(version):
|
||||
"""
|
||||
Parse the given version string and return either a :class:`Version` object
|
||||
or a :class:`LegacyVersion` object depending on if the given version is
|
||||
a valid PEP 440 version or a legacy version.
|
||||
"""
|
||||
try:
|
||||
return Version(version)
|
||||
except InvalidVersion:
|
||||
return LegacyVersion(version)
|
||||
|
||||
|
||||
class InvalidVersion(ValueError):
|
||||
"""
|
||||
An invalid version was found, users should refer to PEP 440.
|
||||
"""
|
||||
|
||||
|
||||
class _BaseVersion:
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._key)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._compare(other, lambda s, o: s < o)
|
||||
|
||||
def __le__(self, other):
|
||||
return self._compare(other, lambda s, o: s <= o)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._compare(other, lambda s, o: s == o)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._compare(other, lambda s, o: s >= o)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._compare(other, lambda s, o: s > o)
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._compare(other, lambda s, o: s != o)
|
||||
|
||||
def _compare(self, other, method):
|
||||
if not isinstance(other, _BaseVersion):
|
||||
return NotImplemented
|
||||
|
||||
return method(self._key, other._key)
|
||||
|
||||
|
||||
class LegacyVersion(_BaseVersion):
|
||||
|
||||
def __init__(self, version):
|
||||
self._version = str(version)
|
||||
self._key = _legacy_cmpkey(self._version)
|
||||
|
||||
def __str__(self):
|
||||
return self._version
|
||||
|
||||
def __repr__(self):
|
||||
return "<LegacyVersion({0})>".format(repr(str(self)))
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def base_version(self):
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_prerelease(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_postrelease(self):
|
||||
return False
|
||||
|
||||
|
||||
_legacy_version_component_re = re.compile(
|
||||
r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
|
||||
)
|
||||
|
||||
_legacy_version_replacement_map = {
|
||||
"pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
|
||||
}
|
||||
|
||||
|
||||
def _parse_version_parts(s):
|
||||
for part in _legacy_version_component_re.split(s):
|
||||
part = _legacy_version_replacement_map.get(part, part)
|
||||
|
||||
if not part or part == ".":
|
||||
continue
|
||||
|
||||
if part[:1] in "0123456789":
|
||||
# pad for numeric comparison
|
||||
yield part.zfill(8)
|
||||
else:
|
||||
yield "*" + part
|
||||
|
||||
# ensure that alpha/beta/candidate are before final
|
||||
yield "*final"
|
||||
|
||||
|
||||
def _legacy_cmpkey(version):
|
||||
# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
|
||||
# greater than or equal to 0. This will effectively put the LegacyVersion,
|
||||
# which uses the defacto standard originally implemented by setuptools,
|
||||
# as before all PEP 440 versions.
|
||||
epoch = -1
|
||||
|
||||
# This scheme is taken from pkg_resources.parse_version setuptools prior to
|
||||
# it's adoption of the packaging library.
|
||||
parts = []
|
||||
for part in _parse_version_parts(version.lower()):
|
||||
if part.startswith("*"):
|
||||
# remove "-" before a prerelease tag
|
||||
if part < "*final":
|
||||
while parts and parts[-1] == "*final-":
|
||||
parts.pop()
|
||||
|
||||
# remove trailing zeros from each series of numeric parts
|
||||
while parts and parts[-1] == "00000000":
|
||||
parts.pop()
|
||||
|
||||
parts.append(part)
|
||||
parts = tuple(parts)
|
||||
|
||||
return epoch, parts
|
||||
|
||||
|
||||
# Deliberately not anchored to the start and end of the string, to make it
|
||||
# easier for 3rd party code to reuse
|
||||
VERSION_PATTERN = r"""
|
||||
v?
|
||||
(?:
|
||||
(?:(?P<epoch>[0-9]+)!)? # epoch
|
||||
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
|
||||
(?P<pre> # pre-release
|
||||
[-_\.]?
|
||||
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
|
||||
[-_\.]?
|
||||
(?P<pre_n>[0-9]+)?
|
||||
)?
|
||||
(?P<post> # post release
|
||||
(?:-(?P<post_n1>[0-9]+))
|
||||
|
|
||||
(?:
|
||||
[-_\.]?
|
||||
(?P<post_l>post|rev|r)
|
||||
[-_\.]?
|
||||
(?P<post_n2>[0-9]+)?
|
||||
)
|
||||
)?
|
||||
(?P<dev> # dev release
|
||||
[-_\.]?
|
||||
(?P<dev_l>dev)
|
||||
[-_\.]?
|
||||
(?P<dev_n>[0-9]+)?
|
||||
)?
|
||||
)
|
||||
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
|
||||
"""
|
||||
|
||||
|
||||
class Version(_BaseVersion):
|
||||
|
||||
_regex = re.compile(
|
||||
r"^\s*" + VERSION_PATTERN + r"\s*$",
|
||||
re.VERBOSE | re.IGNORECASE,
|
||||
)
|
||||
|
||||
def __init__(self, version):
|
||||
# Validate the version and parse it into pieces
|
||||
match = self._regex.search(version)
|
||||
if not match:
|
||||
raise InvalidVersion("Invalid version: '{0}'".format(version))
|
||||
|
||||
# Store the parsed out pieces of the version
|
||||
self._version = _Version(
|
||||
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
|
||||
release=tuple(int(i) for i in match.group("release").split(".")),
|
||||
pre=_parse_letter_version(
|
||||
match.group("pre_l"),
|
||||
match.group("pre_n"),
|
||||
),
|
||||
post=_parse_letter_version(
|
||||
match.group("post_l"),
|
||||
match.group("post_n1") or match.group("post_n2"),
|
||||
),
|
||||
dev=_parse_letter_version(
|
||||
match.group("dev_l"),
|
||||
match.group("dev_n"),
|
||||
),
|
||||
local=_parse_local_version(match.group("local")),
|
||||
)
|
||||
|
||||
# Generate a key which will be used for sorting
|
||||
self._key = _cmpkey(
|
||||
self._version.epoch,
|
||||
self._version.release,
|
||||
self._version.pre,
|
||||
self._version.post,
|
||||
self._version.dev,
|
||||
self._version.local,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Version({0})>".format(repr(str(self)))
|
||||
|
||||
def __str__(self):
|
||||
parts = []
|
||||
|
||||
# Epoch
|
||||
if self._version.epoch != 0:
|
||||
parts.append("{0}!".format(self._version.epoch))
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self._version.release))
|
||||
|
||||
# Pre-release
|
||||
if self._version.pre is not None:
|
||||
parts.append("-" + "".join(str(x) for x in self._version.pre))
|
||||
|
||||
# Post-release
|
||||
if self._version.post is not None:
|
||||
parts.append(".post{0}".format(self._version.post[1]))
|
||||
|
||||
# Development release
|
||||
if self._version.dev is not None:
|
||||
parts.append(".dev{0}".format(self._version.dev[1]))
|
||||
|
||||
# Local version segment
|
||||
if self._version.local is not None:
|
||||
parts.append(
|
||||
"+{0}".format(".".join(str(x) for x in self._version.local))
|
||||
)
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
return str(self).split("+", 1)[0]
|
||||
|
||||
@property
|
||||
def base_version(self):
|
||||
parts = []
|
||||
|
||||
# Epoch
|
||||
if self._version.epoch != 0:
|
||||
parts.append("{0}!".format(self._version.epoch))
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self._version.release))
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
version_string = str(self)
|
||||
if "+" in version_string:
|
||||
return version_string.split("+", 1)[1]
|
||||
|
||||
@property
|
||||
def is_prerelease(self):
|
||||
return bool(self._version.dev or self._version.pre)
|
||||
|
||||
@property
|
||||
def is_postrelease(self):
|
||||
return bool(self._version.post)
|
||||
|
||||
|
||||
def _parse_letter_version(letter, number):
|
||||
if letter:
|
||||
# We consider there to be an implicit 0 in a pre-release if there is
|
||||
# not a numeral associated with it.
|
||||
if number is None:
|
||||
number = 0
|
||||
|
||||
# We normalize any letters to their lower case form
|
||||
letter = letter.lower()
|
||||
|
||||
# We consider some words to be alternate spellings of other words and
|
||||
# in those cases we want to normalize the spellings to our preferred
|
||||
# spelling.
|
||||
if letter == "alpha":
|
||||
letter = "a"
|
||||
elif letter == "beta":
|
||||
letter = "b"
|
||||
elif letter in ["c", "pre", "preview"]:
|
||||
letter = "rc"
|
||||
|
||||
return letter, int(number)
|
||||
if not letter and number:
|
||||
# We assume if we are given a number, but we are not given a letter
|
||||
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||
letter = "post"
|
||||
|
||||
return letter, int(number)
|
||||
|
||||
|
||||
_local_version_separators = re.compile(r"[\._-]")
|
||||
|
||||
|
||||
def _parse_local_version(local):
|
||||
"""
|
||||
Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
|
||||
"""
|
||||
if local is not None:
|
||||
return tuple(
|
||||
part.lower() if not part.isdigit() else int(part)
|
||||
for part in _local_version_separators.split(local)
|
||||
)
|
||||
|
||||
|
||||
def _cmpkey(epoch, release, pre, post, dev, local):
|
||||
# When we compare a release version, we want to compare it with all of the
|
||||
# trailing zeros removed. So we'll use a reverse the list, drop all the now
|
||||
# leading zeros until we come to something non zero, then take the rest
|
||||
# re-reverse it back into the correct order and make it a tuple and use
|
||||
# that for our sorting key.
|
||||
release = tuple(
|
||||
reversed(list(
|
||||
itertools.dropwhile(
|
||||
lambda x: x == 0,
|
||||
reversed(release),
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
||||
# We'll do this by abusing the pre segment, but we _only_ want to do this
|
||||
# if there is not a pre or a post segment. If we have one of those then
|
||||
# the normal sorting rules will handle this case correctly.
|
||||
if pre is None and post is None and dev is not None:
|
||||
pre = -Infinity
|
||||
# Versions without a pre-release (except as noted above) should sort after
|
||||
# those with one.
|
||||
elif pre is None:
|
||||
pre = Infinity
|
||||
|
||||
# Versions without a post segment should sort before those with one.
|
||||
if post is None:
|
||||
post = -Infinity
|
||||
|
||||
# Versions without a development segment should sort after those with one.
|
||||
if dev is None:
|
||||
dev = Infinity
|
||||
|
||||
if local is None:
|
||||
# Versions without a local segment should sort before those with one.
|
||||
local = -Infinity
|
||||
else:
|
||||
# Versions with a local segment need that segment parsed to implement
|
||||
# the sorting rules in PEP440.
|
||||
# - Alpha numeric segments sort before numeric segments
|
||||
# - Alpha numeric segments sort lexicographically
|
||||
# - Numeric segments sort numerically
|
||||
# - Shorter versions sort before longer versions when the prefixes
|
||||
# match exactly
|
||||
local = tuple(
|
||||
(i, "") if isinstance(i, int) else (-Infinity, i)
|
||||
for i in local
|
||||
)
|
||||
|
||||
return epoch, release, pre, post, dev, local
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,24 @@
|
|||
'''
|
||||
Main Buildozer client
|
||||
=====================
|
||||
|
||||
'''
|
||||
|
||||
import sys
|
||||
from buildozer import Buildozer, BuildozerCommandException, BuildozerException
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
Buildozer().run_command(sys.argv[1:])
|
||||
except BuildozerCommandException:
|
||||
# don't show the exception in the command line. The log already show
|
||||
# the command failed.
|
||||
sys.exit(1)
|
||||
except BuildozerException as error:
|
||||
Buildozer().error('%s' % error)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,278 @@
|
|||
'''
|
||||
Buildozer remote
|
||||
================
|
||||
|
||||
.. warning::
|
||||
|
||||
This is an experimental tool and not widely used. It might not fit for you.
|
||||
|
||||
Pack and send the source code to a remote SSH server, bundle buildozer with it,
|
||||
and start the build on the remote.
|
||||
You need paramiko to make it work.
|
||||
'''
|
||||
|
||||
__all__ = ["BuildozerRemote"]
|
||||
|
||||
import socket
|
||||
import sys
|
||||
from buildozer import (
|
||||
Buildozer, BuildozerCommandException, BuildozerException, __version__)
|
||||
from sys import stdout, stdin, exit
|
||||
from select import select
|
||||
from os.path import join, expanduser, realpath, exists, splitext
|
||||
from os import makedirs, walk, getcwd
|
||||
from configparser import ConfigParser
|
||||
try:
|
||||
import termios
|
||||
has_termios = True
|
||||
except ImportError:
|
||||
has_termios = False
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
print('Paramiko missing: pip install paramiko')
|
||||
|
||||
|
||||
class BuildozerRemote(Buildozer):
|
||||
def run_command(self, args):
|
||||
while args:
|
||||
if not args[0].startswith('-'):
|
||||
break
|
||||
arg = args.pop(0)
|
||||
|
||||
if arg in ('-v', '--verbose'):
|
||||
self.log_level = 2
|
||||
|
||||
elif arg in ('-p', '--profile'):
|
||||
self.config_profile = args.pop(0)
|
||||
|
||||
elif arg in ('-h', '--help'):
|
||||
self.usage()
|
||||
exit(0)
|
||||
|
||||
elif arg == '--version':
|
||||
print('Buildozer (remote) {0}'.format(__version__))
|
||||
exit(0)
|
||||
|
||||
self._merge_config_profile()
|
||||
|
||||
if len(args) < 2:
|
||||
self.usage()
|
||||
return
|
||||
|
||||
remote_name = args[0]
|
||||
remote_section = 'remote:{}'.format(remote_name)
|
||||
if not self.config.has_section(remote_section):
|
||||
self.error('Unknown remote "{}", must be configured first.'.format(
|
||||
remote_name))
|
||||
return
|
||||
|
||||
self.remote_host = remote_host = self.config.get(
|
||||
remote_section, 'host', '')
|
||||
self.remote_port = self.config.get(
|
||||
remote_section, 'port', '22')
|
||||
self.remote_user = remote_user = self.config.get(
|
||||
remote_section, 'user', '')
|
||||
self.remote_build_dir = remote_build_dir = self.config.get(
|
||||
remote_section, 'build_directory', '')
|
||||
self.remote_identity = self.config.get(
|
||||
remote_section, 'identity', '')
|
||||
if not remote_host:
|
||||
self.error('Missing "host = " for {}'.format(remote_section))
|
||||
return
|
||||
if not remote_user:
|
||||
self.error('Missing "user = " for {}'.format(remote_section))
|
||||
return
|
||||
if not remote_build_dir:
|
||||
self.error('Missing "build_directory = " for {}'.format(remote_section))
|
||||
return
|
||||
|
||||
# fake the target
|
||||
self.targetname = 'remote'
|
||||
self.check_build_layout()
|
||||
|
||||
# prepare our source code
|
||||
self.info('Prepare source code to sync')
|
||||
self._copy_application_sources()
|
||||
self._ssh_connect()
|
||||
try:
|
||||
self._ensure_buildozer()
|
||||
self._sync_application_sources()
|
||||
self._do_remote_commands(args[1:])
|
||||
self._ssh_sync(getcwd(), mode='get')
|
||||
finally:
|
||||
self._ssh_close()
|
||||
|
||||
def _ssh_connect(self):
|
||||
self.info('Connecting to {}'.format(self.remote_host))
|
||||
self._ssh_client = client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
client.load_system_host_keys()
|
||||
kwargs = {}
|
||||
if self.remote_identity:
|
||||
kwargs['key_filename'] = expanduser(self.remote_identity)
|
||||
client.connect(self.remote_host, username=self.remote_user,
|
||||
port=int(self.remote_port), **kwargs)
|
||||
self._sftp_client = client.open_sftp()
|
||||
|
||||
def _ssh_close(self):
|
||||
self.debug('Closing remote connection')
|
||||
self._sftp_client.close()
|
||||
self._ssh_client.close()
|
||||
|
||||
def _ensure_buildozer(self):
|
||||
s = self._sftp_client
|
||||
root_dir = s.normalize('.')
|
||||
self.remote_build_dir = join(root_dir, self.remote_build_dir,
|
||||
self.package_full_name)
|
||||
self.debug('Remote build directory: {}'.format(self.remote_build_dir))
|
||||
self._ssh_mkdir(self.remote_build_dir)
|
||||
self._ssh_sync(__path__[0]) # noqa: F821 undefined name
|
||||
|
||||
def _sync_application_sources(self):
|
||||
self.info('Synchronize application sources')
|
||||
self._ssh_sync(self.app_dir)
|
||||
|
||||
# create custom buildozer.spec
|
||||
self.info('Create custom buildozer.spec')
|
||||
config = ConfigParser()
|
||||
config.read('buildozer.spec')
|
||||
config.set('app', 'source.dir', 'app')
|
||||
|
||||
fn = join(self.remote_build_dir, 'buildozer.spec')
|
||||
fd = self._sftp_client.open(fn, 'wb')
|
||||
config.write(fd)
|
||||
fd.close()
|
||||
|
||||
def _do_remote_commands(self, args):
|
||||
self.info('Execute remote buildozer')
|
||||
cmd = (
|
||||
'source ~/.profile;'
|
||||
'cd {0};'
|
||||
'env PYTHONPATH={0}:$PYTHONPATH '
|
||||
'python -c "import buildozer, sys;'
|
||||
'buildozer.Buildozer().run_command(sys.argv[1:])" {1} {2} 2>&1').format(
|
||||
self.remote_build_dir,
|
||||
'--verbose' if self.log_level == 2 else '',
|
||||
' '.join(args),
|
||||
)
|
||||
self._ssh_command(cmd)
|
||||
|
||||
def _ssh_mkdir(self, *args):
|
||||
directory = join(*args)
|
||||
self.debug('Create remote directory {}'.format(directory))
|
||||
try:
|
||||
self._sftp_client.mkdir(directory)
|
||||
except IOError:
|
||||
# already created?
|
||||
try:
|
||||
self._sftp_client.stat(directory)
|
||||
except IOError:
|
||||
self.error('Unable to create remote directory {}'.format(directory))
|
||||
raise
|
||||
|
||||
def _ssh_sync(self, directory, mode='put'):
|
||||
self.debug('Syncing {} directory'.format(directory))
|
||||
directory = realpath(expanduser(directory))
|
||||
base_strip = directory.rfind('/')
|
||||
if mode == 'get':
|
||||
local_dir = join(directory, 'bin')
|
||||
remote_dir = join(self.remote_build_dir, 'bin')
|
||||
if not exists(local_dir):
|
||||
makedirs(local_dir)
|
||||
for _file in self._sftp_client.listdir(path=remote_dir):
|
||||
self._sftp_client.get(join(remote_dir, _file),
|
||||
join(local_dir, _file))
|
||||
return
|
||||
for root, dirs, files in walk(directory):
|
||||
self._ssh_mkdir(self.remote_build_dir, root[base_strip + 1:])
|
||||
for fn in files:
|
||||
if splitext(fn)[1] in ('.pyo', '.pyc', '.swp'):
|
||||
continue
|
||||
local_file = join(root, fn)
|
||||
remote_file = join(self.remote_build_dir, root[base_strip + 1:], fn)
|
||||
self.debug('Sync {} -> {}'.format(local_file, remote_file))
|
||||
self._sftp_client.put(local_file, remote_file)
|
||||
|
||||
def _ssh_command(self, command):
|
||||
self.debug('Execute remote command {}'.format(command))
|
||||
transport = self._ssh_client.get_transport()
|
||||
channel = transport.open_session()
|
||||
try:
|
||||
channel.exec_command(command)
|
||||
self._interactive_shell(channel)
|
||||
finally:
|
||||
channel.close()
|
||||
|
||||
def _interactive_shell(self, chan):
|
||||
if has_termios:
|
||||
self._posix_shell(chan)
|
||||
else:
|
||||
self._windows_shell(chan)
|
||||
|
||||
def _posix_shell(self, chan):
|
||||
oldtty = termios.tcgetattr(stdin)
|
||||
try:
|
||||
chan.settimeout(0.0)
|
||||
|
||||
while True:
|
||||
r, w, e = select([chan, stdin], [], [])
|
||||
if chan in r:
|
||||
try:
|
||||
x = chan.recv(128)
|
||||
if len(x) == 0:
|
||||
print('\r\n*** EOF\r\n',)
|
||||
break
|
||||
stdout.write(x)
|
||||
stdout.flush()
|
||||
except socket.timeout:
|
||||
pass
|
||||
if stdin in r:
|
||||
x = stdin.read(1)
|
||||
if len(x) == 0:
|
||||
break
|
||||
chan.sendall(x)
|
||||
finally:
|
||||
termios.tcsetattr(stdin, termios.TCSADRAIN, oldtty)
|
||||
|
||||
# thanks to Mike Looijmans for this code
|
||||
def _windows_shell(self, chan):
|
||||
import threading
|
||||
|
||||
stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
|
||||
|
||||
def writeall(sock):
|
||||
while True:
|
||||
data = sock.recv(256)
|
||||
if not data:
|
||||
stdout.write('\r\n*** EOF ***\r\n\r\n')
|
||||
stdout.flush()
|
||||
break
|
||||
stdout.write(data)
|
||||
stdout.flush()
|
||||
|
||||
writer = threading.Thread(target=writeall, args=(chan,))
|
||||
writer.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
d = stdin.read(1)
|
||||
if not d:
|
||||
break
|
||||
chan.send(d)
|
||||
except EOFError:
|
||||
# user hit ^Z or F6
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
BuildozerRemote().run_command(sys.argv[1:])
|
||||
except BuildozerCommandException:
|
||||
pass
|
||||
except BuildozerException as error:
|
||||
Buildozer().error('%s' % error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,3 @@
|
|||
from os.path import join, dirname
|
||||
import sys
|
||||
sys.path.append(join(dirname(__file__), '_applibs'))
|
263
kivy_venv/lib/python3.11/site-packages/buildozer/target.py
Normal file
263
kivy_venv/lib/python3.11/site-packages/buildozer/target.py
Normal file
|
@ -0,0 +1,263 @@
|
|||
from sys import exit
|
||||
import os
|
||||
from os.path import join
|
||||
|
||||
|
||||
def no_config(f):
|
||||
f.__no_config = True
|
||||
return f
|
||||
|
||||
|
||||
class Target:
|
||||
def __init__(self, buildozer):
|
||||
self.buildozer = buildozer
|
||||
self.build_mode = 'debug'
|
||||
self.artifact_format = 'apk'
|
||||
self.platform_update = False
|
||||
|
||||
def check_requirements(self):
|
||||
pass
|
||||
|
||||
def check_configuration_tokens(self, errors=None):
|
||||
if errors:
|
||||
self.buildozer.info('Check target configuration tokens')
|
||||
self.buildozer.error(
|
||||
'{0} error(s) found in the buildozer.spec'.format(
|
||||
len(errors)))
|
||||
for error in errors:
|
||||
print(error)
|
||||
exit(1)
|
||||
|
||||
def compile_platform(self):
|
||||
pass
|
||||
|
||||
def install_platform(self):
|
||||
pass
|
||||
|
||||
def get_custom_commands(self):
|
||||
result = []
|
||||
for x in dir(self):
|
||||
if not x.startswith('cmd_'):
|
||||
continue
|
||||
if x[4:] in self.buildozer.standard_cmds:
|
||||
continue
|
||||
result.append((x[4:], getattr(self, x).__doc__))
|
||||
return result
|
||||
|
||||
def get_available_packages(self):
|
||||
return ['kivy']
|
||||
|
||||
def run_commands(self, args):
|
||||
if not args:
|
||||
self.buildozer.error('Missing target command')
|
||||
self.buildozer.usage()
|
||||
exit(1)
|
||||
|
||||
result = []
|
||||
last_command = []
|
||||
while args:
|
||||
arg = args.pop(0)
|
||||
if arg == '--':
|
||||
if last_command:
|
||||
last_command += args
|
||||
break
|
||||
elif not arg.startswith('--'):
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
last_command = []
|
||||
last_command.append(arg)
|
||||
else:
|
||||
if not last_command:
|
||||
self.buildozer.error('Argument passed without a command')
|
||||
self.buildozer.usage()
|
||||
exit(1)
|
||||
last_command.append(arg)
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
|
||||
config_check = False
|
||||
|
||||
for item in result:
|
||||
command, args = item[0], item[1:]
|
||||
if not hasattr(self, 'cmd_{0}'.format(command)):
|
||||
self.buildozer.error('Unknown command {0}'.format(command))
|
||||
exit(1)
|
||||
|
||||
func = getattr(self, 'cmd_{0}'.format(command))
|
||||
|
||||
need_config_check = not hasattr(func, '__no_config')
|
||||
if need_config_check and not config_check:
|
||||
config_check = True
|
||||
self.check_configuration_tokens()
|
||||
|
||||
func(args)
|
||||
|
||||
def cmd_clean(self, *args):
|
||||
self.buildozer.clean_platform()
|
||||
|
||||
def cmd_update(self, *args):
|
||||
self.platform_update = True
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_debug(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
self.build_mode = 'debug'
|
||||
self.artifact_format = self.buildozer.config.getdefault('app', 'android.debug_artifact', 'apk')
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_release(self, *args):
|
||||
error = self.buildozer.error
|
||||
self.buildozer.prepare_for_build()
|
||||
if self.buildozer.config.get("app", "package.domain") == "org.test":
|
||||
error("")
|
||||
error("ERROR: Trying to release a package that starts with org.test")
|
||||
error("")
|
||||
error("The package.domain org.test is, as the name intented, a test.")
|
||||
error("Once you published an application with org.test,")
|
||||
error("you cannot change it, it will be part of the identifier")
|
||||
error("for Google Play / App Store / etc.")
|
||||
error("")
|
||||
error("So change package.domain to anything else.")
|
||||
error("")
|
||||
error("If you messed up before, set the environment variable to force the build:")
|
||||
error("export BUILDOZER_ALLOW_ORG_TEST_DOMAIN=1")
|
||||
error("")
|
||||
if "BUILDOZER_ALLOW_ORG_TEST_DOMAIN" not in os.environ:
|
||||
exit(1)
|
||||
|
||||
if self.buildozer.config.get("app", "package.domain") == "org.kivy":
|
||||
error("")
|
||||
error("ERROR: Trying to release a package that starts with org.kivy")
|
||||
error("")
|
||||
error("The package.domain org.kivy is reserved for the Kivy official")
|
||||
error("applications. Please use your own domain.")
|
||||
error("")
|
||||
error("If you are a Kivy developer, add an export in your shell")
|
||||
error("export BUILDOZER_ALLOW_KIVY_ORG_DOMAIN=1")
|
||||
error("")
|
||||
if "BUILDOZER_ALLOW_KIVY_ORG_DOMAIN" not in os.environ:
|
||||
exit(1)
|
||||
|
||||
self.build_mode = 'release'
|
||||
self.artifact_format = self.buildozer.config.getdefault('app', 'android.release_artifact', 'aab')
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_deploy(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_run(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_serve(self, *args):
|
||||
self.buildozer.cmd_serve()
|
||||
|
||||
def path_or_git_url(self, repo, owner='kivy', branch='master',
|
||||
url_format='https://github.com/{owner}/{repo}.git',
|
||||
platform=None,
|
||||
squash_hyphen=True):
|
||||
"""Get source location for a git checkout
|
||||
|
||||
This method will check the `buildozer.spec` for the keys:
|
||||
{repo}_dir
|
||||
{repo}_url
|
||||
{repo}_branch
|
||||
|
||||
and use them to determine the source location for a git checkout.
|
||||
|
||||
If a `platform` is specified, {platform}.{repo} will be used
|
||||
as the base for the buildozer key
|
||||
|
||||
`{repo}_dir` specifies a custom checkout location
|
||||
(relative to `buildozer.root_dir`). If present, `path` will be
|
||||
set to this value and `url`, `branch` will be set to None,
|
||||
None. Otherwise, `{repo}_url` and `{repo}_branch` will be
|
||||
examined.
|
||||
|
||||
If no keys are present, the kwargs will be used to create
|
||||
a sensible default URL and branch.
|
||||
|
||||
:Parameters:
|
||||
`repo`: str (required)
|
||||
name of repository to fetch. Used both for buildozer
|
||||
keys ({platform}.{repo}_dir|_url|_branch) and in building
|
||||
default git URL
|
||||
`branch`: str (default 'master')
|
||||
Specific branch to retrieve if none specified in
|
||||
buildozer.spec.
|
||||
`owner`: str
|
||||
owner of repo.
|
||||
`platform`: str or None
|
||||
platform prefix to use when retrieving `buildozer.spec`
|
||||
keys. If specified, key names will be {platform}.{repo}
|
||||
instead of just {repo}
|
||||
`squash_hyphen`: boolean
|
||||
if True, change '-' to '_' when looking for
|
||||
keys in buildozer.spec. This lets us keep backwards
|
||||
compatibility with old buildozer.spec files
|
||||
`url_format`: format string
|
||||
Used to construct default git URL.
|
||||
can use {repo} {owner} and {branch} if needed.
|
||||
|
||||
:Returns:
|
||||
A Tuple (path, url, branch) where
|
||||
`path`
|
||||
Path to a custom git checkout. If specified,
|
||||
both `url` and `branch` will be None
|
||||
`url`
|
||||
URL of git repository from where code should be
|
||||
checked-out
|
||||
`branch`
|
||||
branch name (or tag) that should be used for the
|
||||
check-out.
|
||||
|
||||
"""
|
||||
if squash_hyphen:
|
||||
key = repo.replace('-', '_')
|
||||
else:
|
||||
key = repo
|
||||
if platform:
|
||||
key = "{}.{}".format(platform, key)
|
||||
config = self.buildozer.config
|
||||
path = config.getdefault('app', '{}_dir'.format(key), None)
|
||||
|
||||
if path is not None:
|
||||
path = join(self.buildozer.root_dir, path)
|
||||
url = None
|
||||
branch = None
|
||||
else:
|
||||
branch = config.getdefault('app', '{}_branch'.format(key), branch)
|
||||
default_url = url_format.format(owner=owner, repo=repo, branch=branch)
|
||||
url = config.getdefault('app', '{}_url'.format(key), default_url)
|
||||
return path, url, branch
|
||||
|
||||
def install_or_update_repo(self, repo, **kwargs):
|
||||
"""Install or update a git repository into the platform directory.
|
||||
|
||||
This will clone the contents of a git repository to
|
||||
`buildozer.platform_dir`. The location of this repo can be
|
||||
specified via URL and branch name, or via a custom (local)
|
||||
directory name.
|
||||
|
||||
:Parameters:
|
||||
**kwargs:
|
||||
Any valid arguments for :meth:`path_or_git_url`
|
||||
|
||||
:Returns:
|
||||
fully qualified path to updated git repo
|
||||
"""
|
||||
cmd = self.buildozer.cmd
|
||||
install_dir = join(self.buildozer.platform_dir, repo)
|
||||
custom_dir, clone_url, clone_branch = self.path_or_git_url(repo, **kwargs)
|
||||
if not self.buildozer.file_exists(install_dir):
|
||||
if custom_dir:
|
||||
cmd(["mkdir", "-p", install_dir])
|
||||
cmd(["cp", "-a", f"{custom_dir}/*", f"{install_dir}/"])
|
||||
else:
|
||||
cmd(["git", "clone", "--branch", clone_branch, clone_url], cwd=self.buildozer.platform_dir)
|
||||
elif self.platform_update:
|
||||
if custom_dir:
|
||||
cmd(["cp", "-a", f"{custom_dir}/*", f"{install_dir}/"])
|
||||
else:
|
||||
cmd(["git", "clean", "-dxf"], cwd=install_dir)
|
||||
cmd(["git", "pull", "origin", clone_branch], cwd=install_dir)
|
||||
return install_dir
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1460
kivy_venv/lib/python3.11/site-packages/buildozer/targets/android.py
Normal file
1460
kivy_venv/lib/python3.11/site-packages/buildozer/targets/android.py
Normal file
File diff suppressed because it is too large
Load diff
478
kivy_venv/lib/python3.11/site-packages/buildozer/targets/ios.py
Normal file
478
kivy_venv/lib/python3.11/site-packages/buildozer/targets/ios.py
Normal file
|
@ -0,0 +1,478 @@
|
|||
'''
|
||||
iOS target, based on kivy-ios project
|
||||
'''
|
||||
|
||||
import sys
|
||||
import plistlib
|
||||
from buildozer import BuildozerCommandException
|
||||
from buildozer.target import Target, no_config
|
||||
from os.path import join, basename, expanduser, realpath
|
||||
from getpass import getpass
|
||||
|
||||
|
||||
PHP_TEMPLATE = '''
|
||||
<?php
|
||||
// credits goes to http://jeffreysambells.com/2010/06/22/ios-wireless-app-distribution
|
||||
|
||||
$ipas = glob('*.ipa');
|
||||
$provisioningProfiles = glob('*.mobileprovision');
|
||||
$plists = glob('*.plist');
|
||||
|
||||
$sr = stristr( $_SERVER['SCRIPT_URI'], '.php' ) === false ?
|
||||
$_SERVER['SCRIPT_URI'] : dirname($_SERVER['SCRIPT_URI']) . '/';
|
||||
$provisioningProfile = $sr . $provisioningProfiles[0];
|
||||
$ipa = $sr . $ipas[0];
|
||||
$itmsUrl = urlencode( $sr . 'index.php?plist=' . str_replace( '.plist', '', $plists[0] ) );
|
||||
|
||||
|
||||
if ($_GET['plist']) {
|
||||
$plist = file_get_contents( dirname(__FILE__)
|
||||
. DIRECTORY_SEPARATOR
|
||||
. preg_replace( '/![A-Za-z0-9-_]/i', '', $_GET['plist']) . '.plist' );
|
||||
$plist = str_replace('_URL_', $ipa, $plist);
|
||||
header('content-type: application/xml');
|
||||
echo $plist;
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Install {appname}</title>
|
||||
<style type="text/css">
|
||||
li { padding: 1em; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li><a href="<? echo $provisioningProfile; ?>">Install Team Provisioning File</a></li>
|
||||
<li><a href="itms-services://?action=download-manifest&url=<? echo $itmsUrl; ?>">
|
||||
Install Application</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
|
||||
class TargetIos(Target):
|
||||
targetname = "ios"
|
||||
|
||||
def __init__(self, buildozer):
|
||||
super().__init__(buildozer)
|
||||
executable = sys.executable or 'python'
|
||||
self._toolchain_cmd = [executable, "toolchain.py"]
|
||||
self._xcodebuild_cmd = ["xcodebuild"]
|
||||
# set via install_platform()
|
||||
self.ios_dir = None
|
||||
self.ios_deploy_dir = None
|
||||
|
||||
def check_requirements(self):
|
||||
if sys.platform != "darwin":
|
||||
raise NotImplementedError("Only macOS is supported for iOS target")
|
||||
checkbin = self.buildozer.checkbin
|
||||
cmd = self.buildozer.cmd
|
||||
|
||||
checkbin('Xcode xcodebuild', 'xcodebuild')
|
||||
checkbin('Xcode xcode-select', 'xcode-select')
|
||||
checkbin('Git git', 'git')
|
||||
checkbin('Cython cython', 'cython')
|
||||
checkbin('pkg-config', 'pkg-config')
|
||||
checkbin('autoconf', 'autoconf')
|
||||
checkbin('automake', 'automake')
|
||||
checkbin('libtool', 'libtool')
|
||||
|
||||
self.buildozer.debug('Check availability of a iPhone SDK')
|
||||
sdk = cmd('xcodebuild -showsdks | fgrep "iphoneos" |'
|
||||
'tail -n 1 | awk \'{print $2}\'',
|
||||
get_stdout=True, shell=True)[0]
|
||||
if not sdk:
|
||||
raise Exception(
|
||||
'No iPhone SDK found. Please install at least one iOS SDK.')
|
||||
else:
|
||||
self.buildozer.debug(' -> found %r' % sdk)
|
||||
|
||||
self.buildozer.debug('Check Xcode path')
|
||||
xcode = cmd(["xcode-select", "-print-path"], get_stdout=True)[0]
|
||||
if not xcode:
|
||||
raise Exception('Unable to get xcode path')
|
||||
self.buildozer.debug(' -> found {0}'.format(xcode))
|
||||
|
||||
def install_platform(self):
|
||||
"""
|
||||
Clones `kivy/kivy-ios` and `phonegap/ios-deploy` then sets `ios_dir`
|
||||
and `ios_deploy_dir` accordingly.
|
||||
"""
|
||||
self.ios_dir = self.install_or_update_repo('kivy-ios', platform='ios')
|
||||
self.ios_deploy_dir = self.install_or_update_repo('ios-deploy',
|
||||
platform='ios',
|
||||
branch='1.7.0',
|
||||
owner='phonegap')
|
||||
|
||||
def toolchain(self, cmd, **kwargs):
|
||||
kwargs.setdefault('cwd', self.ios_dir)
|
||||
return self.buildozer.cmd([*self._toolchain_cmd, *cmd], **kwargs)
|
||||
|
||||
def xcodebuild(self, *args, **kwargs):
|
||||
filtered_args = [arg for arg in args if arg is not None]
|
||||
return self.buildozer.cmd([*self._xcodebuild_cmd, *filtered_args], **kwargs)
|
||||
|
||||
@property
|
||||
def code_signing_allowed(self):
|
||||
allowed = self.buildozer.config.getboolean("app", "ios.codesign.allowed")
|
||||
allowed = "YES" if allowed else "NO"
|
||||
return f"CODE_SIGNING_ALLOWED={allowed}"
|
||||
|
||||
@property
|
||||
def code_signing_development_team(self):
|
||||
team = self.buildozer.config.getdefault("app", f"ios.codesign.development_team.{self.build_mode}", None)
|
||||
return f"DEVELOPMENT_TEAM={team}" if team else None
|
||||
|
||||
def get_available_packages(self):
|
||||
available_modules = self.toolchain(["recipes", "--compact"], get_stdout=True)[0]
|
||||
return available_modules.splitlines()[0].split()
|
||||
|
||||
def load_plist_from_file(self, plist_rfn):
|
||||
with open(plist_rfn, 'rb') as f:
|
||||
return plistlib.load(f)
|
||||
|
||||
def dump_plist_to_file(self, plist, plist_rfn):
|
||||
with open(plist_rfn, 'wb') as f:
|
||||
plistlib.dump(plist, f)
|
||||
|
||||
def compile_platform(self):
|
||||
# for ios, the compilation depends really on the app requirements.
|
||||
# compile the distribution only if the requirements changed.
|
||||
last_requirements = self.buildozer.state.get('ios.requirements', '')
|
||||
app_requirements = self.buildozer.config.getlist('app', 'requirements',
|
||||
'')
|
||||
|
||||
# we need to extract the requirements that kivy-ios knows about
|
||||
available_modules = self.get_available_packages()
|
||||
onlyname = lambda x: x.split('==')[0] # noqa: E731 do not assign a lambda expression, use a def
|
||||
ios_requirements = [x for x in app_requirements if onlyname(x) in
|
||||
available_modules]
|
||||
|
||||
need_compile = 0
|
||||
if last_requirements != ios_requirements:
|
||||
need_compile = 1
|
||||
|
||||
# len('requirements.source.') == 20, so use name[20:]
|
||||
source_dirs = {'{}_DIR'.format(name[20:].upper()):
|
||||
realpath(expanduser(value))
|
||||
for name, value in self.buildozer.config.items('app')
|
||||
if name.startswith('requirements.source.')}
|
||||
if source_dirs:
|
||||
need_compile = 1
|
||||
self.buildozer.environ.update(source_dirs)
|
||||
self.buildozer.info('Using custom source dirs:\n {}'.format(
|
||||
'\n '.join(['{} = {}'.format(k, v)
|
||||
for k, v in source_dirs.items()])))
|
||||
|
||||
if not need_compile:
|
||||
self.buildozer.info('Distribution already compiled, pass.')
|
||||
return
|
||||
|
||||
self.toolchain(["build", *ios_requirements])
|
||||
|
||||
if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'):
|
||||
self.xcodebuild(cwd=self.ios_deploy_dir)
|
||||
|
||||
self.buildozer.state['ios.requirements'] = ios_requirements
|
||||
self.buildozer.state.sync()
|
||||
|
||||
def _get_package(self):
|
||||
config = self.buildozer.config
|
||||
package_domain = config.getdefault('app', 'package.domain', '')
|
||||
package = config.get('app', 'package.name')
|
||||
if package_domain:
|
||||
package = package_domain + '.' + package
|
||||
return package.lower()
|
||||
|
||||
def build_package(self):
|
||||
self._unlock_keychain()
|
||||
|
||||
# create the project
|
||||
app_name = self.buildozer.namify(self.buildozer.config.get('app',
|
||||
'package.name'))
|
||||
|
||||
ios_frameworks = self.buildozer.config.getlist('app', 'ios.frameworks', '')
|
||||
frameworks_cmd = []
|
||||
for framework in ios_frameworks:
|
||||
frameworks_cmd.append(f"--add-framework={framework}")
|
||||
|
||||
self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower()))
|
||||
if not self.buildozer.file_exists(self.app_project_dir):
|
||||
cmd = ["create", *frameworks_cmd, app_name, self.buildozer.app_dir]
|
||||
else:
|
||||
cmd = ["update", *frameworks_cmd, f"{app_name}-ios"]
|
||||
self.toolchain(cmd)
|
||||
|
||||
# fix the plist
|
||||
plist_fn = '{}-Info.plist'.format(app_name.lower())
|
||||
plist_rfn = join(self.app_project_dir, plist_fn)
|
||||
version = self.buildozer.get_version()
|
||||
self.buildozer.info('Update Plist {}'.format(plist_fn))
|
||||
plist = self.load_plist_from_file(plist_rfn)
|
||||
plist['CFBundleIdentifier'] = self._get_package()
|
||||
plist['CFBundleShortVersionString'] = version
|
||||
plist['CFBundleVersion'] = '{}.{}'.format(version,
|
||||
self.buildozer.build_id)
|
||||
|
||||
# add icons
|
||||
self._create_icons()
|
||||
|
||||
# Generate OTA distribution manifest if `app_url`, `display_image_url` and `full_size_image_url` are defined.
|
||||
app_url = self.buildozer.config.getdefault("app", "ios.manifest.app_url", None)
|
||||
display_image_url = self.buildozer.config.getdefault("app", "ios.manifest.display_image_url", None)
|
||||
full_size_image_url = self.buildozer.config.getdefault("app", "ios.manifest.full_size_image_url", None)
|
||||
|
||||
if any((app_url, display_image_url, full_size_image_url)):
|
||||
|
||||
if not all((app_url, display_image_url, full_size_image_url)):
|
||||
self.buildozer.error("Options ios.manifest.app_url, ios.manifest.display_image_url"
|
||||
" and ios.manifest.full_size_image_url should be defined all together")
|
||||
return
|
||||
|
||||
plist['manifest'] = {
|
||||
'appURL': app_url,
|
||||
'displayImageURL': display_image_url,
|
||||
'fullSizeImageURL': full_size_image_url,
|
||||
}
|
||||
|
||||
# ok, write the modified plist.
|
||||
self.dump_plist_to_file(plist, plist_rfn)
|
||||
|
||||
mode = self.build_mode.capitalize()
|
||||
self.xcodebuild(
|
||||
"-configuration",
|
||||
mode,
|
||||
'-allowProvisioningUpdates',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_allowed,
|
||||
self.code_signing_development_team,
|
||||
'clean',
|
||||
'build',
|
||||
cwd=self.app_project_dir)
|
||||
ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format(
|
||||
app_lower=app_name.lower(), mode=mode)
|
||||
self.buildozer.state['ios:latestappdir'] = ios_app_dir
|
||||
|
||||
intermediate_dir = join(self.ios_dir, '{}-{}.intermediates'.format(app_name, version))
|
||||
xcarchive = join(intermediate_dir, '{}-{}.xcarchive'.format(
|
||||
app_name, version))
|
||||
ipa_name = '{}-{}.ipa'.format(app_name, version)
|
||||
ipa_tmp = join(intermediate_dir, ipa_name)
|
||||
ipa = join(self.buildozer.bin_dir, ipa_name)
|
||||
build_dir = join(self.ios_dir, '{}-ios'.format(app_name.lower()))
|
||||
|
||||
self.buildozer.rmdir(intermediate_dir)
|
||||
|
||||
self.buildozer.info('Creating archive...')
|
||||
self.xcodebuild(
|
||||
'-alltargets',
|
||||
'-configuration',
|
||||
mode,
|
||||
'-scheme',
|
||||
app_name.lower(),
|
||||
'-archivePath',
|
||||
xcarchive,
|
||||
'-destination',
|
||||
'generic/platform=iOS',
|
||||
'archive',
|
||||
'ENABLE_BITCODE=NO',
|
||||
self.code_signing_allowed,
|
||||
self.code_signing_development_team,
|
||||
cwd=build_dir)
|
||||
|
||||
key = 'ios.codesign.{}'.format(self.build_mode)
|
||||
ioscodesign = self.buildozer.config.getdefault('app', key, '')
|
||||
if not ioscodesign:
|
||||
self.buildozer.error('Cannot create the IPA package without'
|
||||
' signature. You must fill the "{}" token.'.format(key))
|
||||
return
|
||||
elif ioscodesign[0] not in ('"', "'"):
|
||||
ioscodesign = '"{}"'.format(ioscodesign)
|
||||
|
||||
self.buildozer.info('Creating IPA...')
|
||||
self.xcodebuild(
|
||||
'-exportArchive',
|
||||
f'-archivePath "{xcarchive}"',
|
||||
f'-exportOptionsPlist "{plist_rfn}"',
|
||||
f'-exportPath "{ipa_tmp}"',
|
||||
f'CODE_SIGN_IDENTITY={ioscodesign}',
|
||||
'ENABLE_BITCODE=NO',
|
||||
cwd=build_dir)
|
||||
|
||||
self.buildozer.info('Moving IPA to bin...')
|
||||
self.buildozer.file_rename(ipa_tmp, ipa)
|
||||
|
||||
self.buildozer.info('iOS packaging done!')
|
||||
self.buildozer.info('IPA {0} available in the bin directory'.format(
|
||||
basename(ipa)))
|
||||
self.buildozer.state['ios:latestipa'] = ipa
|
||||
self.buildozer.state['ios:latestmode'] = self.build_mode
|
||||
|
||||
def cmd_deploy(self, *args):
|
||||
super().cmd_deploy(*args)
|
||||
self._run_ios_deploy(lldb=False)
|
||||
|
||||
def cmd_run(self, *args):
|
||||
super().cmd_run(*args)
|
||||
self._run_ios_deploy(lldb=True)
|
||||
|
||||
def cmd_xcode(self, *args):
|
||||
'''Open the xcode project.
|
||||
'''
|
||||
app_name = self.buildozer.namify(self.buildozer.config.get('app',
|
||||
'package.name'))
|
||||
app_name = app_name.lower()
|
||||
|
||||
ios_dir = ios_dir = join(self.buildozer.platform_dir, 'kivy-ios')
|
||||
self.buildozer.cmd(
|
||||
["open", f"{app_name}.xcodeproj"], cwd=join(ios_dir, f"{app_name}-ios")
|
||||
)
|
||||
|
||||
def _run_ios_deploy(self, lldb=False):
|
||||
state = self.buildozer.state
|
||||
if 'ios:latestappdir' not in state:
|
||||
self.buildozer.error(
|
||||
'App not built yet. Run "debug" or "release" first.')
|
||||
return
|
||||
ios_app_dir = state.get('ios:latestappdir')
|
||||
|
||||
if lldb:
|
||||
debug_mode = '-d'
|
||||
self.buildozer.info('Deploy and start the application')
|
||||
else:
|
||||
debug_mode = ''
|
||||
self.buildozer.info('Deploy the application')
|
||||
|
||||
self.buildozer.cmd(
|
||||
[join(self.ios_deploy_dir, "ios-deploy"), debug_mode, "-b", ios_app_dir],
|
||||
cwd=self.ios_dir,
|
||||
show_output=True,
|
||||
)
|
||||
|
||||
def _create_icons(self):
|
||||
icon = self.buildozer.config.getdefault('app', 'icon.filename', '')
|
||||
if not icon:
|
||||
return
|
||||
icon_fn = join(self.buildozer.app_dir, icon)
|
||||
if not self.buildozer.file_exists(icon_fn):
|
||||
self.buildozer.error('Icon {} does not exists'.format(icon_fn))
|
||||
return
|
||||
|
||||
self.toolchain(["icon", self.app_project_dir, icon_fn])
|
||||
|
||||
def check_configuration_tokens(self):
|
||||
errors = []
|
||||
config = self.buildozer.config
|
||||
if not config.getboolean('app', 'ios.codesign.allowed'):
|
||||
return
|
||||
identity_debug = config.getdefault('app', 'ios.codesign.debug', '')
|
||||
identity_release = config.getdefault('app', 'ios.codesign.release',
|
||||
identity_debug)
|
||||
available_identities = self._get_available_identities()
|
||||
|
||||
if not identity_debug:
|
||||
errors.append('[app] "ios.codesign.debug" key missing, '
|
||||
'you must give a certificate name to use.')
|
||||
elif identity_debug not in available_identities:
|
||||
errors.append('[app] identity {} not found. '
|
||||
'Check with list_identities'.format(identity_debug))
|
||||
|
||||
if not identity_release:
|
||||
errors.append('[app] "ios.codesign.release" key missing, '
|
||||
'you must give a certificate name to use.')
|
||||
elif identity_release not in available_identities:
|
||||
errors.append('[app] identity "{}" not found. '
|
||||
'Check with list_identities'.format(identity_release))
|
||||
super().check_configuration_tokens(errors)
|
||||
|
||||
@no_config
|
||||
def cmd_list_identities(self, *args):
|
||||
'''List the available identities to use for signing.
|
||||
'''
|
||||
identities = self._get_available_identities()
|
||||
print('Available identities:')
|
||||
for x in identities:
|
||||
print(' - {}'.format(x))
|
||||
|
||||
def _get_available_identities(self):
|
||||
output = self.buildozer.cmd(
|
||||
["security", "find-identity", "-v", "-p", "codesigning"], get_stdout=True
|
||||
)[0]
|
||||
|
||||
lines = output.splitlines()[:-1]
|
||||
lines = [u'"{}"'.format(x.split('"')[1]) for x in lines]
|
||||
return lines
|
||||
|
||||
def _unlock_keychain(self):
|
||||
password_file = join(self.buildozer.buildozer_dir, '.ioscodesign')
|
||||
password = None
|
||||
if self.buildozer.file_exists(password_file):
|
||||
with open(password_file) as fd:
|
||||
password = fd.read()
|
||||
|
||||
if not password:
|
||||
# no password available, try to unlock anyway...
|
||||
error = self.buildozer.cmd(["security", "unlock-keychain", "-u"],
|
||||
break_on_error=False)[2]
|
||||
if not error:
|
||||
return
|
||||
else:
|
||||
# password available, try to unlock
|
||||
error = self.buildozer.cmd(
|
||||
["security", "unlock-keychain", "-p", password],
|
||||
break_on_error=False,
|
||||
sensible=True,
|
||||
)[2]
|
||||
if not error:
|
||||
return
|
||||
|
||||
# we need the password to unlock.
|
||||
correct = False
|
||||
attempt = 3
|
||||
while attempt:
|
||||
attempt -= 1
|
||||
password = getpass('Password to unlock the default keychain:')
|
||||
error = self.buildozer.cmd(
|
||||
["security", "unlock-keychain", "-p", password],
|
||||
break_on_error=False,
|
||||
sensible=True,
|
||||
)[2]
|
||||
if not error:
|
||||
correct = True
|
||||
break
|
||||
self.buildozer.error('Invalid keychain password')
|
||||
|
||||
if not correct:
|
||||
self.buildozer.error('Unable to unlock the keychain, exiting.')
|
||||
raise BuildozerCommandException()
|
||||
|
||||
# maybe user want to save it for further reuse?
|
||||
print(
|
||||
'The keychain password can be saved in the build directory\n'
|
||||
'As soon as the build directory will be cleaned, '
|
||||
'the password will be erased.')
|
||||
|
||||
save = None
|
||||
while save is None:
|
||||
q = input('Do you want to save the password (Y/n): ')
|
||||
if q in ('', 'Y'):
|
||||
save = True
|
||||
elif q == 'n':
|
||||
save = False
|
||||
else:
|
||||
print('Invalid answer!')
|
||||
|
||||
if save:
|
||||
with open(password_file, 'wb') as fd:
|
||||
fd.write(password.encode())
|
||||
|
||||
|
||||
def get_target(buildozer):
|
||||
return TargetIos(buildozer)
|
246
kivy_venv/lib/python3.11/site-packages/buildozer/targets/osx.py
Normal file
246
kivy_venv/lib/python3.11/site-packages/buildozer/targets/osx.py
Normal file
|
@ -0,0 +1,246 @@
|
|||
'''
|
||||
OSX target, based on kivy-sdk-packager
|
||||
'''
|
||||
|
||||
import sys
|
||||
if sys.platform != 'darwin':
|
||||
raise NotImplementedError('This will only work on osx')
|
||||
|
||||
from buildozer.target import Target
|
||||
from os.path import exists, join, abspath, dirname
|
||||
from subprocess import check_call, check_output
|
||||
|
||||
|
||||
class TargetOSX(Target):
|
||||
targetname = "osx"
|
||||
|
||||
def ensure_sdk(self):
|
||||
self.buildozer.info('Check if kivy-sdk-packager exists')
|
||||
if exists(
|
||||
join(self.buildozer.platform_dir, 'kivy-sdk-packager-master')):
|
||||
self.buildozer.info(
|
||||
'kivy-sdk-packager found at '
|
||||
'{}'.format(self.buildozer.platform_dir))
|
||||
return
|
||||
|
||||
self.buildozer.info('kivy-sdk-packager does not exist, clone it')
|
||||
platdir = self.buildozer.platform_dir
|
||||
check_call(
|
||||
('curl', '-O', '-L',
|
||||
'https://github.com/kivy/kivy-sdk-packager/archive/master.zip'),
|
||||
cwd=platdir)
|
||||
check_call(('unzip', 'master.zip'), cwd=platdir)
|
||||
check_call(('rm', 'master.zip'), cwd=platdir)
|
||||
|
||||
def download_kivy(self, cwd, py_branch=2):
|
||||
current_kivy_vers = self.buildozer.config.get('app', 'osx.kivy_version')
|
||||
|
||||
if exists('/Applications/Kivy{}.app'.format(py_branch)):
|
||||
self.buildozer.info('Kivy found in Applications dir...')
|
||||
check_call(
|
||||
('cp', '-a', '/Applications/Kivy{}.app'.format(py_branch),
|
||||
'Kivy.app'), cwd=cwd)
|
||||
|
||||
else:
|
||||
if not exists(join(cwd, 'Kivy{}.dmg'.format(py_branch))):
|
||||
self.buildozer.info('Downloading kivy...')
|
||||
status_code = check_output(
|
||||
('curl', '-L', '--write-out', '%{http_code}', '-o', 'Kivy{}.dmg'.format(py_branch),
|
||||
'https://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'
|
||||
.format(current_kivy_vers, current_kivy_vers, py_branch)),
|
||||
cwd=cwd)
|
||||
|
||||
if status_code == "404":
|
||||
self.buildozer.error(
|
||||
"Unable to download the Kivy App. Check osx.kivy_version in your buildozer.spec, and verify "
|
||||
"Kivy servers are accessible. https://kivy.org/downloads/")
|
||||
check_call(("rm", "Kivy{}.dmg".format(py_branch)), cwd=cwd)
|
||||
sys.exit(1)
|
||||
|
||||
self.buildozer.info('Extracting and installing Kivy...')
|
||||
check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch)))
|
||||
check_call(('cp', '-a', '/Volumes/Kivy/Kivy.app', './Kivy.app'), cwd=cwd)
|
||||
|
||||
def ensure_kivyapp(self):
|
||||
self.buildozer.info('check if Kivy.app exists in local dir')
|
||||
kivy_app_dir = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')
|
||||
|
||||
py_branch = self.buildozer.config.get('app', 'osx.python_version')
|
||||
|
||||
if not int(py_branch) in (2, 3):
|
||||
self.buildozer.error('incompatible python version... aborting')
|
||||
sys.exit(1)
|
||||
|
||||
if exists(join(kivy_app_dir, 'Kivy.app')):
|
||||
self.buildozer.info('Kivy.app found at ' + kivy_app_dir)
|
||||
else:
|
||||
self.download_kivy(kivy_app_dir, py_branch)
|
||||
|
||||
def check_requirements(self):
|
||||
self.ensure_sdk()
|
||||
self.ensure_kivyapp()
|
||||
|
||||
def check_configuration_tokens(self, errors=None):
|
||||
if errors:
|
||||
self.buildozer.info('Check target configuration tokens')
|
||||
self.buildozer.error(
|
||||
'{0} error(s) found in the buildozer.spec'.format(
|
||||
len(errors)))
|
||||
for error in errors:
|
||||
print(error)
|
||||
sys.exit(1)
|
||||
# check
|
||||
|
||||
def build_package(self):
|
||||
self.buildozer.info('Building package')
|
||||
|
||||
bc = self.buildozer.config
|
||||
bcg = bc.get
|
||||
package_name = bcg('app', 'package.name')
|
||||
domain = bcg('app', 'package.domain')
|
||||
title = bcg('app', 'title')
|
||||
app_deps = open('requirements.txt').read()
|
||||
icon = bc.getdefault('app', 'icon.filename', '')
|
||||
version = self.buildozer.get_version()
|
||||
author = bc.getdefault('app', 'author', '')
|
||||
|
||||
self.buildozer.info('Create {}.app'.format(package_name))
|
||||
cwd = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')
|
||||
# remove kivy from app_deps
|
||||
app_deps = [a for a in app_deps.split('\n') if not a.startswith('#') and a not in ['kivy', '']]
|
||||
|
||||
cmd = [
|
||||
'Kivy.app/Contents/Resources/script',
|
||||
'-m', 'pip', 'install',
|
||||
]
|
||||
cmd.extend(app_deps)
|
||||
check_output(cmd, cwd=cwd)
|
||||
|
||||
cmd = [
|
||||
'python', 'package_app.py', self.buildozer.app_dir,
|
||||
'--appname={}'.format(package_name),
|
||||
'--bundlename={}'.format(title),
|
||||
'--bundleid={}'.format(domain),
|
||||
'--bundleversion={}'.format(version),
|
||||
'--displayname={}'.format(title)
|
||||
]
|
||||
if icon:
|
||||
cmd.append('--icon={}'.format(icon))
|
||||
if author:
|
||||
cmd.append('--author={}'.format(author))
|
||||
|
||||
check_output(cmd, cwd=cwd)
|
||||
|
||||
self.buildozer.info('{}.app created.'.format(package_name))
|
||||
self.buildozer.info('Creating {}.dmg'.format(package_name))
|
||||
check_output(
|
||||
('sh', '-x', 'create-osx-dmg.sh', package_name + '.app'),
|
||||
cwd=cwd)
|
||||
self.buildozer.info('{}.dmg created'.format(package_name))
|
||||
self.buildozer.info('moving {}.dmg to bin.'.format(package_name))
|
||||
binpath = join(
|
||||
self.buildozer.user_build_dir or
|
||||
dirname(abspath(self.buildozer.specfilename)), 'bin')
|
||||
check_output(
|
||||
('cp', '-a', package_name + '.dmg', binpath),
|
||||
cwd=cwd)
|
||||
self.buildozer.info('All Done!')
|
||||
|
||||
def compile_platform(self):
|
||||
pass
|
||||
|
||||
def install_platform(self):
|
||||
# ultimate configuration check.
|
||||
# some of our configuration cannot be check without platform.
|
||||
self.check_configuration_tokens()
|
||||
#
|
||||
self.buildozer.environ.update({
|
||||
'PACKAGES_PATH': self.buildozer.global_packages_dir,
|
||||
})
|
||||
|
||||
def get_custom_commands(self):
|
||||
result = []
|
||||
for x in dir(self):
|
||||
if not x.startswith('cmd_'):
|
||||
continue
|
||||
if x[4:] in self.buildozer.standard_cmds:
|
||||
continue
|
||||
result.append((x[4:], getattr(self, x).__doc__))
|
||||
return result
|
||||
|
||||
def get_available_packages(self):
|
||||
return ['kivy']
|
||||
|
||||
def run_commands(self, args):
|
||||
if not args:
|
||||
self.buildozer.error('Missing target command')
|
||||
self.buildozer.usage()
|
||||
sys.exit(1)
|
||||
|
||||
result = []
|
||||
last_command = []
|
||||
for arg in args:
|
||||
if not arg.startswith('--'):
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
last_command = []
|
||||
last_command.append(arg)
|
||||
else:
|
||||
if not last_command:
|
||||
self.buildozer.error('Argument passed without a command')
|
||||
self.buildozer.usage()
|
||||
sys.exit(1)
|
||||
last_command.append(arg)
|
||||
if last_command:
|
||||
result.append(last_command)
|
||||
|
||||
config_check = False
|
||||
|
||||
for item in result:
|
||||
command, args = item[0], item[1:]
|
||||
if not hasattr(self, 'cmd_{0}'.format(command)):
|
||||
self.buildozer.error('Unknown command {0}'.format(command))
|
||||
sys.exit(1)
|
||||
|
||||
func = getattr(self, 'cmd_{0}'.format(command))
|
||||
|
||||
need_config_check = not hasattr(func, '__no_config')
|
||||
if need_config_check and not config_check:
|
||||
config_check = True
|
||||
self.check_configuration_tokens()
|
||||
|
||||
func(args)
|
||||
|
||||
def check_build_prepared(self):
|
||||
self._build_prepared = False
|
||||
|
||||
def cmd_clean(self, *args):
|
||||
self.buildozer.clean_platform()
|
||||
|
||||
def cmd_update(self, *args):
|
||||
self.platform_update = True
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_debug(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
self.build_mode = 'debug'
|
||||
self.check_build_prepared()
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_release(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
self.build_mode = 'release'
|
||||
self.buildozer.build()
|
||||
|
||||
def cmd_deploy(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_run(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_serve(self, *args):
|
||||
self.buildozer.cmd_serve()
|
||||
|
||||
|
||||
def get_target(buildozer):
|
||||
return TargetOSX(buildozer)
|
Loading…
Add table
Add a link
Reference in a new issue