changeset 4232:0d51eb296fb9

Merge with crew-stable
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Fri, 16 Mar 2007 00:45:18 -0300
parents 2a8b6d78d7ee (current diff) 83153299aab5 (diff)
children da6b14877195
files mercurial/cmdutil.py mercurial/commands.py mercurial/dirstate.py mercurial/hgweb/hgweb_mod.py mercurial/httprepo.py mercurial/localrepo.py mercurial/merge.py mercurial/patch.py mercurial/util.py tests/test-mq.out tests/test-newbranch tests/test-newbranch.out tests/test-walk tests/test-walk.out
diffstat 18 files changed, 173 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -138,7 +138,7 @@ def walk(repo, pats=[], opts={}, node=No
     exact = dict.fromkeys(files)
     for src, fn in repo.walk(node=node, files=files, match=matchfn,
                              badmatch=badmatch):
-        yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
+        yield src, fn, util.pathto(repo.root, repo.getcwd(), fn), fn in exact
 
 def findrenames(repo, added=None, removed=None, threshold=0.5):
     '''find renamed files -- yields (before, after, score) tuples'''
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -493,7 +493,7 @@ def docopy(ui, repo, pats, opts, wlock):
     # target: ossep
     def copy(origsrc, abssrc, relsrc, target, exact):
         abstarget = util.canonpath(repo.root, cwd, target)
-        reltarget = util.pathto(cwd, abstarget)
+        reltarget = util.pathto(repo.root, cwd, abstarget)
         prevsrc = targets.get(abstarget)
         if prevsrc is not None:
             ui.warn(_('%s: not overwriting - %s collides with %s\n') %
@@ -2172,9 +2172,19 @@ def revert(ui, repo, *pats, **opts):
 
     # walk target manifest.
 
+    def badmatch(path):
+        if path in names:
+            return True
+        path_ = path + '/'
+        for f in names:
+            if f.startswith(path_):
+                return True
+        return False
+
     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
-                                             badmatch=names.has_key):
-        if abs in names: continue
+                                             badmatch=badmatch):
+        if abs in names or src == 'b':
+            continue
         names[abs] = (rel, exact)
         target_only[abs] = True
 
@@ -2414,11 +2424,12 @@ def status(ui, repo, *pats, **opts):
             format = "%s %%s%s" % (char, end)
 
         for f in changes:
-            ui.write(format % util.pathto(cwd, f))
+            ui.write(format % util.pathto(repo.root, cwd, f))
             if ((all or opts.get('copies')) and not opts.get('no_status')):
                 copied = repo.dirstate.copied(f)
                 if copied:
