Merge with cmason
authorMatt Mackall <mpm@selenic.com>
Thu, 20 Apr 2006 12:12:03 -0500
changeset 2105 21cf3fe64e27
parent 2100 2b8f887b2d1d (diff)
parent 2101 c6c019fd5db1 (current diff)
child 2106 b03de24ee2ec
Merge with cmason
--- a/contrib/convert-repo
+++ b/contrib/convert-repo
@@ -73,7 +73,7 @@ class convert_git:
             if n == "parent": parents.append(v)
 
         tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
-        tz = int(tzs) * (int(tzh) * 3600 + int(tzm))
+        tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
         date = tm + " " + str(tz)
         return (parents, author, date, message)
 
--- 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:
@@ -1105,7 +1108,8 @@ def refresh(ui, repo, **opts):
 
 def diff(ui, repo, *files, **opts):
     """diff of the current patch"""
-    repomap[repo].diff(repo, files)
+    # deep in the dirstate code, the walkhelper method wants a list, not a tuple
+    repomap[repo].diff(repo, list(files))
     return 0
 
 def lastsavename(path):
--- 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/commands.py
+++ b/mercurial/commands.py
@@ -3249,11 +3249,9 @@ def parse(ui, args):
     return (cmd, cmd and i[0] or None, args, options, cmdoptions)
 
 def dispatch(args):
-    signal.signal(signal.SIGTERM, catchterm)
-    try:
-        signal.signal(signal.SIGHUP, catchterm)
-    except AttributeError:
-        pass
+    for name in 'SIGTERM', 'SIGHUP', 'SIGBREAK':
+        num = getattr(signal, name, None)
+        if num: signal.signal(num, catchterm)
 
     try:
         u = ui.ui()
--- a/mercurial/hgweb.py
+++ b/mercurial/hgweb.py
@@ -419,7 +419,8 @@ class hgweb(object):
         mt = mimetypes.guess_type(f)[0]
         rawtext = text
         if util.binary(text):
-            text = "(binary:%s)" % mt
+            text = "(binary:%s)" % (mt or 'data')
+        mt = mt or 'text/plain'
 
         def lines():
             for l, t in enumerate(text.splitlines(1)):
--- 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
@@ -20,8 +20,12 @@ def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
     (pout, pin) = popen2.popen2(cmd, -1, 'b')
     def writer():
-        pin.write(s)
-        pin.close()
+        try:
+            pin.write(s)
+            pin.close()
+        except IOError, inst:
+            if inst.errno != errno.EPIPE:
+                raise
 
     # we should use select instead on UNIX, but this will work on most
     # systems, including Windows
@@ -201,7 +205,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):
deleted file mode 100644
--- a/templates/filerevision-raw.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-Context-type: #mimetype#
-Content-disposition: filename=#file#
-
-#raw#
--- a/templates/map-raw
+++ b/templates/map-raw
@@ -8,7 +8,7 @@ diffline = '#line#'
 changesetparent = '# parent: #node#'
 changesetchild = '# child: #node#'
 filenodelink = ''
-filerevision = filerevision-raw.tmpl
+filerevision = 'Content-Type: #mimetype#\nContent-Disposition: filename=#file#\n\n#raw#'
 fileline = '#line#'
 diffblock = '#lines#'
 filediff = filediff-raw.tmpl
--- a/tests/test-hup
+++ b/tests/test-hup
@@ -9,7 +9,7 @@ P=$!
 Q=$!
 sleep 1
 kill -HUP $P
-sleep 1
+wait
 ls .hg