hgweb: handle IOErrors and OSErrors during unbundle
authorAlexis S. L. Carvalho <alexis@cecm.usp.br>
Fri, 16 Mar 2007 00:22:55 -0300
changeset 4228 c52b7176af94
parent 4227 f5b9edf3390b
child 4229 24c22a3f2ef8
hgweb: handle IOErrors and OSErrors during unbundle This allows the client to display a reasonable message to the user (e.g. "Permission denied: .hg/lock"), instead of the current "<url> does not appear to be an hg repository".
mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py	Sun Oct 22 13:54:43 2006 -0300
+++ b/mercurial/hgweb/hgweb_mod.py	Fri Mar 16 00:22:55 2007 -0300
@@ -1099,67 +1099,78 @@
             for s in util.filechunkiter(req, limit=length):
                 fp.write(s)
 
-            lock = self.repo.lock()
             try:
-                if not check_heads():
-                    req.write('0\n')
-                    req.write(_('unsynced changes\n'))
-                    return
+                lock = self.repo.lock()
+                try:
+                    if not check_heads():
+                        req.write('0\n')
+                        req.write(_('unsynced changes\n'))
+                        return
 
-                fp.seek(0)
-                header = fp.read(6)
-                if not header.startswith("HG"):
-                    # old client with uncompressed bundle
-                    def generator(f):
-                        yield header
-                        for chunk in f:
-                            yield chunk
-                elif not header.startswith("HG10"):
-                    req.write("0\n")
-                    req.write(_("unknown bundle version\n"))
-                    return
-                elif header == "HG10GZ":
-                    def generator(f):
-                        zd = zlib.decompressobj()
-                        for chunk in f:
-                            yield zd.decompress(chunk)
-                elif header == "HG10BZ":
-                    def generator(f):
-                        zd = bz2.BZ2Decompressor()
-                        zd.decompress("BZ")
-                        for chunk in f:
-                            yield zd.decompress(chunk)
-                elif header == "HG10UN":
-                    def generator(f):
-                        for chunk in f:
-                            yield chunk
+                    fp.seek(0)
+                    header = fp.read(6)
+                    if not header.startswith("HG"):
+                        # old client with uncompressed bundle
+                        def generator(f):
+                            yield header
+                            for chunk in f:
+                                yield chunk
+                    elif not header.startswith("HG10"):
+                        req.write("0\n")
+                        req.write(_("unknown bundle version\n"))
+                        return
+                    elif header == "HG10GZ":
+                        def generator(f):
+                            zd = zlib.decompressobj()
+                            for chunk in f:
+                                yield zd.decompress(chunk)
+                    elif header == "HG10BZ":
+                        def generator(f):
+                            zd = bz2.BZ2Decompressor()
+                            zd.decompress("BZ")
+                            for chunk in f:
+                                yield zd.decompress(chunk)
+                    elif header == "HG10UN":
+                        def generator(f):
+                            for chunk in f:
+                                yield chunk
+                    else:
+                        req.write("0\n")
+                        req.write(_("unknown bundle compression type\n"))
+                        return
+                    gen = generator(util.filechunkiter(fp, 4096))
+
+                    # send addchangegroup output to client
+
+                    old_stdout = sys.stdout
+                    sys.stdout = cStringIO.StringIO()
+
+                    try:
+                        url = 'remote:%s:%s' % (proto,
+                                                req.env.get('REMOTE_HOST', ''))
+                        try:
+                            ret = self.repo.addchangegroup(
+                                        util.chunkbuffer(gen), 'serve', url)
+                        except util.Abort, inst:
+                            sys.stdout.write("abort: %s\n" % inst)
+                            ret = 0
+                    finally:
+                        val = sys.stdout.getvalue()
+                        sys.stdout = old_stdout
+                    req.write('%d\n' % ret)
+                    req.write(val)
+                finally:
+                    lock.release()
+            except (OSError, IOError), inst:
+                req.write('0\n')
+                filename = getattr(inst, 'filename', '')
+                # Don't send our filesystem layout to the client
+                if filename.startswith(self.repo.root):
+                    filename = filename[len(self.repo.root)+1:]
                 else:
-                    req.write("0\n")
-                    req.write(_("unknown bundle compression type\n"))
-                    return
-                gen = generator(util.filechunkiter(fp, 4096))
-
-                # send addchangegroup output to client
-
-                old_stdout = sys.stdout
-                sys.stdout = cStringIO.StringIO()
-
-                try:
-                    url = 'remote:%s:%s' % (proto,
-                                            req.env.get('REMOTE_HOST', ''))
-                    try:
-                        ret = self.repo.addchangegroup(util.chunkbuffer(gen),
-                                                       'serve', url)
-                    except util.Abort, inst:
-                        sys.stdout.write("abort: %s\n" % inst)
-                        ret = 0
-                finally:
-                    val = sys.stdout.getvalue()
-                    sys.stdout = old_stdout
-                req.write('%d\n' % ret)
-                req.write(val)
-            finally:
-                lock.release()
+                    filename = ''
+                error = getattr(inst, 'strerror', 'Unknown error')
+                req.write('%s: %s\n' % (error, filename))
         finally:
             fp.close()
             os.unlink(tempname)