Today, I tried to setup hgwebdir.cgi to access my mercurial repositories using Apache on Windows. Everything went fine until I tried to clone one of the repositories on my laptop:
Traceback (most recent call last):
File "hg", line 38, in
File "mercurial\dispatch.pyc", line 16, in run
File "mercurial\dispatch.pyc", line 27, in dispatch
File "mercurial\dispatch.pyc", line 43, in _runcatch
File "mercurial\dispatch.pyc", line 449, in _dispatch
File "mercurial\dispatch.pyc", line 317, in runcommand
File "mercurial\dispatch.pyc", line 501, in _runcommand
File "mercurial\dispatch.pyc", line 454, in checkargs
File "mercurial\dispatch.pyc", line 448, in
File "mercurial\util.pyc", line 402, in check
File "mercurial\commands.pyc", line 636, in clone
File "mercurial\hg.pyc", line 286, in clone
File "mercurial\localrepo.pyc", line 2177, in clone
File "mercurial\localrepo.pyc", line 1466, in pull
File "mercurial\localrepo.pyc", line 2043, in addchangegroup
File "mercurial\revlog.pyc", line 1210, in addgroup
File "mercurial\changegroup.pyc", line 30, in chunkiter
File "mercurial\changegroup.pyc", line 14, in getchunk
File "mercurial\util.pyc", line 925, in read
File "mercurial\httprepo.pyc", line 19, in zgenerator
zlib.error: Error -3 while decompressing: invalid distance too far back
After digging through hgwebdir.cgi, cgi.py, webutil.py, socket.py, etc., I found the cause of the problem:
Python opens stdout in text mode.
That’s OK on Linux (because there seems to be no difference between text mode and binary mode), but it is a problem on Windows, where in text mode, \n is translated to \r\n. This breaks any binary file transfer that contains \n.
I found a solution here: Change the first line of hgwebdir.cgi from
#!C:\Python26\python.exe
to
#!C:\Python26\python.exe -u
to tell Python to open stdout in binary mode. Problem solved.