Skip to content

Commit 3e515b0

Browse files
committed
Merge branch 'jk/remote-helpers-in-python-3'
Prepare remote-helper test written in Python to be run with Python3. * jk/remote-helpers-in-python-3: git_remote_helpers: remove GIT-PYTHON-VERSION upon "clean" git-remote-testpy: fix path hashing on Python 3 git-remote-testpy: call print as a function git-remote-testpy: don't do unbuffered text I/O git-remote-testpy: hash bytes explicitly svn-fe: allow svnrdump_sim.py to run with Python 3 git_remote_helpers: use 2to3 if building with Python 3 git_remote_helpers: force rebuild if python version changes git_remote_helpers: fix input when running under Python 3 git_remote_helpers: allow building with Python 3
2 parents 9aea11d + ae6037b commit 3e515b0

File tree

6 files changed

+69
-29
lines changed

6 files changed

+69
-29
lines changed

contrib/svn-fe/svnrdump_sim.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
def getrevlimit():
1616
var = 'SVNRMAX'
17-
if os.environ.has_key(var):
17+
if var in os.environ:
1818
return os.environ[var]
1919
return None
2020

@@ -44,7 +44,7 @@ def writedump(url, lower, upper):
4444

4545
if __name__ == "__main__":
4646
if not (len(sys.argv) in (3, 4, 5)):
47-
print "usage: %s dump URL -rLOWER:UPPER"
47+
print("usage: %s dump URL -rLOWER:UPPER")
4848
sys.exit(1)
4949
if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
5050
url = sys.argv[2]

git-remote-testpy.py

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,27 @@
3131
from git_remote_helpers.git.importer import GitImporter
3232
from git_remote_helpers.git.non_local import NonLocalGit
3333

34-
if sys.hexversion < 0x01050200:
35-
# os.makedirs() is the limiter
36-
sys.stderr.write("git-remote-testgit: requires Python 1.5.2 or later.\n")
34+
if sys.hexversion < 0x02000000:
35+
# string.encode() is the limiter
36+
sys.stderr.write("git-remote-testgit: requires Python 2.0 or later.\n")
3737
sys.exit(1)
3838

39+
40+
def encode_filepath(path):
41+
"""Encodes a Unicode file path to a byte string.
42+
43+
On Python 2 this is a no-op; on Python 3 we encode the string as
44+
suggested by [1] which allows an exact round-trip from the command line
45+
to the filesystem.
46+
47+
[1] http://docs.python.org/3/c-api/unicode.html#file-system-encoding
48+
49+
"""
50+
if sys.hexversion < 0x03000000:
51+
return path
52+
return path.encode(sys.getfilesystemencoding(), 'surrogateescape')
53+
54+
3955
def get_repo(alias, url):
4056
"""Returns a git repository object initialized for usage.
4157
"""
@@ -45,7 +61,7 @@ def get_repo(alias, url):
4561
repo.get_head()
4662

4763
hasher = _digest()
48-
hasher.update(repo.path)
64+
hasher.update(encode_filepath(repo.path))
4965
repo.hash = hasher.hexdigest()
5066

