From 55c4c7ca378e617a694a253e0ba304a4e0f6dd6c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 25 May 2020 11:00:15 -0400 Subject: Revert part of 8f7c2fb39c8fddafb4197d7998056f47db43b7d6 --- .github/workflows/python-tests.yml | 6 +- setup.cfg | 1 - src/setuptools_scm/git.py | 5 +- src/setuptools_scm/win_py31_compat.py | 214 ++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 src/setuptools_scm/win_py31_compat.py diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 9099eb2..d8f8ead 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -61,7 +61,7 @@ jobs: architecture: x64 # self install testing needs some clarity # so its being executed without any other tools running - - run: pip install -U setuptools jaraco.windows + - run: pip install -U setuptools - run: python setup.py egg_info - run: python setup.py sdist - run: easy_install dist/* @@ -93,7 +93,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install --upgrade wheel setuptools jaraco.windows + pip install --upgrade wheel setuptools - run: python setup.py egg_info - name: Build package run: python setup.py bdist_egg @@ -115,7 +115,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install --upgrade wheel setuptools jaraco.windows + pip install --upgrade wheel setuptools - run: python setup.py egg_info - name: Build package run: python setup.py bdist_wheel sdist diff --git a/setup.cfg b/setup.cfg index b079bd8..c8f46a1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,6 @@ zip_safe = true python_requires= >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* install_requires= setuptools - jaraco.windows; python_version=="2.7" packages=find: package_dir= =src diff --git a/src/setuptools_scm/git.py b/src/setuptools_scm/git.py index b717584..76be436 100644 --- a/src/setuptools_scm/git.py +++ b/src/setuptools_scm/git.py @@ -6,7 +6,10 @@ from os.path import isfile, join import warnings -from os.path import samefile +try: + from os.path import samefile +except ImportError: + from .win_py31_compat import samefile DEFAULT_DESCRIBE = "git describe --dirty --tags --long --match *[0-9]*" diff --git a/src/setuptools_scm/win_py31_compat.py b/src/setuptools_scm/win_py31_compat.py new file mode 100644 index 0000000..82a11eb --- /dev/null +++ b/src/setuptools_scm/win_py31_compat.py @@ -0,0 +1,214 @@ +""" +Backport of os.path.samefile for Python prior to 3.2 +on Windows from jaraco.windows 3.8. + +DON'T EDIT THIS FILE! + +Instead, file tickets and PR's with `jaraco.windows +`_ and request +a port to setuptools_scm. +""" + +import os +import nt +import posixpath +import ctypes.wintypes +import sys +import __builtin__ as builtins + + +## +# From jaraco.windows.error + +def format_system_message(errno): + """ + Call FormatMessage with a system error number to retrieve + the descriptive error message. + """ + # first some flags used by FormatMessageW + ALLOCATE_BUFFER = 0x100 + FROM_SYSTEM = 0x1000 + + # Let FormatMessageW allocate the buffer (we'll free it below) + # Also, let it know we want a system error message. + flags = ALLOCATE_BUFFER | FROM_SYSTEM + source = None + message_id = errno + language_id = 0 + result_buffer = ctypes.wintypes.LPWSTR() + buffer_size = 0 + arguments = None + bytes = ctypes.windll.kernel32.FormatMessageW( + flags, + source, + message_id, + language_id, + ctypes.byref(result_buffer), + buffer_size, + arguments, + ) + # note the following will cause an infinite loop if GetLastError + # repeatedly returns an error that cannot be formatted, although + # this should not happen. + handle_nonzero_success(bytes) + message = result_buffer.value + ctypes.windll.kernel32.LocalFree(result_buffer) + return message + + +class WindowsError(builtins.WindowsError): + """ + More info about errors at + http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx + """ + + def __init__(self, value=None): + if value is None: + value = ctypes.windll.kernel32.GetLastError() + strerror = format_system_message(value) + if sys.version_info > (3, 3): + args = 0, strerror, None, value + else: + args = value, strerror + super(WindowsError, self).__init__(*args) + + @property + def message(self): + return self.strerror + + @property + def code(self): + return self.winerror + + def __str__(self): + return self.message + + def __repr__(self): + return '{self.__class__.__name__}({self.winerror})'.format(**vars()) + + +def handle_nonzero_success(result): + if result == 0: + raise WindowsError() + + +## +# From jaraco.windows.api.filesystem + +FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 +FILE_FLAG_BACKUP_SEMANTICS = 0x2000000 +OPEN_EXISTING = 3 +FILE_ATTRIBUTE_NORMAL = 0x80 +FILE_READ_ATTRIBUTES = 0x80 +INVALID_HANDLE_VALUE = ctypes.wintypes.HANDLE(-1).value + + +class BY_HANDLE_FILE_INFORMATION(ctypes.Structure): + _fields_ = [ + ('file_attributes', ctypes.wintypes.DWORD), + ('creation_time', ctypes.wintypes.FILETIME), + ('last_access_time', ctypes.wintypes.FILETIME), + ('last_write_time', ctypes.wintypes.FILETIME), + ('volume_serial_number', ctypes.wintypes.DWORD), + ('file_size_high', ctypes.wintypes.DWORD), + ('file_size_low', ctypes.wintypes.DWORD), + ('number_of_links', ctypes.wintypes.DWORD), + ('file_index_high', ctypes.wintypes.DWORD), + ('file_index_low', ctypes.wintypes.DWORD), + ] + + @property + def file_size(self): + return (self.file_size_high << 32) + self.file_size_low + + @property + def file_index(self): + return (self.file_index_high << 32) + self.file_index_low + + +class SECURITY_ATTRIBUTES(ctypes.Structure): + _fields_ = ( + ('length', ctypes.wintypes.DWORD), + ('p_security_descriptor', ctypes.wintypes.LPVOID), + ('inherit_handle', ctypes.wintypes.BOOLEAN), + ) + + +LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES) + + +CreateFile = ctypes.windll.kernel32.CreateFileW +CreateFile.argtypes = ( + ctypes.wintypes.LPWSTR, + ctypes.wintypes.DWORD, + ctypes.wintypes.DWORD, + LPSECURITY_ATTRIBUTES, + ctypes.wintypes.DWORD, + ctypes.wintypes.DWORD, + ctypes.wintypes.HANDLE, +) +CreateFile.restype = ctypes.wintypes.HANDLE + +GetFileInformationByHandle = ctypes.windll.kernel32.GetFileInformationByHandle +GetFileInformationByHandle.restype = ctypes.wintypes.BOOL +GetFileInformationByHandle.argtypes = ( + ctypes.wintypes.HANDLE, + ctypes.POINTER(BY_HANDLE_FILE_INFORMATION), +) + + +## +# From jaraco.windows.filesystem + +def compat_stat(path): + """ + Generate stat as found on Python 3.2 and later. + """ + stat = os.stat(path) + info = get_file_info(path) + # rewrite st_ino, st_dev, and st_nlink based on file info + return nt.stat_result( + (stat.st_mode,) + + (info.file_index, info.volume_serial_number, info.number_of_links) + + stat[4:] + ) + + +def samefile(f1, f2): + """ + Backport of samefile from Python 3.2 with support for Windows. + """ + return posixpath.samestat(compat_stat(f1), compat_stat(f2)) + + +def get_file_info(path): + # open the file the same way CPython does in posixmodule.c + desired_access = FILE_READ_ATTRIBUTES + share_mode = 0 + security_attributes = None + creation_disposition = OPEN_EXISTING + flags_and_attributes = ( + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT + ) + template_file = None + + handle = CreateFile( + path, + desired_access, + share_mode, + security_attributes, + creation_disposition, + flags_and_attributes, + template_file, + ) + + if handle == INVALID_HANDLE_VALUE: + raise WindowsError() + + info = BY_HANDLE_FILE_INFORMATION() + res = GetFileInformationByHandle(handle, info) + handle_nonzero_success(res) + + return info -- cgit v1.2.1 From c17e67f53860b26d265e55ded196be8495a99077 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 25 May 2020 10:49:04 -0400 Subject: Adding Windows + Py 2.7 test, skips --- .github/workflows/python-tests.yml | 2 -- testing/test_file_finder.py | 2 ++ testing/test_git.py | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index d8f8ead..ca8df3f 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -18,8 +18,6 @@ jobs: python_version: [ '2.7', '3.5', '3.6', '3.7', '3.8', 'pypy2', 'pypy3' ] os: [windows-latest, ubuntu-latest] #, macos-latest] exclude: - - os: windows-latest - python_version: "2.7" - os: windows-latest python_version: "pypy2" include: diff --git a/testing/test_file_finder.py b/testing/test_file_finder.py index a6e3d70..463d3d4 100644 --- a/testing/test_file_finder.py +++ b/testing/test_file_finder.py @@ -9,6 +9,8 @@ from setuptools_scm.integration import find_files @pytest.fixture(params=["git", "hg"]) def inwd(request, wd, monkeypatch): if request.param == "git": + if sys.platform == "win32" and sys.version_info[0] < 3: + pytest.skip("Long/short path names supported on Windows Python 2.7") try: wd("git init") except OSError: diff --git a/testing/test_git.py b/testing/test_git.py index e485fc7..e92d19a 100644 --- a/testing/test_git.py +++ b/testing/test_git.py @@ -10,6 +10,12 @@ from setuptools_scm.file_finder_git import git_find_files import warnings +skip_if_win_27 = pytest.mark.skipif( + sys.platform == "win32" and sys.version_info[0] < 3, + reason="Not supported on Windows + Python 2.7", +) + + with warnings.catch_warnings(): warnings.filterwarnings("ignore") if not has_command("git"): @@ -186,6 +192,7 @@ def test_alphanumeric_tags_match(wd): assert wd.version.startswith("0.1.dev1+g") +@skip_if_win_27 def test_git_archive_export_ignore(wd, monkeypatch): wd.write("test1.txt", "test") wd.write("test2.txt", "test") @@ -201,6 +208,7 @@ def test_git_archive_export_ignore(wd, monkeypatch): assert integration.find_files(".") == [opj(".", "test1.txt")] +@skip_if_win_27 @pytest.mark.issue(228) def test_git_archive_subdirectory(wd, monkeypatch): wd("mkdir foobar") @@ -211,6 +219,7 @@ def test_git_archive_subdirectory(wd, monkeypatch): assert integration.find_files(".") == [opj(".", "foobar", "test1.txt")] +@skip_if_win_27 @pytest.mark.issue(251) def test_git_archive_run_from_subdirectory(wd, monkeypatch): wd("mkdir foobar") -- cgit v1.2.1