# HG changeset patch # User Thomas Arendsen Hein # Date 1145475463 -7200 # Node ID cd7cb896396bca257f0f98318b009801380391a3 # Parent fb8b35b0def9239fa3155d3721490cf5e558a753# Parent 190c6a81e6adee29699f086c7858293837c1ce2b Merge with cmason diff --git a/contrib/win32/ReadMe.html b/contrib/win32/ReadMe.html --- a/contrib/win32/ReadMe.html +++ b/contrib/win32/ReadMe.html @@ -2,6 +2,15 @@ Mercurial for Windows + + @@ -12,10 +21,14 @@

Mercurial is a command-line application. You must run it from the Windows command prompt (or if you're hard core, a MinGW shell).

+ +

Note: the standard MinGW msys startup script uses + rxvt which has problems setting up standard input and output. + Running bash directly works correctly.

For documentation, please visit the Mercurial web - site.

+ href="http://www.selenic.com/mercurial">Mercurial web site.

By default, Mercurial installs to C:\Mercurial. The Mercurial command is called hg.exe. To run this diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -625,7 +625,10 @@ class queue: try: repo.wfile(f, "w").write(t) except IOError: - os.makedirs(os.path.dirname(repo.wjoin(f))) + try: + os.makedirs(os.path.dirname(repo.wjoin(f))) + except OSError, err: + if err.errno != errno.EEXIST: raise repo.wfile(f, "w").write(t) if not wlock: diff --git a/mercurial/appendfile.py b/mercurial/appendfile.py --- a/mercurial/appendfile.py +++ b/mercurial/appendfile.py @@ -6,7 +6,7 @@ # of the GNU General Public License, incorporated herein by reference. from demandload import * -demandload(globals(), "cStringIO changelog manifest os tempfile") +demandload(globals(), "cStringIO changelog errno manifest os tempfile") # writes to metadata files are ordered. reads: changelog, manifest, # normal files. writes: normal files, manifest, changelog. @@ -33,18 +33,32 @@ class appendfile(object): file and temp file. readers cannot see appended data until writedata called.''' - def __init__(self, fp): - fd, self.tmpname = tempfile.mkstemp() - self.tmpfp = os.fdopen(fd, 'ab+') + def __init__(self, fp, tmpname): + if tmpname: + self.tmpname = tmpname + self.tmpfp = open(self.tmpname, 'ab+') + else: + fd, self.tmpname = tempfile.mkstemp() + self.tmpfp = os.fdopen(fd, 'ab+') self.realfp = fp self.offset = fp.tell() # real file is not written by anyone else. cache its size so # seek and read can be fast. - self.fpsize = os.fstat(fp.fileno()).st_size + self.realsize = os.fstat(fp.fileno()).st_size def end(self): self.tmpfp.flush() # make sure the stat is correct - return self.fpsize + os.fstat(self.tmpfp.fileno()).st_size + return self.realsize + os.fstat(self.tmpfp.fileno()).st_size + + def tell(self): + return self.offset + + def flush(self): + self.tmpfp.flush() + + def close(self): + self.realfp.close() + self.tmpfp.close() def seek(self, offset, whence=0): '''virtual file offset spans real file and temp file.''' @@ -55,16 +69,16 @@ class appendfile(object): elif whence == 2: self.offset = self.end() + offset - if self.offset < self.fpsize: + if self.offset < self.realsize: self.realfp.seek(self.offset) else: - self.tmpfp.seek(self.offset - self.fpsize) + self.tmpfp.seek(self.offset - self.realsize) def read(self, count=-1): '''only trick here is reads that span real file and temp file.''' fp = cStringIO.StringIO() old_offset = self.offset - if self.offset < self.fpsize: + if self.offset < self.realsize: s = self.realfp.read(count) fp.write(s) self.offset += len(s) @@ -72,7 +86,7 @@ class appendfile(object): count -= len(s) if count != 0: if old_offset != self.offset: - self.tmpfp.seek(self.offset - self.fpsize) + self.tmpfp.seek(self.offset - self.realsize) s = self.tmpfp.read(count) fp.write(s) self.offset += len(s) @@ -83,98 +97,47 @@ class appendfile(object): self.tmpfp.seek(0, 2) self.tmpfp.write(s) # all writes are appends, so offset must go to end of file. - self.offset = self.fpsize + self.tmpfp.tell() - - def writedata(self): - '''copy data from temp file to real file.''' - self.tmpfp.seek(0) - s = self.tmpfp.read() - self.tmpfp.close() - self.realfp.seek(0, 2) - # small race here. we write all new data in one call, but - # reader can see partial update due to python or os. file - # locking no help: slow, not portable, not reliable over nfs. - # only safe thing is write to temp file every time and rename, - # but performance bad when manifest or changelog gets big. - self.realfp.write(s) - self.realfp.close() - - def __del__(self): - '''delete temp file even if exception raised.''' - try: os.unlink(self.tmpname) - except: pass - -class sharedfile(object): - '''let file objects share a single appendfile safely. each - sharedfile has own offset, syncs up with appendfile offset before - read and after read and write.''' - - def __init__(self, fp): - self.fp = fp - self.offset = 0 - - def tell(self): - return self.offset - - def seek(self, offset, whence=0): - if whence == 0: - self.offset = offset - elif whence == 1: - self.offset += offset - elif whence == 2: - self.offset = self.fp.end() + offset - - def read(self, count=-1): - try: - if self.offset != self.fp.offset: - self.fp.seek(self.offset) - return self.fp.read(count) - finally: - self.offset = self.fp.offset - - def write(self, s): - try: - return self.fp.write(s) - finally: - self.offset = self.fp.offset - - def close(self): - # revlog wants this. - pass - - def flush(self): - # revlog wants this. - pass - - def writedata(self): - self.fp.writedata() + self.offset = self.realsize + self.tmpfp.tell() class appendopener(object): '''special opener for files that only read or append.''' def __init__(self, opener): self.realopener = opener - # key: file name, value: appendfile object - self.fps = {} + # key: file name, value: appendfile name + self.tmpnames = {} def __call__(self, name, mode='r'): - '''open file. return same cached appendfile object for every - later call.''' + '''open file.''' assert mode in 'ra+' - fp = self.fps.get(name) - if fp is None: - fp = appendfile(self.realopener(name, 'a+')) - self.fps[name] = fp - return sharedfile(fp) + try: + realfp = self.realopener(name, 'r') + except IOError, err: + if err.errno != errno.ENOENT: raise + realfp = self.realopener(name, 'w+') + tmpname = self.tmpnames.get(name) + fp = appendfile(realfp, tmpname) + if tmpname is None: + self.tmpnames[name] = fp.tmpname + return fp def writedata(self): '''copy data from temp files to real files.''' # write .d file before .i file. - fps = self.fps.items() - fps.sort() - for name, fp in fps: - fp.writedata() + tmpnames = self.tmpnames.items() + tmpnames.sort() + for name, tmpname in tmpnames: + fp = open(tmpname, 'rb') + s = fp.read() + fp.close() + fp = self.realopener(name, 'a') + fp.write(s) + fp.close() + + def __del__(self): + for tmpname in self.tmpnames.itervalues(): + os.unlink(tmpname) # files for changelog and manifest are in different appendopeners, so # not mixed up together. diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -928,6 +928,7 @@ class revlog(object): if data[0]: f.write(data[0]) f.write(data[1]) + f.close() f = self.opener(self.indexfile, "a") else: f = self.opener(self.indexfile, "a+") diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -201,7 +201,7 @@ def canonpath(root, cwd, myname): else: rootsep = root + os.sep name = myname - if not name.startswith(os.sep): + if not os.path.isabs(name): name = os.path.join(root, cwd, name) name = os.path.normpath(name) if name.startswith(rootsep): diff --git a/tests/test-hup b/tests/test-hup --- a/tests/test-hup +++ b/tests/test-hup @@ -9,7 +9,7 @@ P=$! Q=$! sleep 1 kill -HUP $P -sleep 1 +wait ls .hg