Skip to content

Fixes an issue regarding blacklist and bytecode compile + some cleanup #2693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/buildoptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ options (this list may not be exhaustive):
- ``--service``: A service name and the Python script it should
run. See :ref:`arbitrary_scripts_services`.
- ``--add-source``: Add a source directory to the app's Java code.
- ``--no-compile-pyo``: Do not optimise .py files to .pyo.
- ``--no-byte-compile-python``: Skip byte compile for .py files.
- ``--enable-androidx``: Enable AndroidX support library.


Expand Down
2 changes: 1 addition & 1 deletion doc/source/launcher.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ grab an old (cached) package instead of a fresh one.
.. warning::

Do not use any of `--private`, `--public`, `--dir` or other arguments for
adding `main.py` or `main.pyo` to the app. The argument `--launcher` is
adding `main.py` or `main.pyc` to the app. The argument `--launcher` is
above them and tells the p4a to build the launcher version of the APK.

Usage
Expand Down
2 changes: 1 addition & 1 deletion pythonforandroid/bdistapk.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def prepare_build_dir(self):
makedirs(new_dir)
print('Including {}'.format(filen))
copyfile(filen, join(bdist_dir, filen))
if basename(filen) in ('main.py', 'main.pyo'):
if basename(filen) in ('main.py', 'main.pyc'):
main_py_dirs.append(filen)

# This feels ridiculous, but how else to define the main.py dir?
Expand Down
82 changes: 33 additions & 49 deletions pythonforandroid/bootstraps/common/build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ def get_hostpython():
return get_dist_info_for('hostpython')


def get_python_version():
return get_dist_info_for('python_version')


def get_bootstrap_name():
return get_dist_info_for('bootstrap')

Expand All @@ -58,7 +54,6 @@ def get_bootstrap_name():
curdir = dirname(__file__)

PYTHON = get_hostpython()
PYTHON_VERSION = get_python_version()
if PYTHON is not None and not exists(PYTHON):
PYTHON = None

Expand All @@ -73,17 +68,16 @@ def get_bootstrap_name():
'~',
'*.bak',
'*.swp',

# Android artifacts
'*.apk',
'*.aab',
]
# pyc/py
if PYTHON is not None:
BLACKLIST_PATTERNS.append('*.py')

WHITELIST_PATTERNS = []
if get_bootstrap_name() in ('sdl2', 'webview', 'service_only'):
WHITELIST_PATTERNS.append('pyconfig.h')

python_files = []


environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
join(curdir, 'templates')))
Expand Down Expand Up @@ -150,23 +144,11 @@ def listfiles(d):
yield fn


def make_tar(tfn, source_dirs, ignore_path=[], optimize_python=True):
def make_tar(tfn, source_dirs, byte_compile_python=False, optimize_python=True):
'''
Make a zip file `fn` from the contents of source_dis.
'''

# selector function
def select(fn):
rfn = realpath(fn)
for p in ignore_path:
if p.endswith('/'):
p = p[:-1]
if rfn.startswith(p):
return False
if rfn in python_files:
return False
return not is_blacklist(fn)

def clean(tinfo):
"""cleaning function (for reproducible builds)"""
tinfo.uid = tinfo.gid = 0
Expand All @@ -178,9 +160,12 @@ def clean(tinfo):
files = []
for sd in source_dirs:
sd = realpath(sd)
compile_dir(sd, optimize_python=optimize_python)
files += [(x, relpath(realpath(x), sd)) for x in listfiles(sd)
if select(x)]
for fn in listfiles(sd):
if is_blacklist(fn):
continue
if fn.endswith('.py') and byte_compile_python:
fn = compile_py_file(fn, optimize_python=optimize_python)
files.append((fn, relpath(realpath(fn), sd)))
files.sort() # deterministic

# create tar.gz of thoses files
Expand Down Expand Up @@ -210,18 +195,15 @@ def clean(tinfo):
gf.close()


def compile_dir(dfn, optimize_python=True):
def compile_py_file(python_file, optimize_python=True):
'''
Compile *.py in directory `dfn` to *.pyo
Compile python_file to *.pyc and return the filename of the *.pyc file.
'''

if PYTHON is None:
return

