diff --git a/flit/vcs/git.py b/flit/vcs/git.py index cb8890c7..d8376cbd 100644 --- a/flit/vcs/git.py +++ b/flit/vcs/git.py @@ -1,4 +1,5 @@ import os +import os.path as osp from subprocess import check_output name = 'git' @@ -6,10 +7,12 @@ def list_tracked_files(directory): outb = check_output(['git', 'ls-files', '--recurse-submodules', '-z'], cwd=str(directory)) - return [os.fsdecode(l) for l in outb.strip(b'\0').split(b'\0') if l] + # NOTE: os.fsdecode() may cause issues if git returns path names that + # aren't in the filesystem encoding + return [osp.normpath(os.fsdecode(l)) for l in outb.strip(b'\0').split(b'\0') if l] def list_untracked_deleted_files(directory): outb = check_output(['git', 'ls-files', '--deleted', '--others', '--exclude-standard', '-z'], cwd=str(directory)) - return [os.fsdecode(l) for l in outb.strip(b'\0').split(b'\0') if l] + return [osp.normpath(os.fsdecode(l)) for l in outb.strip(b'\0').split(b'\0') if l] diff --git a/tests/test_build.py b/tests/test_build.py index 59dd90e7..f4002db4 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -12,19 +12,36 @@ LIST_FILES_TEMPLATE = """\ #!{python} -import sys -from os.path import join -if '--deleted' not in sys.argv: - files = ['pyproject.toml', '{module}', 'EG_README.rst'] - print('\\0'.join(files), end='\\0') +import sys, posixpath +tracked = {tracked} +untracked_deleted = {untracked_deleted} + +if '--deleted' in sys.argv: + files = untracked_deleted +else: + files = tracked + +for filename in map(posixpath.normpath, files): + print(filename, end='\\0') """ +MODULE1_TOML_FILES = ['EG_README.rst', 'module1.py', 'pyproject.toml'] + +def make_git_script( + tracked = MODULE1_TOML_FILES, + untracked_deleted = ['dist/module1-0.1.tar.gz'] +): + return LIST_FILES_TEMPLATE.format( + python=sys.executable, + tracked=tracked, + untracked_deleted=untracked_deleted, + ) + def test_build_main(copy_sample): td = copy_sample('module1_toml') (td / '.git').mkdir() # Fake a git repo - with MockCommand('git', LIST_FILES_TEMPLATE.format( - python=sys.executable, module='module1.py')): + with MockCommand('git', make_git_script()): res = build.main(td / 'pyproject.toml') assert res.wheel.file.suffix == '.whl' assert res.sdist.file.name.endswith('.tar.gz') @@ -35,8 +52,7 @@ def test_build_sdist_only(copy_sample): td = copy_sample('module1_toml') (td / '.git').mkdir() # Fake a git repo - with MockCommand('git', LIST_FILES_TEMPLATE.format( - python=sys.executable, module='module1.py')): + with MockCommand('git', make_git_script()): res = build.main(td / 'pyproject.toml', formats={'sdist'}) assert res.wheel is None @@ -47,8 +63,7 @@ def test_build_wheel_only(copy_sample): td = copy_sample('module1_toml') (td / '.git').mkdir() # Fake a git repo - with MockCommand('git', LIST_FILES_TEMPLATE.format( - python=sys.executable, module='module1.py')): + with MockCommand('git', make_git_script()): res = build.main(td / 'pyproject.toml', formats={'wheel'}) assert res.sdist is None @@ -58,9 +73,15 @@ def test_build_wheel_only(copy_sample): def test_build_ns_main(copy_sample): td = copy_sample('ns1-pkg') (td / '.git').mkdir() # Fake a git repo - - with MockCommand('git', LIST_FILES_TEMPLATE.format( - python=sys.executable, module='ns1/pkg/__init__.py')): + tracked = [ + 'EG_README.rst', + 'ns1/pkg/__init__.py', + 'pyproject.toml', + ] + untracked_deleted = ['dist/ns1.pkg-0.1.tar.gz'] + + with MockCommand('git', make_git_script(tracked=tracked, + untracked_deleted=untracked_deleted)): res = build.main(td / 'pyproject.toml') assert res.wheel.file.suffix == '.whl' assert res.sdist.file.name.endswith('.tar.gz') @@ -75,10 +96,25 @@ def test_build_module_no_docstring(): shutil.copy(str(samples_dir / 'no_docstring.py'), td) shutil.copy(str(samples_dir / 'EG_README.rst'), td) Path(td, '.git').mkdir() # Fake a git repo + tracked = [ + 'pyproject.toml', + 'no_docstring.py', + 'EG_README.rst', + ] - - with MockCommand('git', LIST_FILES_TEMPLATE.format( - python=sys.executable, module='no_docstring.py')): + with MockCommand('git', make_git_script(tracked=tracked)): with pytest.raises(common.NoDocstringError) as exc_info: build.main(pyproject) assert 'no_docstring.py' in str(exc_info.value) + +def test_rebuild(copy_sample): + """ + build artifacts should not cause subsequent builds to fail if no other + files were changed + """ + td = copy_sample('module1_toml') + (td / '.git').mkdir() # Fake a git repo + + with MockCommand('git', make_git_script()): + res = build.main(td / 'pyproject.toml') + res = build.main(td / 'pyproject.toml')