Skip to content

Commit d467b7c

Browse files
authored
Merge pull request #3266 from AndreMiras/feature/bootstraps_refactoring
♻️ Consolidate assemble_distribution() into base Bootstrap
2 parents 843086b + 1f4a567 commit d467b7c

File tree

5 files changed

+88
-152
lines changed

5 files changed

+88
-152
lines changed

pythonforandroid/bootstrap.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import shlex
99
import shutil
1010

11-
from pythonforandroid.logger import (shprint, info, logger, debug)
11+
from pythonforandroid.logger import (shprint, info, info_main, logger, debug)
1212
from pythonforandroid.util import (
1313
current_directory, ensure_dir, temp_directory, BuildInterruptingException,
1414
rmdir, move)
@@ -184,11 +184,52 @@ def prepare_build_dir(self):
184184
def prepare_dist_dir(self):
185185
ensure_dir(self.dist_dir)
186186

187+
def _assemble_distribution_for_arch(self, arch):
188+
"""Per-architecture distribution assembly.
189+
190+
Override this method to customize per-arch behavior.
191+
Called once for each architecture in self.ctx.archs.
192+
"""
193+
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
194+
self.distribute_aars(arch)
195+
196+
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
197+
ensure_dir(python_bundle_dir)
198+
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
199+
join(self.dist_dir, python_bundle_dir), arch)
200+
if not self.ctx.with_debug_symbols:
201+
self.strip_libraries(arch)
202+
self.fry_eggs(site_packages_dir)
203+
187204
def assemble_distribution(self):
188-
''' Copies all the files into the distribution (this function is
189-
overridden by the specific bootstrap classes to do this)
190-
and add in the distribution info.
191-
'''
205+
"""Assemble the distribution by copying files and creating Python bundle.
206+
207+
This default implementation works for most bootstraps. Override
208+
_assemble_distribution_for_arch() for per-arch customization, or
209+
override this entire method for fundamentally different behavior.
210+
"""
211+
info_main(f'# Creating Android project ({self.name})')
212+
213+
rmdir(self.dist_dir)
214+
shprint(sh.cp, '-r', self.build_dir, self.dist_dir)
215+
216+
with current_directory(self.dist_dir):
217+
with open('local.properties', 'w') as fileh:
218+
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
219+
220+
with current_directory(self.dist_dir):
221+
info('Copying Python distribution')
222+
223+
self.distribute_javaclasses(self.ctx.javaclass_dir,
224+
dest_dir=join("src", "main", "java"))
225+
226+
for arch in self.ctx.archs:
227+
self._assemble_distribution_for_arch(arch)
228+
229+
if 'sqlite3' not in self.ctx.recipe_build_order:
230+
with open('blacklist.txt', 'a') as fileh:
231+
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
232+
192233
self._copy_in_final_files()
193234
self.distribution.save_info(self.dist_dir)
194235

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,23 @@
11
from os.path import join
22

3-
import sh
4-
5-
from pythonforandroid.toolchain import (
6-
Bootstrap, shprint, current_directory, info, info_main)
7-
from pythonforandroid.util import ensure_dir, rmdir
3+
from pythonforandroid.toolchain import Bootstrap
4+
from pythonforandroid.util import ensure_dir
85

96

107
class SDLGradleBootstrap(Bootstrap):
118
name = "_sdl_common"
129

1310
recipe_depends = []
1411

15-
def assemble_distribution(self):
16-
info_main("# Creating Android project ({})".format(self.name))
17-
18-
rmdir(self.dist_dir)
19-
info("Copying SDL/gradle build")
20-
shprint(sh.cp, "-r", self.build_dir, self.dist_dir)
21-
22-
# either the build use environment variable (ANDROID_HOME)
23-
# or the local.properties if exists
24-
with current_directory(self.dist_dir):
25-
with open('local.properties', 'w') as fileh:
26-
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
27-
28-
with current_directory(self.dist_dir):
29-
info("Copying Python distribution")
30-
31-
self.distribute_javaclasses(self.ctx.javaclass_dir,
32-
dest_dir=join("src", "main", "java"))
33-
34-
for arch in self.ctx.archs:
35-
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
36-
ensure_dir(python_bundle_dir)
37-
38-
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
39-
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
40-
join(self.dist_dir, python_bundle_dir), arch)
41-
if not self.ctx.with_debug_symbols:
42-
self.strip_libraries(arch)
43-
self.fry_eggs(site_packages_dir)
44-
45-
if 'sqlite3' not in self.ctx.recipe_build_order:
46-
with open('blacklist.txt', 'a') as fileh:
47-
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
48-
49-
super().assemble_distribution()
12+
def _assemble_distribution_for_arch(self, arch):
13+
"""SDL bootstrap skips distribute_aars() - handled differently."""
14+
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
15+
# Note: SDL bootstrap does not call distribute_aars()
16+
17+
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
18+
ensure_dir(python_bundle_dir)
19+
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
20+
join(self.dist_dir, python_bundle_dir), arch)
21+
if not self.ctx.with_debug_symbols:
22+
self.strip_libraries(arch)
23+
self.fry_eggs(site_packages_dir)
Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import sh
2-
from os.path import join
3-
from pythonforandroid.toolchain import (
4-
Bootstrap, current_directory, info, info_main, shprint)
5-
from pythonforandroid.util import ensure_dir, rmdir
1+
from pythonforandroid.toolchain import Bootstrap
62