5167
repo.get_base_path = lambda base: os.path.join(
@@ -87,9 +103,9 @@ def do_capabilities(repo, args):
87103
"""Prints the supported capabilities.
88104
"""
89105

90-
print "import"
91-
print "export"
92-
print "refspec refs/heads/*:%s*" % repo.prefix
106+
print("import")
107+
print("export")
108+
print("refspec refs/heads/*:%s*" % repo.prefix)
93109

94110
dirname = repo.get_base_path(repo.gitdir)
95111

@@ -98,11 +114,11 @@ def do_capabilities(repo, args):
98114

99115
path = os.path.join(dirname, 'git.marks')
100116

101-
print "*export-marks %s" % path
117+
print("*export-marks %s" % path)
102118
if os.path.exists(path):
103-
print "*import-marks %s" % path
119+
print("*import-marks %s" % path)
104120

105-
print # end capabilities
121+
print('') # end capabilities
106122

107123

108124
def do_list(repo, args):
@@ -115,16 +131,16 @@ def do_list(repo, args):
115131

116132
for ref in repo.revs:
117133
debug("? refs/heads/%s", ref)
118-
print "? refs/heads/%s" % ref
134+
print("? refs/heads/%s" % ref)
119135

120136
if repo.head:
121137
debug("@refs/heads/%s HEAD" % repo.head)
122-
print "@refs/heads/%s HEAD" % repo.head
138+
print("@refs/heads/%s HEAD" % repo.head)
123139
else:
124140
debug("@refs/heads/master HEAD")
125-
print "@refs/heads/master HEAD"
141+
print("@refs/heads/master HEAD")
126142

127-
print # end list
143+
print('') # end list
128144

129145

130146
def update_local_repo(repo):
@@ -154,7 +170,7 @@ def do_import(repo, args):
154170
refs = [ref]
155171

156172
while True:
157-
line = sys.stdin.readline()
173+
line = sys.stdin.readline().decode()
158174
if line == '\n':
159175
break
160176
if not line.startswith('import '):
@@ -164,15 +180,15 @@ def do_import(repo, args):
164180
ref = line[7:].strip()
165181
refs.append(ref)
166182

167-
print "feature done"
183+
print("feature done")
168184

169185
if os.environ.get("GIT_REMOTE_TESTGIT_FAILURE"):
170186
die('Told to fail')
171187

172188
repo = update_local_repo(repo)
173189
repo.exporter.export_repo(repo.gitdir, refs)
174190

175-
print "done"
191+
print("done")
176192

177193

178194
def do_export(repo, args):
@@ -192,8 +208,8 @@ def do_export(repo, args):
192208
repo.non_local.push(repo.gitdir)
193209

194210
for ref in changed:
195-
print "ok %s" % ref
196-
print
211+
print("ok %s" % ref)
212+
print('')
197213

198214

199215
COMMANDS = {
@@ -225,7 +241,7 @@ def read_one_line(repo):
225241

226242
line = sys.stdin.readline()
227243

228-
cmdline = line
244+
cmdline = line.decode()
229245

230246
if not cmdline:
231247
warn("Unexpected EOF")
@@ -277,7 +293,11 @@ def main(args):
277293

278294
more = True
279295

280-
sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
296+
# Use binary mode since Python 3 does not permit unbuffered I/O in text
297+
# mode. Unbuffered I/O is required to avoid data that should be going
298+
# to git-fast-import after an "export" command getting caught in our
299+
# stdin buffer instead.
300+
sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
281301
while (more):
282302
more = read_one_line(repo)
283303

git_remote_helpers/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
/GIT-PYTHON-VERSION
12
/build
23
/dist

git_remote_helpers/Makefile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@ endif
2323

2424
PYLIBDIR=$(shell $(PYTHON_PATH) -c \
2525
"import sys; \
26-
print 'lib/python%i.%i/site-packages' % sys.version_info[:2]")
26+
print('lib/python%i.%i/site-packages' % sys.version_info[:2])")
27+
28+
py_version=$(shell $(PYTHON_PATH) -c \
29+
'import sys; print("%i.%i" % sys.version_info[:2])')
2730

2831
all: $(pysetupfile)
29-
$(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build
32+
$(QUIET)test "$$(cat GIT-PYTHON-VERSION 2>/dev/null)" = "$(py_version)" || \
33+
flags=--force; \
34+
$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build $$flags
35+
$(QUIET)echo "$(py_version)" >GIT-PYTHON-VERSION
3036

3137
install: $(pysetupfile)
3238
$(PYTHON_PATH) $(pysetupfile) install --prefix $(DESTDIR_SQ)$(prefix)
@@ -36,4 +42,4 @@ instlibdir: $(pysetupfile)
3642

3743
clean:
3844
$(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) clean -a
39-
$(RM) *.pyo *.pyc
45+
$(RM) *.pyo *.pyc GIT-PYTHON-VERSION

git_remote_helpers/git/importer.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ def __init__(self, repo):
1818

1919
def get_refs(self, gitdir):
2020
"""Returns a dictionary with refs.
21+
22+
Note that the keys in the returned dictionary are byte strings as
23+
read from git.
2124
"""
2225
args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
23-
lines = check_output(args).strip().split('\n')
26+
lines = check_output(args).strip().split('\n'.encode('ascii'))
2427
refs = {}
2528
for line in lines:
26-
value, name = line.split(' ')
27-
name = name.strip('commit\t')
29+
value, name = line.split(' '.encode('ascii'))
30+
name = name.strip('commit\t'.encode('ascii'))
2831
refs[name] = value
2932
return refs
3033

git_remote_helpers/setup.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
from distutils.core import setup
66

7+
# If building under Python3 we need to run 2to3 on the code, do this by
8+
# trying to import distutils' 2to3 builder, which is only available in
9+
# Python3.
10+
try:
11+
from distutils.command.build_py import build_py_2to3 as build_py
12+
except ImportError:
13+
# 2.x
14+
from distutils.command.build_py import build_py
15+
716
setup(
817
name = 'git_remote_helpers',
918
version = '0.1.0',
@@ -14,4 +23,5 @@
1423
url = 'http://www.git-scm.com/',
1524
package_dir = {'git_remote_helpers': ''},
1625
packages = ['git_remote_helpers', 'git_remote_helpers.git'],
26+
cmdclass = {'build_py': build_py},
1727
)

0 commit comments

Comments
 (0)