changeset 2099:cd7cb896396b

Merge with cmason
author Thomas Arendsen Hein <thomas@intevation.de>
date Wed, 19 Apr 2006 21:37:43 +0200
parents fb8b35b0def9 (diff) 190c6a81e6ad (current diff)
children 2b8f887b2d1d
files
diffstat 6 files changed, 73 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/win32/ReadMe.html
+++ b/contrib/win32/ReadMe.html
@@ -2,6 +2,15 @@
 <html>
   <head>
     <title>Mercurial for Windows</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >  
+    <style type="text/css">
+      <!--
+      .indented
+      {
+      padding-left: 10pt;
+      }
+      -->
+    </style>
   </head>
 
   <body>
@@ -12,10 +21,14 @@
     <p>Mercurial is a command-line application.  You must run it from
       the Windows command prompt (or if you're hard core, a <a
       href="http://www.mingw.org/">MinGW</a> shell).</p>
+    
+    <p><div class="indented"><i>Note: the standard <a
+      href="http://www.mingw.org/">MinGW</a> msys startup script uses
+      rxvt which has problems setting up standard input and output.
+      Running bash directly works correctly.</i></div>
 
     <p>For documentation, please visit the <a
-	href="http://www.selenic.com/mercurial">Mercurial web
-	site</a>.</p>
+      href="http://www.selenic.com/mercurial">Mercurial web site</a>.</p>
 
     <p>By default, Mercurial installs to <tt>C:\Mercurial</tt>.  The
       Mercurial command is called <tt>hg.exe</tt>.  To run this
--- 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:
--- 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.
--- 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+")
--- 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):
--- a/tests/test-hup
+++ b/tests/test-hup
@@ -9,7 +9,7 @@ P=$!
 Q=$!
 sleep 1
 kill -HUP $P
-sleep 1
+wait
 ls .hg