73

84
class ServiceOnlyBootstrap(Bootstrap):
@@ -13,40 +9,5 @@ class ServiceOnlyBootstrap(Bootstrap):
139
set(Bootstrap.recipe_depends).union({'genericndkbuild'})
1410
)
1511

16-
def assemble_distribution(self):
17-
info_main('# Creating Android project from build and {} bootstrap'.format(
18-
self.name))
19-
20-
info('This currently just copies the build stuff straight from the build dir.')
21-
rmdir(self.dist_dir)
22-
shprint(sh.cp, '-r', self.build_dir, self.dist_dir)
23-
with current_directory(self.dist_dir):
24-
with open('local.properties', 'w') as fileh:
25-
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
26-
27-
with current_directory(self.dist_dir):
28-
info('Copying python distribution')
29-
30-
self.distribute_javaclasses(self.ctx.javaclass_dir,
31-
dest_dir=join("src", "main", "java"))
32-
33-
for arch in self.ctx.archs:
34-
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
35-
self.distribute_aars(arch)
36-
37-
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
38-
ensure_dir(python_bundle_dir)
39-
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
40-
join(self.dist_dir, python_bundle_dir), arch)
41-
if not self.ctx.with_debug_symbols:
42-
self.strip_libraries(arch)
43-
self.fry_eggs(site_packages_dir)
44-
45-
if 'sqlite3' not in self.ctx.recipe_build_order:
46-
with open('blacklist.txt', 'a') as fileh:
47-
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
48-
49-
super().assemble_distribution()
50-
5112

5213
bootstrap = ServiceOnlyBootstrap()
Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
from os.path import join
2-
3-
import sh
4-
5-
from pythonforandroid.toolchain import Bootstrap, current_directory, info, info_main, shprint
6-
from pythonforandroid.util import ensure_dir, rmdir
1+
from pythonforandroid.toolchain import Bootstrap
72

83

94
class WebViewBootstrap(Bootstrap):
@@ -13,39 +8,5 @@ class WebViewBootstrap(Bootstrap):
138
set(Bootstrap.recipe_depends).union({'genericndkbuild'})
149
)
1510

16-
def assemble_distribution(self):
17-
info_main('# Creating Android project from build and {} bootstrap'.format(
18-
self.name))
19-
20-
rmdir(self.dist_dir)
21-
shprint(sh.cp, '-r', self.build_dir, self.dist_dir)
22-
with current_directory(self.dist_dir):
23-
with open('local.properties', 'w') as fileh:
24-
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
25-
26-
with current_directory(self.dist_dir):
27-
info('Copying python distribution')
28-
29-
self.distribute_javaclasses(self.ctx.javaclass_dir,
30-
dest_dir=join("src", "main", "java"))
31-
32-
for arch in self.ctx.archs:
33-
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
34-
self.distribute_aars(arch)
35-
36-
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
37-
ensure_dir(python_bundle_dir)
38-
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
39-
join(self.dist_dir, python_bundle_dir), arch)
40-
if not self.ctx.with_debug_symbols:
41-
self.strip_libraries(arch)
42-
self.fry_eggs(site_packages_dir)
43-
44-
if 'sqlite3' not in self.ctx.recipe_build_order:
45-
with open('blacklist.txt', 'a') as fileh:
46-
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
47-
48-
super().assemble_distribution()
49-
5011

5112
bootstrap = WebViewBootstrap()