if int(PYTHON_VERSION[0]) >= 3:
args = [PYTHON, '-m', 'compileall', '-b', '-f', dfn]
else:
args = [PYTHON, '-m', 'compileall', '-f', dfn]
args = [PYTHON, '-m', 'compileall', '-b', '-f', python_file]
if optimize_python:
# -OO = strip docstrings
args.insert(1, '-OO')
Expand All @@ -233,16 +215,18 @@ def compile_dir(dfn, optimize_python=True):
'error, see logs above')
exit(1)

return ".".join([os.path.splitext(python_file)[0], "pyc"])


def make_package(args):
# If no launcher is specified, require a main.py/main.pyo:
# If no launcher is specified, require a main.py/main.pyc:
if (get_bootstrap_name() != "sdl" or args.launcher is None) and \
get_bootstrap_name() not in ["webview", "service_library"]:
# (webview doesn't need an entrypoint, apparently)
if args.private is None or (
not exists(join(realpath(args.private), 'main.py')) and
not exists(join(realpath(args.private), 'main.pyo'))):
print('''BUILD FAILURE: No main.py(o) found in your app directory. This
not exists(join(realpath(args.private), 'main.pyc'))):
print('''BUILD FAILURE: No main.py(c) found in your app directory. This
file must exist to act as the entry point for you app. If your app is
started by a file with a different name, rename it to main.py or add a
main.py that loads it.''')
Expand Down Expand Up @@ -290,7 +274,6 @@ def make_package(args):
variants = [
copy_path,
copy_path.partition(".")[0] + ".pyc",
copy_path.partition(".")[0] + ".pyo",
]
# Check in all variants with all possible endings:
for variant in variants:
Expand Down Expand Up @@ -326,11 +309,17 @@ def make_package(args):
for arch in get_dist_info_for("archs"):
libs_dir = f"libs/{arch}"
make_tar(
join(libs_dir, 'libpybundle.so'), [f'_python_bundle__{arch}'], args.ignore_path,
optimize_python=args.optimize_python)
join(libs_dir, "libpybundle.so"),
[f"_python_bundle__{arch}"],
byte_compile_python=args.byte_compile_python,
optimize_python=args.optimize_python,
)
make_tar(
join(assets_dir, 'private.tar'), private_tar_dirs, args.ignore_path,
optimize_python=args.optimize_python)
join(assets_dir, "private.tar"),
private_tar_dirs,
byte_compile_python=args.byte_compile_python,
optimize_python=args.optimize_python,
)
finally:
for directory in _temp_dirs_to_clean:
shutil.rmtree(directory)
Expand Down Expand Up @@ -824,8 +813,6 @@ def parse_args_and_make_package(args=None):
ap.add_argument('--try-system-python-compile', dest='try_system_python_compile',
action='store_true',
help='Use the system python during compileall if possible.')
ap.add_argument('--no-compile-pyo', dest='no_compile_pyo', action='store_true',
help='Do not optimise .py files to .pyo.')
ap.add_argument('--sign', action='store_true',
help=('Try to sign the APK with your credentials. You must set '
'the appropriate environment variables.'))
Expand All @@ -844,9 +831,12 @@ def parse_args_and_make_package(args=None):
'files (containing your main.py entrypoint). '
'See https://developer.android.com/guide/topics/data/'
'autobackup#IncludingFiles for more information'))
ap.add_argument('--no-byte-compile-python', dest='byte_compile_python',
action='store_false', default=True,
help='Skip byte compile for .py files.')
ap.add_argument('--no-optimize-python', dest='optimize_python',
action='store_false', default=True,
help=('Whether to compile to optimised .pyo files, using -OO '
help=('Whether to compile to optimised .pyc files, using -OO '
'(strips docstrings and asserts)'))
ap.add_argument('--extra-manifest-xml', default='',
help=('Extra xml to write directly inside the <manifest> element of'
Expand Down Expand Up @@ -881,8 +871,6 @@ def _read_configuration():

args = ap.parse_args(args)

args.ignore_path = []

if args.name and args.name[0] == '"' and args.name[-1] == '"':
args.name = args.name[1:-1]

Expand Down Expand Up @@ -925,10 +913,6 @@ def _read_configuration():
else:
PYTHON = python_executable

if args.no_compile_pyo:
PYTHON = None
BLACKLIST_PATTERNS.remove('*.py')

if args.blacklist:
with open(args.blacklist) as fd:
patterns = [x.strip() for x in fd.read().splitlines()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,10 @@ int main(int argc, char *argv[]) {
*/
LOGP("Run user program, change dir and execute entrypoint");

/* Get the entrypoint, search the .pyo then .py
/* Get the entrypoint, search the .pyc then .py
*/
char *dot = strrchr(env_entrypoint, '.');
#if PY_MAJOR_VERSION > 2
char *ext = ".pyc";
#else
char *ext = ".pyo";
#endif
if (dot <= 0) {
LOGP("Invalid entrypoint, abort.");
return -1;
Expand All @@ -281,14 +277,10 @@ int main(int argc, char *argv[]) {
strcpy(entrypoint, env_entrypoint);
}
} else if (!strcmp(dot, ".py")) {
/* if .py is passed, check the pyo version first */
/* if .py is passed, check the pyc version first */
strcpy(entrypoint, env_entrypoint);
entrypoint[strlen(env_entrypoint) + 1] = '\0';
#if PY_MAJOR_VERSION > 2
entrypoint[strlen(env_entrypoint)] = 'c';
#else
entrypoint[strlen(env_entrypoint)] = 'o';
#endif
if (!file_exists(entrypoint)) {
/* fallback on pure python version */
if (!file_exists(env_entrypoint)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,11 +419,10 @@ public void run() {
}

public String getEntryPoint(String search_dir) {
/* Get the main file (.pyc|.pyo|.py) depending on if we
/* Get the main file (.pyc|.py) depending on if we
* have a compiled version or not.
*/
List<String> entryPoints = new ArrayList<String>();
entryPoints.add("main.pyo"); // python 2 compiled files
entryPoints.add("main.pyc"); // python 3 compiled files
for (String value : entryPoints) {
File mainFile = new File(search_dir + "/" + value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@ public String getAppRoot() {
}

public String getEntryPoint(String search_dir) {
/* Get the main file (.pyc|.pyo|.py) depending on if we
/* Get the main file (.pyc|.py) depending on if we
* have a compiled version or not.
*/
List<String> entryPoints = new ArrayList<String>();
entryPoints.add("main.pyo"); // python 2 compiled files
entryPoints.add("main.pyc"); // python 3 compiled files
for (String value : entryPoints) {
File mainFile = new File(search_dir + "/" + value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,10 @@ public String getAppRoot() {
}

public String getEntryPoint(String search_dir) {
/* Get the main file (.pyc|.pyo|.py) depending on if we
/* Get the main file (.pyc|.py) depending on if we
* have a compiled version or not.
*/
List<String> entryPoints = new ArrayList<String>();
entryPoints.add("main.pyo"); // python 2 compiled files
entryPoints.add("main.pyc"); // python 3 compiled files
for (String value : entryPoints) {
File mainFile = new File(search_dir + "/" + value);
Expand Down
1 change: 0 additions & 1 deletion pythonforandroid/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ def has_package(self, name, arch=None):
return (exists(join(site_packages_dir, name)) or
exists(join(site_packages_dir, name + '.py')) or
exists(join(site_packages_dir, name + '.pyc')) or
exists(join(site_packages_dir, name + '.pyo')) or
exists(join(site_packages_dir, name + '.so')) or
glob.glob(join(site_packages_dir, name + '-*.egg')))

Expand Down
6 changes: 3 additions & 3 deletions pythonforandroid/recipes/python3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,11 +364,11 @@ def create_python_bundle(self, dirn, arch):
self.major_minor_version_string
))

# Compile to *.pyc/*.pyo the python modules
# Compile to *.pyc the python modules
self.compile_python_files(modules_build_dir)
# Compile to *.pyc/*.pyo the standard python library
# Compile to *.pyc the standard python library
self.compile_python_files(join(self.get_build_dir(arch.arch), 'Lib'))
# Compile to *.pyc/*.pyo the other python packages (site-packages)
# Compile to *.pyc the other python packages (site-packages)
self.compile_python_files(self.ctx.get_python_install_dir(arch.arch))

# Bundle compiled python modules to a folder
Expand Down