From 40fbf3826167d5c7c1da82515f21e6217340b02f Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 11 Sep 2023 02:53:07 +1000 Subject: [PATCH] Improve Buildozer's venv handling. (#1689) * Improve Buildozer's venv handling. * Rather than call a subprocess to run venv, use the built-in venv library. * Rather than check if an attribute exists, define it in __init__ and see if it has changed. * self.venv contained a folder name, but the folder name didn't need to be stored after the method returned. A boolean was all that was required. Also, some trivial clean ups thrown in: * Comment improvements. * Copy command didn't need to be logged; buildops will do that. * Directory's existence doesn't need to be checked; buildops will do that. * Add reference to comment Co-authored-by: Mirko Galimberti --------- Co-authored-by: Mirko Galimberti --- buildozer/__init__.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 37ac57f43..d82cce6df 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -18,6 +18,7 @@ from sys import exit import textwrap import warnings +import venv import buildozer.buildops as buildops from buildozer.jsonstore import JsonStore @@ -38,6 +39,7 @@ def __init__(self, filename='buildozer.spec', target=None): self.state = None self.build_id = None self.config = SpecParser() + self._venv_created = False self.logger = Logger() @@ -225,11 +227,18 @@ def check_application_requirements(self): return # remove all the requirements that the target can compile + + # TODO: Make more general - filter at the first non [a-z0-9_-] char? onlyname = lambda x: x.split('==')[0] # noqa: E731 + requirements = [x for x in requirements if onlyname(x) not in target_available_packages] - if requirements and hasattr(sys, 'real_prefix'): + # Technique defined in venv library documentation. + # See: https://docs.python.org/3/library/venv.html#how-venvs-work + currently_in_venv = sys.prefix != sys.base_prefix + + if requirements and currently_in_venv: e = self.logger.error e('virtualenv is needed to install pure-Python modules, but') e('virtualenv does not support nesting, and you are running') @@ -237,7 +246,7 @@ def check_application_requirements(self): e('virtualenv instead.') exit(1) - # did we already installed the libs ? + # did we already install the libs ? if ( exists(self.applibs_dir) and self.state.get('cache.applibs', '') == requirements @@ -272,14 +281,14 @@ def check_garden_requirements(self): warnings.warn("`garden_requirements` settings is deprecated, use `requirements` instead", DeprecationWarning) def _ensure_virtualenv(self): - if hasattr(self, 'venv'): + # Only do it once. + if self._venv_created: return - self.venv = join(self.buildozer_dir, 'venv') - if not buildops.file_exists(self.venv): - buildops.cmd( - ["python3", "-m", "venv", "./venv"], - cwd=self.buildozer_dir, - env=self.environ) + + venv_dir = join(self.buildozer_dir, 'venv') + if not buildops.file_exists(venv_dir): + venv.create(venv_dir) + self._venv_created = True # read virtualenv output and parse it assert sys.platform != "win32", "Can't call bash on Windows" @@ -305,8 +314,6 @@ def _ensure_virtualenv(self): def clean_platform(self): self.logger.info('Clean the platform build directory') - if not exists(self.platform_dir): - return buildops.rmdir(self.platform_dir) def get_version(self): @@ -446,7 +453,6 @@ def _copy_application_sources(self): buildops.mkdir(dfn) # copy! - self.logger.debug('Copy {0}'.format(sfn)) buildops.file_copy(sfn, rfn) def _copy_application_libs(self): @@ -695,7 +701,7 @@ def check_root(self): sys.exit() def cmd_init(self, *args): - '''Create a initial buildozer.spec in the current directory + '''Create an initial buildozer.spec in the current directory ''' if exists('buildozer.spec'): print('ERROR: You already have a buildozer.spec file.')