-                    ui.write('  %s%s' % (util.pathto(cwd, copied), end))
+                    ui.write('  %s%s' % (util.pathto(repo.root, cwd, copied),
+                                         end))
 
 def tag(ui, repo, name, rev_=None, **opts):
     """add a tag for the current or given revision
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -33,10 +33,14 @@ class dirstate(object):
         cwd = os.getcwd()
         if cwd == self.root: return ''
         # self.root ends with a path separator if self.root is '/' or 'C:\'
-        common_prefix_len = len(self.root)
-        if not self.root.endswith(os.sep):
-            common_prefix_len += 1
-        return cwd[common_prefix_len:]
+        rootsep = self.root
+        if not rootsep.endswith(os.sep):
+            rootsep += os.sep
+        if cwd.startswith(rootsep):
+            return cwd[len(rootsep):]
+        else:
+            # we're outside the repo. return an absolute path.
+            return cwd
 
     def hgignore(self):
         '''return the contents of .hgignore files as a list of patterns.
@@ -361,7 +365,7 @@ class dirstate(object):
             elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
             elif stat.S_ISDIR(st.st_mode): kind = _('directory')
             self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
-                util.pathto(self.getcwd(), f),
+                util.pathto(self.root, self.getcwd(), f),
                 kind))
         return False
 
@@ -471,7 +475,7 @@ class dirstate(object):
                 if not found:
                     if inst.errno != errno.ENOENT or not badmatch:
                         self.ui.warn('%s: %s\n' % (
-                            util.pathto(self.getcwd(), ff),
+                            util.pathto(self.root, self.getcwd(), ff),
                             inst.strerror))
                     elif badmatch and badmatch(ff) and imatch(nf):
                         yield 'b', ff, None
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -1066,8 +1066,6 @@ class hgweb(object):
                  headers={'status': '401 Unauthorized'})
             return
 
-        req.httphdr("application/mercurial-0.1")
-
         their_heads = req.form['heads'][0].split(' ')
 
         def check_heads():
@@ -1079,6 +1077,8 @@ class hgweb(object):
             bail(_('unsynced changes\n'))
             return
 
+        req.httphdr("application/mercurial-0.1")
+
         # do not lock repo until all changegroup data is
         # streamed. save to temporary file.
 
@@ -1089,67 +1089,78 @@ class hgweb(object):
             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)
--- a/mercurial/httprepo.py
+++ b/mercurial/httprepo.py
@@ -75,6 +75,14 @@ def netlocunsplit(host, port, user=None,
         return userpass + '@' + hostport
     return hostport
 
+# work around a bug in Python < 2.4.2
+# (it leaves a "\n" at the end of Proxy-authorization headers)
+class request(urllib2.Request):
+    def add_header(self, key, val):
+        if key.lower() == 'proxy-authorization':
+            val = val.strip()
+        return urllib2.Request.add_header(self, key, val)
+
 class httpsendfile(file):
     def __len__(self):
         return os.fstat(self.fileno()).st_size
@@ -238,7 +246,7 @@ class httprepository(remoterepository):
             if data:
                 self.ui.debug(_("sending %s bytes\n") %
                               headers.get('content-length', 'X'))
-            resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
+            resp = urllib2.urlopen(request(cu, data, headers))
         except urllib2.HTTPError, inst:
             if inst.code == 401:
                 raise util.Abort(_('authorization failed'))
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -902,7 +902,7 @@ class localrepository(repo.repository):
                         yield 'b', fn
                 else:
                     self.ui.warn(_('%s: No such file in rev %s\n') % (
-                        util.pathto(self.getcwd(), fn), short(node)))
+                        util.pathto(self.root, self.getcwd(), fn), short(node)))
         else:
             for src, fn in self.dirstate.walk(files, match, badmatch=badmatch):
                 yield src, fn
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -450,7 +450,10 @@ def update(repo, node, branchmerge, forc
     wc = repo.workingctx()
     if node is None:
         # tip of current branch
-        node = repo.branchtags()[wc.branch()]
+        try:
+            node = repo.branchtags()[wc.branch()]
+        except KeyError:
+            raise util.Abort(_("branch %s not found") % wc.branch())
     overwrite = force and not branchmerge
     forcemerge = force and branchmerge
     pl = wc.parents()
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -359,7 +359,7 @@ def updatedir(ui, repo, patches, wlock=N
     cfiles = patches.keys()
     cwd = repo.getcwd()
     if cwd:
-        cfiles = [util.pathto(cwd, f) for f in patches.keys()]
+        cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
     for f in patches:
         ctype, gp = patches[f]
         if ctype == 'RENAME':
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -325,13 +325,22 @@ def globre(pat, head='^', tail='$'):
 
 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
 
-def pathto(n1, n2):
+def pathto(root, n1, n2):
     '''return the relative path from one place to another.
+    root should use os.sep to separate directories
     n1 should use os.sep to separate directories
     n2 should use "/" to separate directories
     returns an os.sep-separated path.
+
+    If n1 is a relative path, it's assumed it's
+    relative to root.
+    n2 should always be relative to root.
     '''
     if not n1: return localpath(n2)
+    if os.path.isabs(n1):
+        if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
+            return os.path.join(root, localpath(n2))
+        n2 = '/'.join((pconvert(root), n2))
     a, b = n1.split(os.sep), n2.split('/')
     a.reverse()
     b.reverse()
--- a/tests/test-import
+++ b/tests/test-import
@@ -32,6 +32,17 @@ hg --cwd a diff -r0:1 > tip.patch
 hg --cwd b import -mpatch ../tip.patch
 rm -r b
 
+echo % hg -R repo import
+# put the clone in a subdir - having a directory named "a"
+# used to hide a bug.
+mkdir dir
+hg clone -r0 a dir/b
+hg --cwd a export tip > dir/tip.patch
+cd dir
+hg -R b import tip.patch
+cd ..
+rm -r dir
+
 echo % import from stdin
 hg clone -r0 a b
 hg --cwd a export tip | hg --cwd b import -
--- a/tests/test-import.out
+++ b/tests/test-import.out
@@ -30,6 +30,14 @@ adding file changes
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
+% hg -R repo import
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 2 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+applying tip.patch
 % import from stdin
 requesting all changes
 adding changesets
--- a/tests/test-mq.out
+++ b/tests/test-mq.out
@@ -68,8 +68,8 @@ guards
   series:
 abort: repository already exists!
 % qinit; <stuff>; qinit -c
-adding A
-adding B
+adding .hg/patches/A
+adding .hg/patches/B
 A .hgignore
 A A
 A B
--- a/tests/test-newbranch
+++ b/tests/test-newbranch
@@ -48,3 +48,7 @@ hg id
 hg up -q 1
 hg up -q
 hg id
+hg branch foobar
+hg up
+
+exit 0
--- a/tests/test-newbranch.out
+++ b/tests/test-newbranch.out
@@ -83,3 +83,4 @@ 67ec16bde7f1575d523313b9bca000f6a6f12dca
 % update with no arguments: tipmost revision of the current branch
 bf1bc2f45e83
 4909a3732169 (foo) tip
+abort: branch foobar not found
--- a/tests/test-revert
+++ b/tests/test-revert
@@ -88,5 +88,8 @@ hg revert --all -rtip
 echo %% issue332
 hg ci -A -m b -d '1000001 0'
 echo foobar > b/b
-hg revert b
+mkdir newdir
+echo foo > newdir/newfile
+hg add newdir/newfile
+hg revert b newdir
 true
--- a/tests/test-revert.out
+++ b/tests/test-revert.out
@@ -61,3 +61,4 @@ reverting a
 %% issue332
 adding b/b
 reverting b/b
+forgetting newdir/newfile
--- a/tests/test-walk
+++ b/tests/test-walk
@@ -90,3 +90,9 @@ hg rm fenugreek
 debugwalk fenugreek
 touch new
 debugwalk new
+chdir ..
+debugwalk -R t t/mammals/skunk
+mkdir t2
+chdir t2
+debugwalk -R ../t ../t/mammals/skunk
+debugwalk --cwd ../t mammals/skunk
--- a/tests/test-walk.out
+++ b/tests/test-walk.out
@@ -276,3 +276,16 @@ m  fenugreek  fenugreek  exact
 hg debugwalk new
 f  new  new  exact
 
+cd ..
+
+hg debugwalk -R t t/mammals/skunk
+f  mammals/skunk  t/mammals/skunk  exact
+
+cd t2
+
+hg debugwalk -R ../t ../t/mammals/skunk
+f  mammals/skunk  ../t/mammals/skunk  exact
+
+hg debugwalk --cwd ../t mammals/skunk
+f  mammals/skunk  mammals/skunk  exact
+