Skip to content

Commit 7253898

Browse files
committed
Refactor hg and git file finders to use the same algorithm
Also make the test parametric.
1 parent 9b36312 commit 7253898

File tree

6 files changed

+98
-38
lines changed

6 files changed

+98
-38
lines changed

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ def parse(root):
8181
pip-egg-info = setuptools_scm.hacks:parse_pip_egg_info
8282
8383
[setuptools_scm.files_command]
84-
.hg = setuptools_scm.hg:FILES_COMMAND
85-
.git = setuptools_scm.git_file_finder:find_files
84+
.hg = setuptools_scm.file_finder_hg:hg_find_files
85+
.git = setuptools_scm.file_finder_git:git_find_files
8686
8787
[setuptools_scm.version_scheme]
8888
guess-next-dev = setuptools_scm.version:guess_next_dev_version

setuptools_scm/file_finder.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
3+
4+
def scm_find_files(path, scm_files, scm_dirs):
5+
""" setuptools compatible file finder that follows symlinks
6+
7+
- path: the root directory from which to search
8+
- scm_files: set of scm controlled files
9+
- scm_files: set of scm controlled directories
10+
11+
scm_files and scm_dirs must be absolute with symlinks resolved (realpath),
12+
with normalized case (normcase)
13+
14+
Spec here: http://setuptools.readthedocs.io/en/latest/setuptools.html#\
15+
adding-support-for-revision-control-systems
16+
"""
17+
realpath = os.path.normcase(os.path.realpath(path))
18+
seen = set()
19+
res = []
20+
for dirpath, dirnames, filenames in os.walk(realpath, followlinks=True):
21+
# dirpath with symlinks resolved
22+
realdirpath = os.path.normcase(os.path.realpath(dirpath))
23+
if realdirpath not in scm_dirs or realdirpath in seen:
24+
dirnames[:] = []
25+
continue
26+
for filename in filenames:
27+
# dirpath + filename with symlinks preserved
28+
fullfilename = os.path.join(dirpath, filename)
29+
if os.path.normcase(os.path.realpath(fullfilename)) in scm_files:
30+
res.append(
31+
os.path.join(path, os.path.relpath(fullfilename, path)))
32+
seen.add(realdirpath)
33+
return res

setuptools_scm/git_file_finder.py renamed to setuptools_scm/file_finder_git.py

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import subprocess
33
import tarfile
44

5+
from .file_finder import scm_find_files
6+
57

68
def _git_toplevel(path):
79
try:
@@ -35,31 +37,9 @@ def _git_ls_files_and_dirs(toplevel):
3537
return git_files, git_dirs
3638

3739

38-
def find_files(path=''):
39-
""" setuptools compatible git file finder that follows symlinks
40-
41-
Spec here: http://setuptools.readthedocs.io/en/latest/setuptools.html#\
42-
adding-support-for-revision-control-systems
43-
"""
40+
def git_find_files(path=''):
4441
toplevel = _git_toplevel(path)
4542
if not toplevel:
4643
return []
4744
git_files, git_dirs = _git_ls_files_and_dirs(toplevel)
48-
realpath = os.path.normcase(os.path.realpath(path))
49-
assert realpath.startswith(toplevel)
50-
seen = set()
51-
res = []
52-
for dirpath, dirnames, filenames in os.walk(realpath, followlinks=True):
53-
# dirpath with symlinks resolved
54-
realdirpath = os.path.normcase(os.path.realpath(dirpath))
55-
if realdirpath not in git_dirs or realdirpath in seen:
56-
dirnames[:] = []
57-
continue
58-
for filename in filenames:
59-
# dirpath + filename with symlinks preserved
60-
fullfilename = os.path.join(dirpath, filename)
61-
if os.path.normcase(os.path.realpath(fullfilename)) in git_files:
62-
res.append(
63-
os.path.join(path, os.path.relpath(fullfilename, path)))
64-
seen.add(realdirpath)
65-
return res
45+
return scm_find_files(path, git_files, git_dirs)

setuptools_scm/file_finder_hg.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import os
2+
import subprocess
3+
4+
from .file_finder import scm_find_files
5+
6+
7+
def _hg_toplevel(path):
8+
try:
9+
with open(os.devnull, 'wb') as devnull:
10+
out = subprocess.check_output([
11+
'hg', 'root',
12+
], cwd=(path or '.'), universal_newlines=True, stderr=devnull)
13+
return os.path.normcase(os.path.realpath(out.strip()))
14+
except subprocess.CalledProcessError:
15+
# hg returned error, we are not in a mercurial repo
16+
return None
17+
except OSError:
18+
# hg command not found, probably
19+
return None
20+
21+
22+
def _hg_ls_files_and_dirs(toplevel):
23+
hg_files = set()
24+
hg_dirs = set([toplevel])
25+
out = subprocess.check_output([
26+
'hg', 'files',
27+
], cwd=toplevel, universal_newlines=True)
28+
for name in out.split():
29+
name = os.path.normcase(name).replace('/', os.path.sep)
30+
fullname = os.path.join(toplevel, name)
31+
hg_files.add(fullname)
32+
dirname = os.path.dirname(fullname)
33+
while len(dirname) > len(toplevel) and dirname not in hg_dirs:
34+
hg_dirs.add(dirname)
35+
dirname = os.path.dirname(dirname)
36+
return hg_files, hg_dirs
37+
38+
39+
def hg_find_files(path=''):
40+
toplevel = _hg_toplevel(path)
41+
if not toplevel:
42+
return []
43+
hg_files, hg_dirs = _hg_ls_files_and_dirs(toplevel)
44+
return scm_find_files(path, hg_files, hg_dirs)

setuptools_scm/hg.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from .utils import do, trace, data_from_mime, has_command
33
from .version import meta, tags_to_versions
44

5-
FILES_COMMAND = 'hg locate -I .'
6-
75

86
def _hg_tagdist_normalize_tagcommit(root, tag, dist, node, branch):
97
dirty = node.endswith('+')

testing/test_git_file_finder.py renamed to testing/test_file_finder.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33

44
import pytest
55

6-
from setuptools_scm.git_file_finder import find_files
7-
8-
9-
@pytest.fixture
10-
def inwd(wd):
11-
wd('git init')
12-
wd('git config user.email [email protected]')
13-
wd('git config user.name "a test"')
14-
wd.add_command = 'git add .'
15-
wd.commit_command = 'git commit -m test-{reason}'
6+
from setuptools_scm.integration import find_files
7+
8+
9+
@pytest.fixture(params=['git', 'hg'])
10+
def inwd(request, wd):
11+
if request.param == 'git':
12+
wd('git init')
13+
wd('git config user.email [email protected]')
14+
wd('git config user.name "a test"')
15+
wd.add_command = 'git add .'
16+
wd.commit_command = 'git commit -m test-{reason}'
17+
elif request.param == 'hg':
18+
wd('hg init')
19+
wd.add_command = 'hg add .'
20+
wd.commit_command = 'hg commit -m test-{reason} -u test -d "0 0"'
1621
(wd.cwd / 'file1').ensure(file=True)
1722
adir = (wd.cwd / 'adir').ensure(dir=True)
1823
(adir / 'filea').ensure(file=True)

0 commit comments

Comments
 (0)