3131from git_remote_helpers .git .importer import GitImporter
3232from 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+
3955def 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
108124def 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
130146def 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
178194def 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
199215COMMANDS = {
@@ -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
0 commit comments