Skip to content

Commit 7a0c935

Browse files
authored
Factor out dependency checking. Use modern version handling (kivy#2866)
LooseVersion used again Handle bad SDK versions
1 parent 910df0a commit 7a0c935

File tree

2 files changed

+109
-83
lines changed

2 files changed

+109
-83
lines changed

pythonforandroid/checkdependencies.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from importlib import import_module
2+
from os import environ
3+
import sys
4+
5+
from packaging.version import Version
6+
7+
from pythonforandroid.prerequisites import (
8+
check_and_install_default_prerequisites,
9+
)
10+
11+
12+
def check_python_dependencies():
13+
"""
14+
Check if the Python requirements are installed. This must appears
15+
before other imports because otherwise they're imported elsewhere.
16+
17+
Using the ok check instead of failing immediately so that all
18+
errors are printed at once.
19+
"""
20+
21+
ok = True
22+
23+
modules = [("colorama", "0.3.3"), "appdirs", ("sh", "1.10"), "jinja2"]
24+
25+
for module in modules:
26+
if isinstance(module, tuple):
27+
module, version = module
28+
else:
29+
version = None
30+
31+
try:
32+
import_module(module)
33+
except ImportError:
34+
if version is None:
35+
print(
36+
"ERROR: The {} Python module could not be found, please "
37+
"install it.".format(module)
38+
)
39+
ok = False
40+
else:
41+
print(
42+
"ERROR: The {} Python module could not be found, "
43+
"please install version {} or higher".format(
44+
module, version
45+
)
46+
)
47+
ok = False
48+
else:
49+
if version is None:
50+
continue
51+
try:
52+
cur_ver = sys.modules[module].__version__
53+
except AttributeError: # this is sometimes not available
54+
continue
55+
if Version(cur_ver) < Version(version):
56+
print(
57+
"ERROR: {} version is {}, but python-for-android needs "
58+
"at least {}.".format(module, cur_ver, version)
59+
)
60+
ok = False
61+
62+
if not ok:
63+
print("python-for-android is exiting due to the errors logged above")
64+
exit(1)
65+
66+
67+
def check():
68+
if not environ.get("SKIP_PREREQUISITES_CHECK", "0") == "1":
69+
check_and_install_default_prerequisites()
70+
check_python_dependencies()

pythonforandroid/toolchain.py

Lines changed: 39 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,96 +6,43 @@
66
This module defines the entry point for command line and programmatic use.
77
"""
88

9+
from appdirs import user_data_dir
10+
import argparse
11+
from functools import wraps
12+
import glob
13+
import logging
14+
import os
915
from os import environ
10-
from pythonforandroid import __version__
11-
from pythonforandroid.pythonpackage import get_dep_names_of_package
12-
from pythonforandroid.recommendations import (
13-
RECOMMENDED_NDK_API, RECOMMENDED_TARGET_API, print_recommendations)
14-
from pythonforandroid.util import BuildInterruptingException, load_source
15-
from pythonforandroid.entrypoints import main
16-
from pythonforandroid.prerequisites import check_and_install_default_prerequisites
17-
18-
19-
def check_python_dependencies():
20-
# Check if the Python requirements are installed. This appears
21-
# before the imports because otherwise they're imported elsewhere.
22-
23-
# Using the ok check instead of failing immediately so that all
24-
# errors are printed at once
25-
26-
from distutils.version import LooseVersion
27-
from importlib import import_module
28-
import sys
29-
30-
ok = True
31-
32-
modules = [('colorama', '0.3.3'), 'appdirs', ('sh', '1.10'), 'jinja2']
33-
34-
for module in modules:
35-
if isinstance(module, tuple):
36-
module, version = module
37-
else:
38-
version = None
39-
40-
try:
41-
import_module(module)
42-
except ImportError:
43-
if version is None:
44-
print('ERROR: The {} Python module could not be found, please '
45-
'install it.'.format(module))
46-
ok = False
47-
else:
48-
print('ERROR: The {} Python module could not be found, '
49-
'please install version {} or higher'.format(
50-
module, version))
51-
ok = False
52-
else:
53-
if version is None:
54-
continue
55-
try:
56-
cur_ver = sys.modules[module].__version__
57-
except AttributeError: # this is sometimes not available
58-
continue
59-
if LooseVersion(cur_ver) < LooseVersion(version):
60-
print('ERROR: {} version is {}, but python-for-android needs '
61-
'at least {}.'.format(module, cur_ver, version))
62-
ok = False
63-
64-
if not ok:
65-
print('python-for-android is exiting due to the errors logged above')
66-
exit(1)
67-
68-
69-
if not environ.get('SKIP_PREREQUISITES_CHECK', '0') == '1':
70-
check_and_install_default_prerequisites()
71-
check_python_dependencies()
72-
73-
74-
import sys
75-
from sys import platform
7616
from os.path import (join, dirname, realpath, exists, expanduser, basename)
77-
import os
78-
import glob
79-
import shutil
8017
import re
8118
import shlex
82-
from functools import wraps
19+
import shutil
20+
import sys
21+
from sys import platform
8322

84-
import argparse
23+
# This must be imported and run before other third-party or p4a
24+
# packages.
25+
from pythonforandroid.checkdependencies import check
26+
check()
27+
28+
from packaging.version import Version, InvalidVersion
8529
import sh
86-
from appdirs import user_data_dir
87-
import logging
88-
from distutils.version import LooseVersion
8930

90-
from pythonforandroid.recipe import Recipe
91-
from pythonforandroid.logger import (logger, info, warning, setup_color,
92-
Out_Style, Out_Fore,
93-
info_notify, info_main, shprint)
94-
from pythonforandroid.util import current_directory
31+
from pythonforandroid import __version__
9532
from pythonforandroid.bootstrap import Bootstrap
33+
from pythonforandroid.build import Context, build_recipes
9634
from pythonforandroid.distribution import Distribution, pretty_log_dists
35+
from pythonforandroid.entrypoints import main
9736
from pythonforandroid.graph import get_recipe_order_and_bootstrap
98-
from pythonforandroid.build import Context, build_recipes
37+
from pythonforandroid.logger import (logger, info, warning, setup_color,
38+
Out_Style, Out_Fore,
39+
info_notify, info_main, shprint)
40+
from pythonforandroid.pythonpackage import get_dep_names_of_package
41+
from pythonforandroid.recipe import Recipe
42+
from pythonforandroid.recommendations import (
43+
RECOMMENDED_NDK_API, RECOMMENDED_TARGET_API, print_recommendations)
44+
from pythonforandroid.util import (
45+
current_directory, BuildInterruptingException, load_source)
9946

10047
user_dir = dirname(realpath(os.path.curdir))
10148
toolchain_dir = dirname(__file__)
@@ -1068,13 +1015,22 @@ def _build_package(self, args, package_type):
10681015
self.hook("before_apk_assemble")
10691016
build_tools_versions = os.listdir(join(ctx.sdk_dir,
10701017
'build-tools'))
1071-
build_tools_versions = sorted(build_tools_versions,
1072-
key=LooseVersion)
1018+
1019+
def sort_key(version_text):
1020+
try:
1021+
# Historically, Android build release candidates have had
1022+
# spaces in the version number.
1023+
return Version(version_text.replace(" ", ""))
1024+
except InvalidVersion:
1025+
# Put badly named versions at worst position.
1026+
return Version("0")
1027+
1028+
build_tools_versions.sort(key=sort_key)
10731029
build_tools_version = build_tools_versions[-1]
10741030
info(('Detected highest available build tools '
10751031
'version to be {}').format(build_tools_version))
10761032

1077-
if build_tools_version < '25.0':
1033+
if Version(build_tools_version.replace(" ", "")) < Version('25.0'):
10781034
raise BuildInterruptingException(
10791035
'build_tools >= 25 is required, but %s is installed' % build_tools_version)
10801036
if not exists("gradlew"):

0 commit comments

Comments
 (0)