diff --git a/hgext/inotify/server.py b/hgext/inotify/server.py index 8c545dfbb8..6ca0941c6c 100644 --- a/hgext/inotify/server.py +++ b/hgext/inotify/server.py @@ -213,7 +213,9 @@ class repowatcher(object): if time != int(st_mtime): return 'l' return 'n' - if type_ == '?' and self.dirstate._ignore(fn): + if type_ == '?' and self.dirstate._dirignore(fn): + # we must check not only if the file is ignored, but if any part + # of its path match an ignore pattern return 'i' return type_ diff --git a/hgext/mq.py b/hgext/mq.py index 94ef93048a..9d7d6d350a 100644 --- a/hgext/mq.py +++ b/hgext/mq.py @@ -476,6 +476,11 @@ class queue(object): write_list(self.full_series, self.series_path) if self.guards_dirty: write_list(self.active_guards, self.guards_path) + if self.added: + qrepo = self.qrepo() + if qrepo: + qrepo[None].add(self.added) + self.added = [] def removeundo(self, repo): undo = repo.sjoin('undo') @@ -1623,7 +1628,6 @@ class queue(object): if (len(files) > 1 or len(rev) > 1) and patchname: raise util.Abort(_('option "-n" not valid when importing multiple ' 'patches')) - self.added = [] if rev: # If mq patches are applied, we can only import revisions # that form a linear path to qbase. @@ -1810,9 +1814,6 @@ def qimport(ui, repo, *filename, **opts): git=opts['git']) finally: q.save_dirty() - qrepo = q.qrepo() - if qrepo: - qrepo[None].add(q.added) if opts.get('push') and not opts.get('rev'): return q.push(repo, None) diff --git a/hgext/rebase.py b/hgext/rebase.py index 9b27a7c2b6..45e6e9c209 100644 --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -271,9 +271,9 @@ def concludenode(repo, rev, p1, p2, commitmsg=None, extrafn=None): 'Commit the changes and store useful information in extra' try: repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) - if commitmsg is None: - commitmsg = repo[rev].description() ctx = repo[rev] + if commitmsg is None: + commitmsg = ctx.description() extra = {'rebase_source': ctx.hex()} if extrafn: extrafn(ctx, extra) @@ -347,23 +347,25 @@ def isagitpatch(repo, patchname): def updatemq(repo, state, skipped, **opts): 'Update rebased mq patches - finalize and then import them' mqrebase = {} - for p in repo.mq.applied: - if repo[p.node].rev() in state: + mq = repo.mq + for p in mq.applied: + rev = repo[p.node].rev() + if rev in state: repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' % - (repo[p.node].rev(), p.name)) - mqrebase[repo[p.node].rev()] = (p.name, isagitpatch(repo, p.name)) + (rev, p.name)) + mqrebase[rev] = (p.name, isagitpatch(repo, p.name)) if mqrebase: - repo.mq.finish(repo, mqrebase.keys()) + mq.finish(repo, mqrebase.keys()) # We must start import from the newest revision for rev in sorted(mqrebase, reverse=True): if rev not in skipped: - repo.ui.debug('import mq patch %d (%s)\n' - % (state[rev], mqrebase[rev][0])) - repo.mq.qimport(repo, (), patchname=mqrebase[rev][0], - git=mqrebase[rev][1],rev=[str(state[rev])]) - repo.mq.save_dirty() + name, isgit = mqrebase[rev] + repo.ui.debug('import mq patch %d (%s)\n' % (state[rev], name)) + mq.qimport(repo, (), patchname=name, git=isgit, + rev=[str(state[rev])]) + mq.save_dirty() def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches, external): diff --git a/mercurial/context.py b/mercurial/context.py index 12ecbd9136..004037f6a0 100644 --- a/mercurial/context.py +++ b/mercurial/context.py @@ -353,6 +353,10 @@ class filectx(object): return self._filelog.size(self._filerev) def cmp(self, text): + """compare text with stored file revision + + returns True if text is different than what is stored. + """ return self._filelog.cmp(self._filenode, text) def renamed(self): @@ -932,7 +936,11 @@ class workingfilectx(filectx): return (t, tz) def cmp(self, text): - return self._repo.wread(self._path) == text + """compare text with disk content + + returns True if text is different than what is on disk. + """ + return self._repo.wread(self._path) != text class memctx(object): """Use memctx to perform in-memory commits via localrepo.commitctx(). diff --git a/mercurial/filelog.py b/mercurial/filelog.py index 0e730d81b4..1ae2b17201 100644 --- a/mercurial/filelog.py +++ b/mercurial/filelog.py @@ -53,14 +53,27 @@ class filelog(revlog.revlog): if self.renamed(node): return len(self.read(node)) + # XXX if self.read(node).startswith("\1\n"), this returns (size+4) return revlog.revlog.size(self, rev) def cmp(self, node, text): - """compare text with a given file revision""" + """compare text with a given file revision - # for renames, we have to go the slow way - if text.startswith('\1\n') or self.renamed(node): + returns True if text is different than what is stored. + """ + + t = text + if text.startswith('\1\n'): + t = '\1\n\1\n' + text + + samehashes = not revlog.revlog.cmp(self, node, t) + if samehashes: + return False + + # renaming a file produces a different hash, even if the data + # remains unchanged. Check if it's the case (slow): + if self.renamed(node): t2 = self.read(node) return t2 != text - return revlog.revlog.cmp(self, node, text) + return True diff --git a/mercurial/hg.py b/mercurial/hg.py index 59cefa37d8..ca1b96bfec 100644 --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -221,7 +221,7 @@ def clone(ui, source, dest=None, pull=False, rev=None, update=True, src_repo = repository(ui, source) else: src_repo = source - branch = None + branch = (None, []) origsource = source = src_repo.url() rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev) diff --git a/mercurial/mail.py b/mercurial/mail.py index 4548a5c784..ef9fa769fb 100644 --- a/mercurial/mail.py +++ b/mercurial/mail.py @@ -10,6 +10,26 @@ import util, encoding import os, smtplib, socket, quopri import email.Header, email.MIMEText, email.Utils +_oldheaderinit = email.Header.Header.__init__ +def _unifiedheaderinit(self, *args, **kw): + """ + Python2.7 introduces a backwards incompatible change + (Python issue1974, r70772) in email.Generator.Generator code: + pre-2.7 code passed "continuation_ws='\t'" to the Header + constructor, and 2.7 removed this parameter. + + Default argument is continuation_ws=' ', which means that the + behaviour is different in <2.7 and 2.7 + + We consider the 2.7 behaviour to be preferable, but need + to have an unified behaviour for versions 2.4 to 2.7 + """ + # override continuation_ws + kw['continuation_ws'] = ' ' + _oldheaderinit(self, *args, **kw) + +email.Header.Header.__dict__['__init__'] = _unifiedheaderinit + def _smtp(ui): '''build an smtp connection and return a function to send mail''' local_hostname = ui.config('smtp', 'local_hostname') diff --git a/mercurial/revlog.py b/mercurial/revlog.py index 3a1ab43186..8f092e9df1 100644 --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -943,7 +943,10 @@ class revlog(object): raise LookupError(id, self.indexfile, _('no match found')) def cmp(self, node, text): - """compare text with a given file revision""" + """compare text with a given file revision + + returns True if text is different than what is stored. + """ p1, p2 = self.parents(node) return hash(text, p1, p2) != node diff --git a/tests/test-bheads b/tests/test-bheads index 9b63405eb5..6e98fabfc3 100755 --- a/tests/test-bheads +++ b/tests/test-bheads @@ -137,21 +137,21 @@ hg ci -m "b3 (HN)" echo '% case NN: msg' hg up -q null hg branch -f b -echo 1 > B +echo 1 > bb hg ci -Am "b4 (NN): new topo root for branch b" echo '% case HN: no msg' -echo 2 >> B +echo 2 >> bb hg ci -m "b5 (HN)" echo '% case BN: msg' hg branch -f default -echo 1 > A +echo 1 > aa hg ci -Am "a6 (BN): new branch root" echo '% case CN: msg' hg up -q 4 -echo 3 >> BB +echo 3 >> bbb hg ci -Am "b7 (CN): regular new head" echo '% case BB: msg' diff --git a/tests/test-bheads.out b/tests/test-bheads.out index 2690126c1d..54f851176a 100644 --- a/tests/test-bheads.out +++ b/tests/test-bheads.out @@ -187,15 +187,15 @@ marked working directory as branch b adding b % case NN: msg marked working directory as branch b -adding B +adding bb created new head % case HN: no msg % case BN: msg marked working directory as branch default -adding A +adding aa created new head % case CN: msg -adding BB +adding bbb created new head % case BB: msg marked working directory as branch default diff --git a/tests/test-clone b/tests/test-clone index 60fc17aa8c..dc2aedcaab 100755 --- a/tests/test-clone +++ b/tests/test-clone @@ -199,4 +199,14 @@ hg -R a parents --template "{node|short}\n" hg -R ua parents --template "{node|short}\n" rm -r ua +cat < simpleclone.py +from mercurial import ui, hg +myui = ui.ui() +repo = hg.repository(myui, 'a') +hg.clone(myui, repo, dest="ua") +EOF + +python simpleclone.py +rm -r ua + exit 0 diff --git a/tests/test-clone.out b/tests/test-clone.out index 97908ae675..b2e67921d8 100644 --- a/tests/test-clone.out +++ b/tests/test-clone.out @@ -312,3 +312,5 @@ summary: hacked default % same revision checked out in repo a and ua e8ece76546a6 e8ece76546a6 +updating to branch default +3 files updated, 0 files merged, 0 files removed, 0 files unresolved diff --git a/tests/test-filelog b/tests/test-filelog new file mode 100644 index 0000000000..923fe290e2 --- /dev/null +++ b/tests/test-filelog @@ -0,0 +1,50 @@ +#!/usr/bin/env python +""" +Tests the behaviour of filelog w.r.t. data starting with '\1\n' +""" +from mercurial import ui, hg +from mercurial.node import nullid, hex + +myui = ui.ui() +repo = hg.repository(myui, path='.', create=True) + +fl = repo.file('foobar') + +def addrev(text, renamed=False): + if renamed: + # data doesnt matter. Just make sure filelog.renamed() returns True + meta = dict(copyrev=hex(nullid), copy='bar') + else: + meta = {} + + t = repo.transaction('commit') + try: + node = fl.add(text, meta, t, 0, nullid, nullid) + return node + finally: + t.close() + +def error(text): + print 'ERROR: ' + text + +textwith = '\1\nfoo' +without = 'foo' + +node = addrev(textwith) +if not textwith == fl.read(node): + error('filelog.read for data starting with \\1\\n') +if fl.cmp(node, textwith) or not fl.cmp(node, without): + error('filelog.cmp for data starting with \\1\\n') +if fl.size(0) != len(textwith): + error('FIXME: This is a known failure of filelog.size for data starting ' + 'with \\1\\n') + +node = addrev(textwith, renamed=True) +if not textwith == fl.read(node): + error('filelog.read for a renaming + data starting with \\1\\n') +if fl.cmp(node, textwith) or not fl.cmp(node, without): + error('filelog.cmp for a renaming + data starting with \\1\\n') +if fl.size(1) != len(textwith): + error('filelog.size for a renaming + data starting with \\1\\n') + +print 'OK.' diff --git a/tests/test-filelog.out b/tests/test-filelog.out new file mode 100644 index 0000000000..d9ecd51616 --- /dev/null +++ b/tests/test-filelog.out @@ -0,0 +1,2 @@ +ERROR: FIXME: This is a known failure of filelog.size for data starting with \1\n +OK. diff --git a/tests/test-inotify b/tests/test-inotify index a083d7d766..c5e0124c56 100755 --- a/tests/test-inotify +++ b/tests/test-inotify @@ -97,4 +97,17 @@ hg ci -m 'working' echo b >> 1844/foo hg ci 1844 -m 'broken' +# Test for issue884: "Build products not ignored until .hgignore is touched" +echo '^build$' > .hgignore +hg add .hgignore +hg ci .hgignore -m 'ignorelist' + +# Now, lets add some build products... +mkdir build +touch build/x +touch build/y + +# build/x & build/y shouldn't appear in "hg st" +hg st + kill `cat hg.pid` diff --git a/tests/test-patchbomb.out b/tests/test-patchbomb.out index d574df47da..f2ab6bd03c 100644 --- a/tests/test-patchbomb.out +++ b/tests/test-patchbomb.out @@ -573,7 +573,7 @@ Displaying [PATCH 3 of 3] charset=utf-8; content-transfer-encoding: quoted-print Content-Type: multipart/mixed; boundary="=== MIME-Version: 1.0 Subject: [PATCH 3 of 3] charset=utf-8; - content-transfer-encoding: quoted-printable + content-transfer-encoding: quoted-printable X-Mercurial-Node: c655633f8c87700bb38cc6a59a2753bdc5a6c376 Message-Id: p hg qref -m 'P1' +hg qcommit -m 'save patch state' +echo '% patch series step 1/2' +hg qseries -s +echo '% patch queue manifest step 1/2' +hg -R .hg/patches manifest echo '% Git patch' cat .hg/patches/f_git.patch | filterpatch @@ -112,6 +117,11 @@ cat .hg/patches/f.patch | filterpatch echo echo '% Rebase the applied mq patches' hg rebase -s 2 -d 1 --quiet +hg qcommit -m 'save patch state' +echo '% patch series step 2/2' +hg qseries -s +echo '% patch queue manifest step 2/2' +hg -R .hg/patches manifest echo '% And the patches are correct' echo '% Git patch' diff --git a/tests/test-rebase-mq.out b/tests/test-rebase-mq.out index 87083c4dc4..b20f81fea8 100644 --- a/tests/test-rebase-mq.out +++ b/tests/test-rebase-mq.out @@ -80,6 +80,14 @@ popping f2.patch popping f.patch patch queue now empty 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% patch series step 1/2 +f_git.patch: P0 (git) +f.patch: P1 +% patch queue manifest step 1/2 +.hgignore +f.patch +f_git.patch +series % Git patch P0 (git) @@ -101,6 +109,14 @@ diff -r x p +mq2 % Rebase the applied mq patches +% patch series step 2/2 +f_git.patch: P0 (git) +f.patch: P1 +% patch queue manifest step 2/2 +.hgignore +f.patch +f_git.patch +series % And the patches are correct % Git patch # HG changeset patch