# HG changeset patch # User Henrik Stuart # Date 1279129452 -7200 # Node ID 724362365ea0b8dae1f3fdf19d1221d4f80b372e # Parent 52874ddeb166961c3c240a1750f12b97f4a5dd0b# Parent 4484a7b661f2f79f142c06c7ab1d9b58a7c3a608 merge crew and main diff -r 52874ddeb166 -r 724362365ea0 hgext/inotify/linux/_inotify.c --- a/hgext/inotify/linux/_inotify.c Mon Jul 12 17:27:32 2010 -0500 +++ b/hgext/inotify/linux/_inotify.c Wed Jul 14 19:44:12 2010 +0200 @@ -15,6 +15,15 @@ #include #include +#include + +/* Variables used in the event string representation */ +static PyObject *join; +static PyObject *er_wm; +static PyObject *er_wmc; +static PyObject *er_wmn; +static PyObject *er_wmcn; + static PyObject *init(PyObject *self, PyObject *args) { PyObject *ret = NULL; @@ -312,8 +321,8 @@ }; PyDoc_STRVAR( - event_doc, - "event: Structure describing an inotify event."); + event_doc, + "event: Structure describing an inotify event."); static PyObject *event_new(PyTypeObject *t, PyObject *a, PyObject *k) { @@ -327,20 +336,15 @@ Py_XDECREF(evt->cookie); Py_XDECREF(evt->name); - (*evt->ob_type->tp_free)(evt); + Py_TYPE(evt)->tp_free(evt); } static PyObject *event_repr(struct event *evt) { - int wd = PyInt_AsLong(evt->wd); int cookie = evt->cookie == Py_None ? -1 : PyInt_AsLong(evt->cookie); PyObject *ret = NULL, *pymasks = NULL, *pymask = NULL; - PyObject *join = NULL; char *maskstr; - - join = PyString_FromString("|"); - if (join == NULL) - goto bail; + PyObject *tuple = NULL, *formatstr = NULL; pymasks = decode_mask(PyInt_AsLong(evt->mask)); if (pymasks == NULL) @@ -350,33 +354,35 @@ if (pymask == NULL) goto bail; - maskstr = PyString_AsString(pymask); - if (evt->name != Py_None) { - PyObject *pyname = PyString_Repr(evt->name, 1); - char *name = pyname ? PyString_AsString(pyname) : "???"; - - if (cookie == -1) - ret = PyString_FromFormat( - "event(wd=%d, mask=%s, name=%s)", - wd, maskstr, name); - else - ret = PyString_FromFormat("event(wd=%d, mask=%s, " - "cookie=0x%x, name=%s)", - wd, maskstr, cookie, name); - - Py_XDECREF(pyname); + if (cookie == -1) { + formatstr = er_wmn; + tuple = PyTuple_Pack(3, evt->wd, pymask, evt->name); + } + else { + formatstr = er_wmcn; + tuple = PyTuple_Pack(4, evt->wd, pymask, + evt->cookie, evt->name); + } } else { - if (cookie == -1) - ret = PyString_FromFormat("event(wd=%d, mask=%s)", - wd, maskstr); + if (cookie == -1) { + formatstr = er_wm; + tuple = PyTuple_Pack(2, evt->wd, pymask); + } else { - ret = PyString_FromFormat( - "event(wd=%d, mask=%s, cookie=0x%x)", - wd, maskstr, cookie); + formatstr = er_wmc; + tuple = PyTuple_Pack(3, evt->wd, pymask, evt->cookie); } } + if (tuple == NULL) + goto bail; + + ret = PyNumber_Remainder(formatstr, tuple); + + if (ret == NULL) + goto bail; + goto done; bail: Py_CLEAR(ret); @@ -384,14 +390,13 @@ done: Py_XDECREF(pymask); Py_XDECREF(pymasks); - Py_XDECREF(join); + Py_XDECREF(tuple); return ret; } static PyTypeObject event_type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL, 0) "_inotify.event", /*tp_name*/ sizeof(struct event), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -561,6 +566,17 @@ return ret; } +static int init_globals(void) +{ + join = PyString_FromString("|"); + er_wm = PyString_FromString("event(wd=%d, mask=%s)"); + er_wmn = PyString_FromString("event(wd=%d, mask=%s, name=%s)"); + er_wmc = PyString_FromString("event(wd=%d, mask=%s, cookie=0x%x)"); + er_wmcn = PyString_FromString("event(wd=%d, mask=%s, cookie=0x%x, name=%s)"); + + return join && er_wm && er_wmn && er_wmc && er_wmcn; +} + PyDoc_STRVAR( read_doc, "read(fd, bufsize[=65536]) -> list_of_events\n" @@ -585,6 +601,35 @@ {NULL}, }; +#ifdef IS_PY3K +static struct PyModuleDef _inotify_module = { + PyModuleDef_HEAD_INIT, + "_inotify", + doc, + -1, + methods +}; + +PyMODINIT_FUNC PyInit__inotify(void) +{ + PyObject *mod, *dict; + + mod = PyModule_Create(&_inotify_module); + + if (mod == NULL) + return NULL; + + if (!init_globals()) + return; + + dict = PyModule_GetDict(mod); + + if (dict) + define_consts(dict); + + return mod; +} +#else void init_inotify(void) { PyObject *mod, *dict; @@ -592,6 +637,9 @@ if (PyType_Ready(&event_type) == -1) return; + if (!init_globals()) + return; + mod = Py_InitModule3("_inotify", methods, doc); dict = PyModule_GetDict(mod); @@ -599,3 +647,4 @@ if (dict) define_consts(dict); } +#endif diff -r 52874ddeb166 -r 724362365ea0 hgext/inotify/server.py --- a/hgext/inotify/server.py Mon Jul 12 17:27:32 2010 -0500 +++ b/hgext/inotify/server.py Wed Jul 14 19:44:12 2010 +0200 @@ -213,7 +213,9 @@ 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 -r 52874ddeb166 -r 724362365ea0 hgext/mq.py --- a/hgext/mq.py Mon Jul 12 17:27:32 2010 -0500 +++ b/hgext/mq.py Wed Jul 14 19:44:12 2010 +0200 @@ -476,6 +476,11 @@ 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 @@ 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 @@ 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 -r 52874ddeb166 -r 724362365ea0 hgext/rebase.py --- a/hgext/rebase.py Mon Jul 12 17:27:32 2010 -0500 +++ b/hgext/rebase.py Wed Jul 14 19:44:12 2010 +0200 @@ -271,9 +271,9 @@ 'Commit the changes and store useful information in extra' try: repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) + ctx = repo[rev] if commitmsg is None: - commitmsg = repo[rev].description() - ctx = repo[rev] + commitmsg = ctx.description() extra = {'rebase_source': ctx.hex()} if extrafn: extrafn(ctx, extra) @@ -347,23 +347,25 @@ 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 -r 52874ddeb166 -r 724362365ea0 mercurial/commands.py --- a/mercurial/commands.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/commands.py Wed Jul 14 19:44:12 2010 +0200 @@ -83,7 +83,7 @@ Returns 0 if all files are successfully added. """ try: - sim = float(opts.get('similarity') or 0) + sim = float(opts.get('similarity') or 100) except ValueError: raise util.Abort(_('similarity must be a number')) if sim < 0 or sim > 100: diff -r 52874ddeb166 -r 724362365ea0 mercurial/context.py --- a/mercurial/context.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/context.py Wed Jul 14 19:44:12 2010 +0200 @@ -353,6 +353,10 @@ 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 @@ 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 -r 52874ddeb166 -r 724362365ea0 mercurial/filelog.py --- a/mercurial/filelog.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/filelog.py Wed Jul 14 19:44:12 2010 +0200 @@ -53,14 +53,27 @@ 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 + + returns True if text is different than what is stored. + """ - # for renames, we have to go the slow way - if text.startswith('\1\n') or self.renamed(node): + 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 -r 52874ddeb166 -r 724362365ea0 mercurial/hg.py --- a/mercurial/hg.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/hg.py Wed Jul 14 19:44:12 2010 +0200 @@ -221,7 +221,7 @@ 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 -r 52874ddeb166 -r 724362365ea0 mercurial/mail.py --- a/mercurial/mail.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/mail.py Wed Jul 14 19:44:12 2010 +0200 @@ -10,6 +10,26 @@ 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 -r 52874ddeb166 -r 724362365ea0 mercurial/revlog.py --- a/mercurial/revlog.py Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/revlog.py Wed Jul 14 19:44:12 2010 +0200 @@ -943,7 +943,10 @@ 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 -r 52874ddeb166 -r 724362365ea0 mercurial/util.h --- a/mercurial/util.h Mon Jul 12 17:27:32 2010 -0500 +++ b/mercurial/util.h Wed Jul 14 19:44:12 2010 +0200 @@ -12,6 +12,48 @@ #define IS_PY3K #define PyInt_FromLong PyLong_FromLong +#define PyInt_AsLong PyLong_AsLong + +/* + Mapping of some of the python < 2.x PyString* functions to py3k's PyUnicode. + + The commented names below represent those that are present in the PyBytes + definitions for python < 2.6 (below in this file) that don't have a direct + implementation. +*/ + +#define PyStringObject PyUnicodeObject +#define PyString_Type PyUnicode_Type + +#define PyString_Check PyUnicode_Check +#define PyString_CheckExact PyUnicode_CheckExact +#define PyString_CHECK_INTERNED PyUnicode_CHECK_INTERNED +#define PyString_AS_STRING PyUnicode_AsLatin1String +#define PyString_GET_SIZE PyUnicode_GET_SIZE + +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyString_FromString PyUnicode_FromString +#define PyString_FromFormatV PyUnicode_FromFormatV +#define PyString_FromFormat PyUnicode_FromFormat +/* #define PyString_Size PyUnicode_GET_SIZE */ +/* #define PyString_AsString */ +/* #define PyString_Repr */ +#define PyString_Concat PyUnicode_Concat +#define PyString_ConcatAndDel PyUnicode_AppendAndDel +#define _PyString_Resize PyUnicode_Resize +/* #define _PyString_Eq */ +#define PyString_Format PyUnicode_Format +/* #define _PyString_FormatLong */ +/* #define PyString_DecodeEscape */ +#define _PyString_Join PyUnicode_Join +#define PyString_Decode PyUnicode_Decode +#define PyString_Encode PyUnicode_Encode +#define PyString_AsEncodedObject PyUnicode_AsEncodedObject +#define PyString_AsEncodedString PyUnicode_AsEncodedString +#define PyString_AsDecodedObject PyUnicode_AsDecodedObject +#define PyString_AsDecodedString PyUnicode_AsDecodedUnicode +/* #define PyString_AsStringAndSize */ +#define _PyString_InsertThousandsGrouping _PyUnicode_InsertThousandsGrouping #endif /* PY_MAJOR_VERSION */ diff -r 52874ddeb166 -r 724362365ea0 setup.py --- a/setup.py Mon Jul 12 17:27:32 2010 -0500 +++ b/setup.py Wed Jul 14 19:44:12 2010 +0200 @@ -9,6 +9,17 @@ if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'): raise SystemExit("Mercurial requires Python 2.4 or later.") +if sys.version_info[0] >= 3: + def b(s): + '''A helper function to emulate 2.6+ bytes literals using string + literals.''' + return s.encode('latin1') +else: + def b(s): + '''A helper function to emulate 2.6+ bytes literals using string + literals.''' + return s + # Solaris Python packaging brain damage try: import hashlib @@ -114,8 +125,8 @@ # fine, we don't want to load it anyway. Python may warn about # a missing __init__.py in mercurial/locale, we also ignore that. err = [e for e in err.splitlines() - if not e.startswith('Not trusting file') \ - and not e.startswith('warning: Not importing')] + if not e.startswith(b('Not trusting file')) \ + and not e.startswith(b('warning: Not importing'))] if err: return '' return out @@ -275,7 +286,8 @@ cc = new_compiler() if hasfunction(cc, 'inotify_add_watch'): inotify = Extension('hgext.inotify.linux._inotify', - ['hgext/inotify/linux/_inotify.c']) + ['hgext/inotify/linux/_inotify.c'], + ['mercurial']) inotify.optional = True extmodules.append(inotify) packages.extend(['hgext.inotify', 'hgext.inotify.linux']) diff -r 52874ddeb166 -r 724362365ea0 tests/test-bheads --- a/tests/test-bheads Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-bheads Wed Jul 14 19:44:12 2010 +0200 @@ -137,21 +137,21 @@ 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 -r 52874ddeb166 -r 724362365ea0 tests/test-bheads.out --- a/tests/test-bheads.out Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-bheads.out Wed Jul 14 19:44:12 2010 +0200 @@ -187,15 +187,15 @@ 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 -r 52874ddeb166 -r 724362365ea0 tests/test-clone --- a/tests/test-clone Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-clone Wed Jul 14 19:44:12 2010 +0200 @@ -199,4 +199,14 @@ 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 -r 52874ddeb166 -r 724362365ea0 tests/test-clone.out --- a/tests/test-clone.out Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-clone.out Wed Jul 14 19:44:12 2010 +0200 @@ -312,3 +312,5 @@ % 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 -r 52874ddeb166 -r 724362365ea0 tests/test-diff-upgrade --- a/tests/test-diff-upgrade Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-diff-upgrade Wed Jul 14 19:44:12 2010 +0200 @@ -35,7 +35,7 @@ python -c "file('binary', 'wb').write('\0\0')" python -c "file('newbinary', 'wb').write('\0')" rm rmbinary -hg addremove +hg addremove -s 0 echo '% git=no: regular diff for all files' hg autodiff --git=no diff -r 52874ddeb166 -r 724362365ea0 tests/test-filelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-filelog Wed Jul 14 19:44:12 2010 +0200 @@ -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 -r 52874ddeb166 -r 724362365ea0 tests/test-filelog.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-filelog.out Wed Jul 14 19:44:12 2010 +0200 @@ -0,0 +1,2 @@ +ERROR: FIXME: This is a known failure of filelog.size for data starting with \1\n +OK. diff -r 52874ddeb166 -r 724362365ea0 tests/test-inotify --- a/tests/test-inotify Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-inotify Wed Jul 14 19:44:12 2010 +0200 @@ -97,4 +97,17 @@ 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 -r 52874ddeb166 -r 724362365ea0 tests/test-issue660 --- a/tests/test-issue660 Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-issue660 Wed Jul 14 19:44:12 2010 +0200 @@ -56,7 +56,7 @@ echo a > a/a echo b > b -hg addremove +hg addremove -s 0 hg st echo % commit diff -r 52874ddeb166 -r 724362365ea0 tests/test-patchbomb.out --- a/tests/test-patchbomb.out Mon Jul 12 17:27:32 2010 -0500 +++ b/tests/test-patchbomb.out Wed Jul 14 19:44:12 2010 +0200 @@ -573,7 +573,7 @@ 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: