summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/news.rst3
-rw-r--r--src/wheel/bdist_wheel.py9
-rw-r--r--tests/test_bdist_wheel.py19
3 files changed, 27 insertions, 4 deletions
diff --git a/docs/news.rst b/docs/news.rst
index 731c4d4..ef16d4e 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -9,8 +9,9 @@ Release Notes
- Updated project packaging and testing configuration for :pep:`517`
- Moved the contents of setup.py to setup.cfg
- Fixed duplicate RECORD file when using "wheel pack" on Windows
+- Fixed bdist_wheel failing at cleanup on Windows with a read-only source tree
- Switched the project to use the "src" layout
-. Switched to setuptools_scm_ for versioning
+- Switched to setuptools_scm_ for versioning
.. _setuptools_scm: https://github.com/pypa/setuptools_scm/
diff --git a/src/wheel/bdist_wheel.py b/src/wheel/bdist_wheel.py
index 014983c..ce82eb6 100644
--- a/src/wheel/bdist_wheel.py
+++ b/src/wheel/bdist_wheel.py
@@ -6,6 +6,7 @@ A wheel is a built archive format.
import os
import shutil
+import stat
import sys
import re
from email.generator import Generator
@@ -40,6 +41,12 @@ def safer_version(version):
return safe_version(version).replace('-', '_')
+def remove_readonly(func, path, excinfo):
+ print(str(excinfo[1]))
+ os.chmod(path, stat.S_IWRITE)
+ func(path)
+
+
class bdist_wheel(Command):
description = 'create a wheel distribution'
@@ -267,7 +274,7 @@ class bdist_wheel(Command):
if not self.keep_temp:
logger.info('removing %s', self.bdist_dir)
if not self.dry_run:
- rmtree(self.bdist_dir)
+ rmtree(self.bdist_dir, onerror=remove_readonly)
def write_wheelfile(self, wheelfile_base, generator='bdist_wheel (' + wheel_version + ')'):
from email.message import Message
diff --git a/tests/test_bdist_wheel.py b/tests/test_bdist_wheel.py
index 4c98eda..de8d46f 100644
--- a/tests/test_bdist_wheel.py
+++ b/tests/test_bdist_wheel.py
@@ -1,5 +1,7 @@
# coding: utf-8
-import os
+import os.path
+import shutil
+import stat
import subprocess
import sys
from zipfile import ZipFile
@@ -20,7 +22,7 @@ DEFAULT_LICENSE_FILES = {
}
-@pytest.fixture(scope='module')
+@pytest.fixture
def dummy_dist(tmpdir_factory):
basedir = tmpdir_factory.mktemp('dummy_dist')
basedir.join('setup.py').write("""\
@@ -113,3 +115,16 @@ def test_limited_abi(monkeypatch, tmpdir):
monkeypatch.chdir(source_dir)
subprocess.check_call([sys.executable, 'setup.py', 'bdist_wheel', '-b', str(build_dir),
'-d', str(dist_dir)])
+
+
+def test_build_from_readonly_tree(dummy_dist, monkeypatch, tmpdir):
+ basedir = str(tmpdir.join('dummy'))
+ shutil.copytree(str(dummy_dist), basedir)
+ monkeypatch.chdir(basedir)
+
+ # Make the tree read-only
+ for root, dirs, files in os.walk(basedir):
+ for fname in files:
+ os.chmod(os.path.join(root, fname), stat.S_IREAD)
+
+ subprocess.check_call([sys.executable, 'setup.py', 'bdist_wheel'])