Skip to content

Commit 910ea5b

Browse files
committed
(backport) pin pip<23.1 and setuptools<67
to allow PEP-440 non compliance. (backported relevant parts from master branch in juju#653) PEP-440 is more strict about requirement lines. As an example: pytz>dev is non-compliant, but is in 5.2.4 of kombu's requirements. This breaks building wheelhouses from source (such as the octavia charm). This patch pins pip and setuptools to the latest versions that will defintely still allow PEP-440 non-compliant packages to install. The option --upgrade-buildvenv-core-deps can be used to override this and will install the latest versions of pip and setuptools available. Fixes-Bug: juju#652
1 parent 98edcd3 commit 910ea5b

File tree

5 files changed

+64
-3
lines changed

5 files changed

+64
-3
lines changed

charmtools/build/tactics.py

+1
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,7 @@ def __call__(self):
12301230
utils.Process(
12311231
('virtualenv', '--python', 'python3', self._venv)
12321232
).exit_on_error()()
1233+
utils.pin_setuptools_for_pep440(self._venv, env=utils.host_env())
12331234
if self.per_layer:
12341235
self._process_per_layer(wheelhouse)
12351236
else:

charmtools/utils.py

+33
Original file line numberDiff line numberDiff line change
@@ -633,3 +633,36 @@ def validate_display_name(entity, linter):
633633
linter.err('display-name: not in valid format. '
634634
'Only letters, numbers, dashes, and hyphens are permitted.')
635635
return
636+
637+
638+
def host_env():
639+
"""Get environment appropriate for executing commands outside snap context.
640+
:returns: Dictionary with environment variables
641+
:rtype: Dict[str,str]
642+
"""
643+
env = os.environ.copy()
644+
for key in ('PREFIX', 'PYTHONHOME', 'PYTHONPATH',
645+
'GIT_TEMPLATE_DIR', 'GIT_EXEC_PATH'):
646+
if key in env:
647+
del(env[key])
648+
env['PATH'] = ':'.join([
649+
element
650+
for element in env['PATH'].split(':')
651+
if not element.startswith('/snap/charm/')])
652+
return env
653+
654+
655+
def pin_setuptools_for_pep440(venv_dir, env=None):
656+
"""Pin setuptools so that pep440 non-compliant packages can be installed.
657+
Also pins pip as it's a combination that definitely works.
658+
:param venv_dir: Full path to virtualenv in which packages will be upgraded
659+
:type venv_dir: str
660+
:param env: Environment to use when executing command
661+
:type env: Optional[Dict[str,str]]
662+
:returns: This function is called for its side effect
663+
"""
664+
log.debug('Pinning setuptools < 67 for pep440 non compliant packages "{}"'
665+
.format(venv_dir))
666+
Process((os.path.join(venv_dir, 'bin/pip'),
667+
'install', '-U', 'pip<23.1', 'setuptools<67'),
668+
env=env).exit_on_error()()

tests/test_build.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -431,14 +431,16 @@ def test_version_tactic_with_existing_version_file(self, mcall, ph, pi,
431431

432432
self.assertEqual((bu.target_dir / 'version').text(), 'sha2')
433433

434+
@mock.patch("charmtools.utils.pin_setuptools_for_pep440")
434435
@mock.patch("charmtools.utils.sign")
435436
@mock.patch("charmtools.build.builder.Builder.plan_version")
436437
@mock.patch("charmtools.build.builder.Builder.plan_interfaces")
437438
@mock.patch("charmtools.build.builder.Builder.plan_hooks")
438439
@mock.patch("path.Path.rmtree_p")
439440
@mock.patch("tempfile.mkdtemp")
440441
@mock.patch("charmtools.utils.Process")
441-
def test_wheelhouse(self, Process, mkdtemp, rmtree_p, ph, pi, pv, sign):
442+
def test_wheelhouse(self, Process, mkdtemp, rmtree_p, ph, pi, pv, sign,
443+
pin_setuptools_for_pep440):
442444
build.tactics.WheelhouseTactic.per_layer = False
443445
mkdtemp.return_value = '/tmp'
444446
bu = build.Builder()
@@ -486,7 +488,7 @@ def _store_wheelhouses(args):
486488
'',
487489
'# --wheelhouse-overrides',
488490
'git+https://github.com/me/qux#egg=qux',
489-
'setuptools_scm>=3.0<=3.4.1',
491+
'setuptools_scm>=3.0,<=3.4.1',
490492
'',
491493
])
492494

tests/test_utils.py

+25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import print_function
22

3+
import unittest
34
from unittest import TestCase
45
from charmtools import utils
56
from six import StringIO
@@ -43,3 +44,27 @@ def react(db):
4344
self.assertIn("Beta", output)
4445
self.assertIn("@when('db.ready'", output)
4546
self.assertIn("bar", output)
47+
48+
@unittest.mock.patch("os.environ")
49+
def test_host_env(self, mock_environ):
50+
mock_environ.copy.return_value = {
51+
'PREFIX': 'fake-prefix',
52+
'PYTHONHOME': 'fake-pythonhome',
53+
'PYTHONPATH': 'fake-pythonpath',
54+
'GIT_TEMPLATE_DIR': 'fake-git-template-dir',
55+
'GIT_EXEC_PATH': 'fake-git-exec-path',
56+
'SOME_OTHER_KEY': 'fake-some-other-key',
57+
'PATH': '/snap/charm/current/bin:/usr/bin:'
58+
'/snap/charm/current/usr/bin:/bin',
59+
}
60+
self.assertDictEqual(
61+
{'SOME_OTHER_KEY': 'fake-some-other-key', 'PATH': '/usr/bin:/bin'},
62+
utils.host_env())
63+
64+
@unittest.mock.patch.object(utils, "Process")
65+
def test_pin_setuptools_for_pep440(self, mock_Process):
66+
utils.pin_setuptools_for_pep440('/some/dir', env={'some': 'envvar'})
67+
mock_Process.assert_called_once_with(
68+
('/some/dir/bin/pip', 'install', '-U', 'pip<23.1',
69+
'setuptools<67'),
70+
env={'some': 'envvar'})

tests/wh-over.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
git+https://github.com/me/qux#egg=qux
2-
setuptools_scm>=3.0<=3.4.1
2+
setuptools_scm>=3.0,<=3.4.1

0 commit comments

Comments
 (0)