# HG changeset patch # User Vadim Gelfer # Date 1146605875 25200 # Node ID 6886bc0b77af070fd0f939aa6bcca4e520e413e1 # Parent 3044a3fdae7602654f571859462a4a5407cfb198# Parent 9b42304d9896acd903a536f359174131a09149f5 merge with crew. diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -9,6 +9,7 @@ syntax: glob *.swp *.prof tests/.coverage* +tests/annotated tests/*.err build dist diff --git a/CONTRIBUTORS b/CONTRIBUTORS --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -14,6 +14,7 @@ Volker Kleinfeld Christopher Li Chris Mason +Colin McMillen Wojciech Milkowski Chad Netzer Bryan O'Sullivan diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt --- a/doc/hgrc.5.txt +++ b/doc/hgrc.5.txt @@ -131,11 +131,11 @@ decode/encode:: **.txt = tempfile: unix2dos -n INFILE OUTFILE hooks:: - Commands that get automatically executed by various actions such as - starting or finishing a commit. Multiple commands can be run for - the same action by appending a suffix to the action. Overriding a - site-wide hook can be done by changing its value or setting it to - an empty string. + Commands or Python functions that get automatically executed by + various actions such as starting or finishing a commit. Multiple + hooks can be run for the same action by appending a suffix to the + action. Overriding a site-wide hook can be done by changing its + value or setting it to an empty string. Example .hg/hgrc: @@ -211,6 +211,21 @@ hooks:: the environment for backwards compatibility, but their use is deprecated, and they will be removed in a future release. + The syntax for Python hooks is as follows: + + hookname = python:modulename.submodule.callable + + Python hooks are run within the Mercurial process. Each hook is + called with at least three keyword arguments: a ui object (keyword + "ui"), a repository object (keyword "repo"), and a "hooktype" + keyword that tells what kind of hook is used. Arguments listed as + environment variables above are passed as keyword arguments, with no + "HG_" prefix, and names in lower case. + + A Python hook must return a "true" value to succeed. Returning a + "false" value or raising an exception is treated as failure of the + hook. + http_proxy:: Used to access web-based Mercurial repositories through a HTTP proxy. diff --git a/hgext/gpg.py b/hgext/gpg.py --- a/hgext/gpg.py +++ b/hgext/gpg.py @@ -23,11 +23,11 @@ class gpg: """ returns of the good and bad signatures""" try: # create temporary files - fd, sigfile = tempfile.mkstemp(prefix="hggpgsig") + fd, sigfile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".sig") fp = os.fdopen(fd, 'wb') fp.write(sig) fp.close() - fd, datafile = tempfile.mkstemp(prefix="hggpgdata") + fd, datafile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".txt") fp = os.fdopen(fd, 'wb') fp.write(data) fp.close() diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py --- a/hgext/patchbomb.py +++ b/hgext/patchbomb.py @@ -62,7 +62,7 @@ try: except ImportError: pass def diffstat(patch): - fd, name = tempfile.mkstemp() + fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt") try: p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) try: diff --git a/mercurial/appendfile.py b/mercurial/appendfile.py --- a/mercurial/appendfile.py +++ b/mercurial/appendfile.py @@ -38,7 +38,7 @@ class appendfile(object): self.tmpname = tmpname self.tmpfp = util.posixfile(self.tmpname, 'ab+') else: - fd, self.tmpname = tempfile.mkstemp() + fd, self.tmpname = tempfile.mkstemp(prefix="hg-appendfile-") os.close(fd) self.tmpfp = util.posixfile(self.tmpname, 'ab+') self.realfp = fp diff --git a/mercurial/archival.py b/mercurial/archival.py --- a/mercurial/archival.py +++ b/mercurial/archival.py @@ -80,8 +80,11 @@ class zipit: def __init__(self, dest, prefix, compress=True): self.prefix = tidyprefix(dest, prefix, ('.zip',)) - if not isinstance(dest, str) and not hasattr(dest, 'tell'): - dest = tellable(dest) + if not isinstance(dest, str): + try: + dest.tell() + except (AttributeError, IOError): + dest = tellable(dest) self.z = zipfile.ZipFile(dest, 'w', compress and zipfile.ZIP_DEFLATED or zipfile.ZIP_STORED) diff --git a/mercurial/changelog.py b/mercurial/changelog.py --- a/mercurial/changelog.py +++ b/mercurial/changelog.py @@ -11,7 +11,7 @@ from demandload import demandload demandload(globals(), "os time util") class changelog(revlog): - def __init__(self, opener, defversion=0): + def __init__(self, opener, defversion=REVLOGV0): revlog.__init__(self, opener, "00changelog.i", "00changelog.d", defversion) @@ -41,14 +41,15 @@ class changelog(revlog): if date: # validate explicit (probably user-specified) date and # time zone offset. values must fit in signed 32 bits for - # current 32-bit linux runtimes. + # current 32-bit linux runtimes. timezones go from UTC-12 + # to UTC+14 try: when, offset = map(int, date.split(' ')) except ValueError: raise ValueError(_('invalid date: %r') % date) if abs(when) > 0x7fffffff: raise ValueError(_('date exceeds 32 bits: %d') % when) - if abs(offset) >= 43200: + if offset < -50400 or offset > 43200: raise ValueError(_('impossible time zone offset: %d') % offset) else: date = "%d %d" % util.makedate() diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -19,6 +19,11 @@ class UnknownCommand(Exception): class AmbiguousCommand(Exception): """Exception raised if command shortcut matches more than one command.""" +def bail_if_changed(repo): + modified, added, removed, deleted, unknown = repo.changes() + if modified or added or removed or deleted: + raise util.Abort(_("outstanding uncommitted changes")) + def filterfiles(filters, files): l = [x for x in files if x in filters] @@ -298,7 +303,7 @@ def write_bundle(cg, filename=None, comp raise util.Abort(_("file '%s' already exists"), filename) fh = open(filename, "wb") else: - fd, filename = tempfile.mkstemp(suffix=".hg", prefix="hg-bundle-") + fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg") fh = os.fdopen(fd, "wb") cleanup = filename @@ -926,10 +931,48 @@ def archive(ui, repo, dest, **opts): prefix = make_filename(repo, repo.changelog, opts['prefix'], node) if os.path.realpath(dest) == repo.root: raise util.Abort(_('repository root cannot be destination')) - _, matchfn, _ = matchpats(repo, [], opts) + dummy, matchfn, dummy = matchpats(repo, [], opts) archival.archive(repo, dest, node, opts.get('type') or 'files', not opts['no_decode'], matchfn, prefix) +def backout(ui, repo, rev, **opts): + '''reverse effect of earlier changeset + + Commit the backed out changes as a new changeset. + + If you back out a changeset other than the tip, a new head is + created. The --merge option remembers the parent of the working + directory before starting the backout, then merges the new head + with it afterwards, to save you from doing this by hand. The + result of this merge is not committed, as for a normal merge.''' + + bail_if_changed(repo) + op1, op2 = repo.dirstate.parents() + if op2 != nullid: + raise util.Abort(_('outstanding uncommitted merge')) + node = repo.lookup(rev) + parent, p2 = repo.changelog.parents(node) + if parent == nullid: + raise util.Abort(_('cannot back out a change with no parents')) + if p2 != nullid: + raise util.Abort(_('cannot back out a merge')) + repo.update(node, force=True) + revert_opts = opts.copy() + revert_opts['rev'] = hex(parent) + revert(ui, repo, **revert_opts) + commit_opts = opts.copy() + commit_opts['addremove'] = False + if not commit_opts['message'] and not commit_opts['logfile']: + commit_opts['message'] = _("Backed out changeset %s") % (hex(node)) + commit(ui, repo, **commit_opts) + def nice(node): + return '%d:%s' % (repo.changelog.rev(node), short(node)) + ui.status(_('changeset %s backs out changeset %s\n') % + (nice(repo.changelog.tip()), nice(node))) + if opts['merge'] and op1 != node: + ui.status(_('merging with changeset %s\n') % nice(op1)) + update(ui, repo, hex(op1), **opts) + def bundle(ui, repo, fname, dest="default-push", **opts): """create a changegroup file @@ -1572,10 +1615,15 @@ def export(ui, repo, *changesets, **opts doexport(ui, repo, cset, seqno, total, revwidth, opts) def forget(ui, repo, *pats, **opts): - """don't add the specified files on the next commit - + """don't add the specified files on the next commit (DEPRECATED) + + (DEPRECATED) Undo an 'hg add' scheduled for the next commit. + + This command is now deprecated and will be removed in a future + release. Please use revert instead. """ + ui.warn(_("(the forget command is deprecated; use revert instead)\n")) forget = [] for src, abs, rel, exact in walk(repo, pats, opts): if repo.dirstate.state(abs) == 'a': @@ -1792,9 +1840,7 @@ def import_(ui, repo, patch1, *patches, patches = (patch1,) + patches if not opts['force']: - modified, added, removed, deleted, unknown = repo.changes() - if modified or added or removed or deleted: - raise util.Abort(_("outstanding uncommitted changes")) + bail_if_changed(repo) d = opts["base"] strip = opts["strip"] @@ -2885,7 +2931,7 @@ table = { ('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')), - 'archive': + "archive": (archive, [('', 'no-decode', None, _('do not pass files through decoders')), ('p', 'prefix', '', _('directory prefix for files in archive')), @@ -2894,6 +2940,17 @@ table = { ('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], _('hg archive [OPTION]... DEST')), + "backout": + (backout, + [('', 'merge', None, + _('merge with old dirstate parent after backout')), + ('m', 'message', '', _('use as commit message')), + ('l', 'logfile', '', _('read commit message from ')), + ('d', 'date', '', _('record datecode as commit date')), + ('u', 'user', '', _('record user as committer')), + ('I', 'include', [], _('include names matching the given patterns')), + ('X', 'exclude', [], _('exclude names matching the given patterns'))], + _('hg backout [OPTION]... REV')), "bundle": (bundle, [('f', 'force', None, @@ -2973,7 +3030,7 @@ table = { ('a', 'text', None, _('treat all files as text')), ('', 'switch-parent', None, _('diff against the second parent'))], _('hg export [-a] [-o OUTFILESPEC] REV...')), - "forget": + "debugforget|forget": (forget, [('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], @@ -3255,11 +3312,8 @@ def find(cmd): raise UnknownCommand(cmd) -class SignalInterrupt(Exception): - """Exception raised on SIGTERM and SIGHUP.""" - def catchterm(*args): - raise SignalInterrupt + raise util.SignalInterrupt def run(): sys.exit(dispatch(sys.argv[1:])) @@ -3311,7 +3365,7 @@ def dispatch(args): if num: signal.signal(num, catchterm) try: - u = ui.ui() + u = ui.ui(traceback='--traceback' in sys.argv[1:]) except util.Abort, inst: sys.stderr.write(_("abort: %s\n") % inst) return -1 @@ -3335,7 +3389,7 @@ def dispatch(args): external.append(mod) except Exception, inst: u.warn(_("*** failed to import extension %s: %s\n") % (x[0], inst)) - if "--traceback" in sys.argv[1:]: + if u.traceback: traceback.print_exc() return 1 continue @@ -3363,7 +3417,7 @@ def dispatch(args): atexit.register(print_time) u.updateopts(options["verbose"], options["debug"], options["quiet"], - not options["noninteractive"]) + not options["noninteractive"], options["traceback"]) # enter the debugger before command execution if options['debugger']: @@ -3430,7 +3484,7 @@ def dispatch(args): # enter the debugger when we hit an exception if options['debugger']: pdb.post_mortem(sys.exc_info()[2]) - if options['traceback']: + if u.traceback: traceback.print_exc() raise except ParseError, inst: @@ -3447,7 +3501,7 @@ def dispatch(args): u.warn(_("hg: unknown command '%s'\n") % inst.args[0]) help_(u, 'shortlist') except hg.RepoError, inst: - u.warn(_("abort: "), inst, "!\n") + u.warn(_("abort: %s!\n") % inst) except lock.LockHeld, inst: if inst.errno == errno.ETIMEDOUT: reason = _('timed out waiting for lock held by %s') % inst.locker @@ -3459,7 +3513,7 @@ def dispatch(args): (inst.desc or inst.filename, inst.strerror)) except revlog.RevlogError, inst: u.warn(_("abort: "), inst, "!\n") - except SignalInterrupt: + except util.SignalInterrupt: u.warn(_("killed!\n")) except KeyboardInterrupt: try: diff --git a/mercurial/hgweb.py b/mercurial/hgweb.py --- a/mercurial/hgweb.py +++ b/mercurial/hgweb.py @@ -125,7 +125,7 @@ class hgweb(object): def archivelist(self, nodeid): for i in self.archives: if self.repo.ui.configbool("web", "allow" + i, False): - yield {"type" : i, "node" : nodeid} + yield {"type" : i, "node" : nodeid, "url": ""} def listfiles(self, files, mf): for f in files[:self.maxfiles]: @@ -293,7 +293,8 @@ class hgweb(object): yield self.t('changelog', changenav=changenav, manifest=hex(mf), - rev=pos, changesets=count, entries=changelist) + rev=pos, changesets=count, entries=changelist, + archives=self.archivelist("tip")) def search(self, query): @@ -727,7 +728,9 @@ class hgweb(object): yield self.t("header", **map) def footer(**map): - yield self.t("footer", **map) + yield self.t("footer", + motd=self.repo.ui.config("web", "motd", ""), + **map) def expand_form(form): shortcuts = { @@ -1006,8 +1009,11 @@ class hgwebdir(object): def cleannames(items): return [(name.strip(os.sep), path) for name, path in items] + self.motd = "" + self.repos_sorted = ('name', False) if isinstance(config, (list, tuple)): self.repos = cleannames(config) + self.repos_sorted = ('', False) elif isinstance(config, dict): self.repos = cleannames(config.items()) self.repos.sort() @@ -1015,6 +1021,8 @@ class hgwebdir(object): cp = ConfigParser.SafeConfigParser() cp.read(config) self.repos = [] + if cp.has_section('web') and cp.has_option('web', 'motd'): + self.motd = cp.get('web', 'motd') if cp.has_section('paths'): self.repos.extend(cleannames(cp.items('paths'))) if cp.has_section('collections'): @@ -1032,14 +1040,20 @@ class hgwebdir(object): yield tmpl("header", **map) def footer(**map): - yield tmpl("footer", **map) + yield tmpl("footer", motd=self.motd, **map) m = os.path.join(templater.templatepath(), "map") tmpl = templater.templater(m, templater.common_filters, defaults={"header": header, "footer": footer}) - def entries(**map): + def archivelist(ui, nodeid, url): + for i in ['zip', 'gz', 'bz2']: + if ui.configbool("web", "allow" + i, False): + yield {"type" : i, "node": nodeid, "url": url} + + def entries(sortcolumn="", descending=False, **map): + rows = [] parity = 0 for name, path in self.repos: u = ui.ui() @@ -1058,16 +1072,37 @@ class hgwebdir(object): except OSError: continue - yield dict(contact=(get("ui", "username") or # preferred - get("web", "contact") or # deprecated - get("web", "author", "unknown")), # also - name=get("web", "name", name), + contact = (get("ui", "username") or # preferred + get("web", "contact") or # deprecated + get("web", "author", "")) # also + description = get("web", "description", "") + name = get("web", "name", name) + row = dict(contact=contact or "unknown", + contact_sort=contact.upper() or "unknown", + name=name, + name_sort=name, url=url, - parity=parity, - shortdesc=get("web", "description", "unknown"), - lastupdate=d) - - parity = 1 - parity + description=description or "unknown", + description_sort=description.upper() or "unknown", + lastchange=d, + lastchange_sort=d[1]-d[0], + archives=archivelist(u, "tip", url)) + if (not sortcolumn + or (sortcolumn, descending) == self.repos_sorted): + # fast path for unsorted output + row['parity'] = parity + parity = 1 - parity + yield row + else: + rows.append((row["%s_sort" % sortcolumn], row)) + if rows: + rows.sort() + if descending: + rows.reverse() + for key, row in rows: + row['parity'] = parity + parity = 1 - parity + yield row virtual = req.env.get("PATH_INFO", "").strip('/') if virtual: @@ -1088,4 +1123,20 @@ class hgwebdir(object): req.write(staticfile(static, fname) or tmpl("error", error="%r not found" % fname)) else: - req.write(tmpl("index", entries=entries)) + sortable = ["name", "description", "contact", "lastchange"] + sortcolumn, descending = self.repos_sorted + if req.form.has_key('sort'): + sortcolumn = req.form['sort'][0] + descending = sortcolumn.startswith('-') + if descending: + sortcolumn = sortcolumn[1:] + if sortcolumn not in sortable: + sortcolumn = "" + + sort = [("sort_%s" % column, + "%s%s" % ((not descending and column == sortcolumn) + and "-" or "", column)) + for column in sortable] + req.write(tmpl("index", entries=entries, + sortcolumn=sortcolumn, descending=descending, + **dict(sort))) diff --git a/mercurial/httprangereader.py b/mercurial/httprangereader.py --- a/mercurial/httprangereader.py +++ b/mercurial/httprangereader.py @@ -18,7 +18,11 @@ class httprangereader(object): urllib2.install_opener(opener) req = urllib2.Request(self.url) end = '' - if bytes: end = self.pos + bytes + if bytes: + end = self.pos + bytes - 1 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end)) f = urllib2.urlopen(req) - return f.read() + data = f.read() + if bytes: + data = data[:bytes] + return data diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -11,7 +11,8 @@ from node import * from i18n import gettext as _ from demandload import * demandload(globals(), "appendfile changegroup") -demandload(globals(), "re lock transaction tempfile stat mdiff errno ui revlog") +demandload(globals(), "re lock transaction tempfile stat mdiff errno ui") +demandload(globals(), "revlog traceback") class localrepository(object): def __del__(self): @@ -42,7 +43,8 @@ class localrepository(object): pass v = self.ui.revlogopts - self.revlogversion = int(v.get('format', 0)) + self.revlogversion = int(v.get('format', revlog.REVLOGV0)) + self.revlogv1 = self.revlogversion != revlog.REVLOGV0 flags = 0 for x in v.get('flags', "").split(): flags |= revlog.flagstr(x) @@ -71,7 +73,59 @@ class localrepository(object): os.mkdir(self.join("data")) self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) + def hook(self, name, throw=False, **args): + def callhook(hname, funcname): + '''call python hook. hook is callable object, looked up as + name in python module. if callable returns "true", hook + passes, else fails. if hook raises exception, treated as + hook failure. exception propagates if throw is "true".''' + + self.ui.note(_("calling hook %s: %s\n") % (hname, funcname)) + d = funcname.rfind('.') + if d == -1: + raise util.Abort(_('%s hook is invalid ("%s" not in a module)') + % (hname, funcname)) + modname = funcname[:d] + try: + obj = __import__(modname) + except ImportError: + raise util.Abort(_('%s hook is invalid ' + '(import of "%s" failed)') % + (hname, modname)) + try: + for p in funcname.split('.')[1:]: + obj = getattr(obj, p) + except AttributeError, err: + raise util.Abort(_('%s hook is invalid ' + '("%s" is not defined)') % + (hname, funcname)) + if not callable(obj): + raise util.Abort(_('%s hook is invalid ' + '("%s" is not callable)') % + (hname, funcname)) + try: + r = obj(ui=ui, repo=repo, hooktype=name, **args) + except (KeyboardInterrupt, util.SignalInterrupt): + raise + except Exception, exc: + if isinstance(exc, util.Abort): + self.ui.warn(_('error: %s hook failed: %s\n') % + (hname, exc.args[0] % exc.args[1:])) + else: + self.ui.warn(_('error: %s hook raised an exception: ' + '%s\n') % (hname, exc)) + if throw: + raise + if self.ui.traceback: + traceback.print_exc() + return False + if not r: + if throw: + raise util.Abort(_('%s hook failed') % hname) + self.ui.warn(_('error: %s hook failed\n') % hname) + return r + def runhook(name, cmd): self.ui.note(_("running hook %s: %s\n") % (name, cmd)) env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()] + @@ -90,7 +144,10 @@ class localrepository(object): if hname.split(".", 1)[0] == name and cmd] hooks.sort() for hname, cmd in hooks: - r = runhook(hname, cmd) and r + if cmd.startswith('python:'): + r = callhook(hname, cmd[7:].strip()) and r + else: + r = runhook(hname, cmd) and r return r def tags(self): @@ -1320,7 +1377,8 @@ class localrepository(object): # Signal that no more groups are left. yield changegroup.closechunk() - self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) + if msng_cl_lst: + self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) return util.chunkbuffer(gengroup()) @@ -1766,7 +1824,7 @@ class localrepository(object): def temp(prefix, node): pre = "%s~%s." % (os.path.basename(fn), prefix) - (fd, name) = tempfile.mkstemp("", pre) + (fd, name) = tempfile.mkstemp(prefix=pre) f = os.fdopen(fd, "wb") self.wwrite(fn, fl.read(node), f) f.close() @@ -1803,12 +1861,17 @@ class localrepository(object): filenodes = {} changesets = revisions = files = 0 errors = [0] + warnings = [0] neededmanifests = {} def err(msg): self.ui.warn(msg + "\n") errors[0] += 1 + def warn(msg): + self.ui.warn(msg + "\n") + warnings[0] += 1 + def checksize(obj, name): d = obj.checksize() if d[0]: @@ -1816,6 +1879,18 @@ class localrepository(object): if d[1]: err(_("%s index contains %d extra bytes") % (name, d[1])) + def checkversion(obj, name): + if obj.version != revlog.REVLOGV0: + if not revlogv1: + warn(_("warning: `%s' uses revlog format 1") % name) + elif revlogv1: + warn(_("warning: `%s' uses revlog format 0") % name) + + revlogv1 = self.revlogversion != revlog.REVLOGV0 + if self.ui.verbose or revlogv1 != self.revlogv1: + self.ui.status(_("repository uses revlog format %d\n") % + (revlogv1 and 1 or 0)) + seen = {} self.ui.status(_("checking changesets\n")) checksize(self.changelog, "changelog") @@ -1850,6 +1925,7 @@ class localrepository(object): seen = {} self.ui.status(_("checking manifests\n")) + checkversion(self.manifest, "manifest") checksize(self.manifest, "manifest") for i in range(self.manifest.count()): @@ -1914,6 +1990,7 @@ class localrepository(object): err(_("file without name in manifest %s") % short(n)) continue fl = self.file(f) + checkversion(fl, f) checksize(fl, f) nodes = {nullid: 1} @@ -1962,6 +2039,8 @@ class localrepository(object): self.ui.status(_("%d files, %d changesets, %d total revisions\n") % (files, changesets, revisions)) + if warnings[0]: + self.ui.warn(_("%d warnings encountered!\n") % warnings[0]) if errors[0]: self.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) return 1 diff --git a/mercurial/manifest.py b/mercurial/manifest.py --- a/mercurial/manifest.py +++ b/mercurial/manifest.py @@ -12,7 +12,7 @@ from demandload import * demandload(globals(), "bisect array") class manifest(revlog): - def __init__(self, opener, defversion=0): + def __init__(self, opener, defversion=REVLOGV0): self.mapcache = None self.listcache = None revlog.__init__(self, opener, "00manifest.i", "00manifest.d", diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -293,7 +293,7 @@ class revlog(object): remove data, and can use some simple techniques to avoid the need for locking while reading. """ - def __init__(self, opener, indexfile, datafile, defversion=0): + def __init__(self, opener, indexfile, datafile, defversion=REVLOGV0): """ create a revlog object @@ -333,11 +333,11 @@ class revlog(object): and st.st_ctime == oldst.st_ctime): return self.indexstat = st - if len(i) > 0: - v = struct.unpack(versionformat, i)[0] + if len(i) > 0: + v = struct.unpack(versionformat, i)[0] flags = v & ~0xFFFF fmt = v & 0xFFFF - if fmt == 0: + if fmt == REVLOGV0: if flags: raise RevlogError(_("index %s invalid flags %x for format v0" % (self.indexfile, flags))) @@ -349,7 +349,7 @@ class revlog(object): raise RevlogError(_("index %s invalid format %d" % (self.indexfile, fmt))) self.version = v - if v == 0: + if v == REVLOGV0: self.indexformat = indexformatv0 shaoffset = v0shaoffset else: @@ -369,7 +369,7 @@ class revlog(object): # we've already got the entire data file read in, save it # in the chunk data self.chunkcache = (0, i) - if self.version != 0: + if self.version != REVLOGV0: e = list(self.index[0]) type = self.ngtype(e[0]) e[0] = self.offset_type(0, type) @@ -399,7 +399,7 @@ class revlog(object): def ngoffset(self, q): if q & 0xFFFF: raise RevlogError(_('%s: incompatible revision flag %x') % - (self.indexfile, type)) + (self.indexfile, q)) return long(q >> 16) def ngtype(self, q): @@ -441,13 +441,13 @@ class revlog(object): if node == nullid: return (nullid, nullid) r = self.rev(node) d = self.index[r][-3:-1] - if self.version == 0: + if self.version == REVLOGV0: return d return [ self.node(x) for x in d ] def start(self, rev): if rev < 0: return -1 - if self.version != 0: + if self.version != REVLOGV0: return self.ngoffset(self.index[rev][0]) return self.index[rev][0] @@ -456,7 +456,7 @@ class revlog(object): def size(self, rev): """return the length of the uncompressed text for a given revision""" l = -1 - if self.version != 0: + if self.version != REVLOGV0: l = self.index[rev][2] if l >= 0: return l @@ -911,7 +911,7 @@ class revlog(object): if t >= 0: offset = self.end(t) - if self.version == 0: + if self.version == REVLOGV0: e = (offset, l, base, link, p1, p2, node) else: e = (self.offset_type(offset, 0), l, len(text), @@ -935,7 +935,7 @@ class revlog(object): f.seek(0, 2) transaction.add(self.indexfile, f.tell(), self.count() - 1) - if len(self.index) == 1 and self.version != 0: + if len(self.index) == 1 and self.version != REVLOGV0: l = struct.pack(versionformat, self.version) f.write(l) entry = entry[4:] @@ -1135,7 +1135,7 @@ class revlog(object): raise RevlogError(_("consistency error adding group")) textlen = len(text) else: - if self.version == 0: + if self.version == REVLOGV0: e = (end, len(cdelta), base, link, p1, p2, node) else: e = (self.offset_type(end, 0), len(cdelta), textlen, base, diff --git a/mercurial/sshrepo.py b/mercurial/sshrepo.py --- a/mercurial/sshrepo.py +++ b/mercurial/sshrepo.py @@ -9,7 +9,7 @@ from node import * from remoterepo import * from i18n import gettext as _ from demandload import * -demandload(globals(), "hg os re stat") +demandload(globals(), "hg os re stat util") class sshrepository(remoterepository): def __init__(self, ui, path): diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -12,7 +12,7 @@ demandload(globals(), "errno os re socke class ui(object): def __init__(self, verbose=False, debug=False, quiet=False, - interactive=True, parentui=None): + interactive=True, traceback=False, parentui=None): self.overlay = {} if parentui is None: # this is the parent of all ui children @@ -24,6 +24,7 @@ class ui(object): self.verbose = self.configbool("ui", "verbose") self.debugflag = self.configbool("ui", "debug") self.interactive = self.configbool("ui", "interactive", True) + self.traceback = traceback self.updateopts(verbose, debug, quiet, interactive) self.diffcache = None @@ -45,11 +46,12 @@ class ui(object): return getattr(self.parentui, key) def updateopts(self, verbose=False, debug=False, quiet=False, - interactive=True): + interactive=True, traceback=False): self.quiet = (self.quiet or quiet) and not verbose and not debug self.verbose = (self.verbose or verbose) or debug self.debugflag = (self.debugflag or debug) self.interactive = (self.interactive and interactive) + self.traceback = self.traceback or traceback def readconfig(self, fn, root=None): if isinstance(fn, basestring): diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -16,6 +16,9 @@ from demandload import * demandload(globals(), "cStringIO errno popen2 re shutil sys tempfile") demandload(globals(), "threading time") +class SignalInterrupt(Exception): + """Exception raised on SIGTERM and SIGHUP.""" + def pipefilter(s, cmd): '''filter string S through command CMD, returning its output''' (pout, pin) = popen2.popen2(cmd, -1, 'b') @@ -43,11 +46,11 @@ def tempfilter(s, cmd): the temporary files generated.''' inname, outname = None, None try: - infd, inname = tempfile.mkstemp(prefix='hgfin') + infd, inname = tempfile.mkstemp(prefix='hg-filter-in-') fp = os.fdopen(infd, 'wb') fp.write(s) fp.close() - outfd, outname = tempfile.mkstemp(prefix='hgfout') + outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-') os.close(outfd) cmd = cmd.replace('INFILE', inname) cmd = cmd.replace('OUTFILE', outname) @@ -676,7 +679,7 @@ def opener(base, audit=True): def mktempcopy(name): d, fn = os.path.split(name) - fd, temp = tempfile.mkstemp(prefix=fn, dir=d) + fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) os.close(fd) fp = posixfile(temp, "wb") try: diff --git a/templates/changelog.tmpl b/templates/changelog.tmpl --- a/templates/changelog.tmpl +++ b/templates/changelog.tmpl @@ -8,6 +8,7 @@
tags manifest +#archives%archiveentry# rss
diff --git a/templates/changelogentry.tmpl b/templates/changelogentry.tmpl --- a/templates/changelogentry.tmpl +++ b/templates/changelogentry.tmpl @@ -1,11 +1,11 @@ - +
- + - - + + #parent%changelogparent# #child%changelogchild# diff --git a/templates/filelogentry.tmpl b/templates/filelogentry.tmpl --- a/templates/filelogentry.tmpl +++ b/templates/filelogentry.tmpl @@ -1,20 +1,25 @@ -
#date|age# ago:#date|age# ago: #desc|strip|firstline|escape#
changeset #rev#:#node|short#changeset #rev#:#node|short#
- - - - - - -#rename%filelogrename# - - - - - - +
#date|age# ago: #desc|strip|firstline|escape#
revision #filerev#: #filenode|short# -(diff) -(annotate) -
author: #author|obfuscate#
date: #date|date# (#date|age# ago)
+ + + + + + + + #rename%filelogrename# + + + + + + + +
#date|age# ago:#desc|strip|firstline|escape#
revision #filerev#: + + #filenode|short# + (diff) + (annotate) +
author:#author|obfuscate#
date:#date|date#
diff --git a/templates/footer.tmpl b/templates/footer.tmpl --- a/templates/footer.tmpl +++ b/templates/footer.tmpl @@ -1,3 +1,4 @@ +#motd#