tests/test_bootstrap.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -353,34 +353,30 @@ def bootstrap_name(self):
353353
name of the bootstrap to test"""
354354
raise NotImplementedError("Not implemented in GenericBootstrapTest")
355355

356+
@mock.patch("pythonforandroid.bootstraps.qt.shprint")
357+
@mock.patch("pythonforandroid.bootstraps.qt.rmdir")
356358
@mock.patch("pythonforandroid.bootstraps.qt.open", create=True)
357-
@mock.patch("pythonforandroid.bootstraps.service_only.open", create=True)
358-
@mock.patch("pythonforandroid.bootstraps.webview.open", create=True)
359-
@mock.patch("pythonforandroid.bootstraps._sdl_common.open", create=True)
359+
@mock.patch("pythonforandroid.bootstrap.open", create=True)
360360
@mock.patch("pythonforandroid.distribution.open", create=True)
361361
@mock.patch("pythonforandroid.bootstrap.Bootstrap.strip_libraries")
362362
@mock.patch("pythonforandroid.util.exists")
363363
@mock.patch("pythonforandroid.util.chdir")
364364
@mock.patch("pythonforandroid.bootstrap.listdir")
365-
@mock.patch("pythonforandroid.bootstraps._sdl_common.rmdir")
366-
@mock.patch("pythonforandroid.bootstraps.service_only.rmdir")
367-
@mock.patch("pythonforandroid.bootstraps.webview.rmdir")
368-
@mock.patch("pythonforandroid.bootstrap.sh.cp")
365+
@mock.patch("pythonforandroid.bootstrap.rmdir")
366+
@mock.patch("pythonforandroid.bootstrap.shprint")
369367
def test_assemble_distribution(
370368
self,
371-
mock_sh_cp,
372-
mock_rmdir1,
373-
mock_rmdir2,
374-
mock_rmdir3,
369+
mock_shprint,
370+
mock_rmdir,
375371
mock_listdir,
376372
mock_chdir,
377373
mock_ensure_dir,
378374
mock_strip_libraries,
379375
mock_open_dist_files,
380-
mock_open_sdl_files,
381-
mock_open_webview_files,
382-
mock_open_service_only_files,
383-
mock_open_qt_files
376+
mock_open_bootstrap_files,
377+
mock_open_qt_files,
378+
mock_qt_rmdir,
379+
mock_qt_shprint
384380
):
385381
"""
386382
A test for any overwritten method of
@@ -417,13 +413,11 @@ def test_assemble_distribution(
417413
bs.assemble_distribution()
418414

419415
mock_open_dist_files.assert_called_once_with("dist_info.json", "w")
420-
mock_open_bootstraps = {
421-
"sdl2": mock_open_sdl_files,
422-
"sdl3": mock_open_sdl_files,
423-
"webview": mock_open_webview_files,
424-
"service_only": mock_open_service_only_files,
425-
"qt": mock_open_qt_files
426-
}
416+
# Qt bootstrap has its own assemble_distribution, others use base class
417+
if self.bootstrap_name == "qt":
418+
mock_open_bs = mock_open_qt_files
419+
else:
420+
mock_open_bs = mock_open_bootstrap_files
427421
expected_open_calls = {
428422
"sdl2": [
429423
mock.call("local.properties", "w"),
@@ -433,11 +427,16 @@ def test_assemble_distribution(
433427
mock.call("local.properties", "w"),
434428
mock.call("blacklist.txt", "a"),
435429
],
436-
"webview": [mock.call("local.properties", "w")],
437-
"service_only": [mock.call("local.properties", "w")],
430+
"webview": [
431+
mock.call("local.properties", "w"),
432+
mock.call("blacklist.txt", "a"),
433+
],
434+
"service_only": [
435+
mock.call("local.properties", "w"),
436+
mock.call("blacklist.txt", "a"),
437+
],
438438
"qt": [mock.call("local.properties", "w")]
439439
}
440-
mock_open_bs = mock_open_bootstraps[self.bootstrap_name]
441440
# test that the expected calls has been called
442441
for expected_call in expected_open_calls[self.bootstrap_name]:
443442
self.assertIn(expected_call, mock_open_bs.call_args_list)
@@ -446,7 +445,7 @@ def test_assemble_distribution(
446445
mock.call().__enter__().write("sdk.dir=/opt/android/android-sdk"),
447446
mock_open_bs.mock_calls,
448447
)
449-
if self.bootstrap_name in ["sdl2", "sdl3"]:
448+
if self.bootstrap_name in ["sdl2", "sdl3", "webview", "service_only"]:
450449
self.assertIn(
451450
mock.call()
452451
.__enter__()
@@ -455,7 +454,7 @@ def test_assemble_distribution(
455454
)
456455

457456
# check that the other mocks we made are actually called
458-
mock_sh_cp.assert_called()
457+
mock_shprint.assert_called()
459458
mock_chdir.assert_called()
460459
mock_listdir.assert_called()
461460
mock_strip_libraries.assert_called()

0 commit comments

Comments
 (0)