# HG changeset patch # User Bryan O'Sullivan # Date 1201305886 28800 # Node ID 597d8402087d7fa2a9b61c2f352d99670bd8faf8 # Parent 528c986f016216943df9ab3f69abc4bcea89e0b2# Parent ee0dc0f3804b8527070ff3b73e71a30b2d8267d2 Merge after backout diff -r 528c986f0162 -r 597d8402087d contrib/churn.py --- a/contrib/churn.py Fri Jan 25 16:04:32 2008 -0800 +++ b/contrib/churn.py Fri Jan 25 16:04:46 2008 -0800 @@ -114,11 +114,11 @@ who, lines = __gather(ui, repo, node1, node2) # remap the owner if possible - if amap.has_key(who): + if who in amap: ui.note("using '%s' alias for '%s'\n" % (amap[who], who)) who = amap[who] - if not stats.has_key(who): + if not who in stats: stats[who] = 0 stats[who] += lines diff -r 528c986f0162 -r 597d8402087d contrib/zsh_completion --- a/contrib/zsh_completion Fri Jan 25 16:04:32 2008 -0800 +++ b/contrib/zsh_completion Fri Jan 25 16:04:46 2008 -0800 @@ -13,6 +13,9 @@ # option) any later version. # +emulate -LR zsh +setopt extendedglob + local curcontext="$curcontext" state line typeset -A _hg_cmd_globals @@ -153,9 +156,9 @@ typeset -a tags local tag rev - _hg_cmd tags 2> /dev/null | while read tag rev + _hg_cmd tags 2> /dev/null | while read tag do - tags+=($tag) + tags+=(${tag/ # [0-9]#:*}) done (( $#tags )) && _describe -t tags 'tags' tags } @@ -674,13 +677,13 @@ # MQ _hg_qseries() { typeset -a patches - patches=($(_hg_cmd qseries 2>/dev/null)) + patches=(${(f)"$(_hg_cmd qseries 2>/dev/null)"}) (( $#patches )) && _describe -t hg-patches 'patches' patches } _hg_qapplied() { typeset -a patches - patches=($(_hg_cmd qapplied 2>/dev/null)) + patches=(${(f)"$(_hg_cmd qapplied 2>/dev/null)"}) if (( $#patches )) then patches+=(qbase qtip) @@ -690,7 +693,7 @@ _hg_qunapplied() { typeset -a patches - patches=($(_hg_cmd qunapplied 2>/dev/null)) + patches=(${(f)"$(_hg_cmd qunapplied 2>/dev/null)"}) (( $#patches )) && _describe -t hg-unapplied-patches 'unapplied patches' patches } @@ -730,6 +733,12 @@ '*:unapplied patch:_hg_qunapplied' } +_hg_cmd_qgoto() { + _arguments -s -w : $_hg_global_opts \ + '(--force -f)'{-f,--force}'[overwrite any local changes]' \ + ':patch:_hg_qseries' +} + _hg_cmd_qguard() { _arguments -s -w : $_hg_global_opts \ '(--list -l)'{-l,--list}'[list all patches and guards]' \ diff -r 528c986f0162 -r 597d8402087d hgext/convert/cvs.py --- a/hgext/convert/cvs.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/convert/cvs.py Fri Jan 25 16:04:46 2008 -0800 @@ -53,11 +53,13 @@ os.chdir(self.path) id = None state = 0 + filerevids = {} for l in util.popen(cmd): if state == 0: # header if l.startswith("PatchSet"): id = l[9:-2] if maxrev and int(id) > maxrev: + # ignore everything state = 3 elif l.startswith("Date"): date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"]) @@ -68,7 +70,8 @@ self.lastbranch[branch] = id elif l.startswith("Ancestor branch"): ancestor = l[17:-1] - self.parent[id] = self.lastbranch[ancestor] + # figure out the parent later + self.parent[id] = None elif l.startswith("Author"): author = self.recode(l[8:-1]) elif l.startswith("Tag:") or l.startswith("Tags:"): @@ -77,23 +80,36 @@ if (len(t) > 1) or (t[0] and (t[0] != "(none)")): self.tags.update(dict.fromkeys(t, id)) elif l.startswith("Log:"): + # switch to gathering log state = 1 log = "" elif state == 1: # log if l == "Members: \n": + # switch to gathering members files = {} + oldrevs = [] log = self.recode(log[:-1]) state = 2 else: + # gather log log += l - elif state == 2: - if l == "\n": # + elif state == 2: # members + if l == "\n": # start of next entry state = 0 p = [self.parent[id]] if id == "1": p = [] if branch == "HEAD": branch = "" + if branch and p[0] == None: + latest = None + # the last changeset that contains a base + # file is our parent + for r in oldrevs: + latest = max(filerevids[r], latest) + p = [latest] + + # add current commit to set c = commit(author=author, date=date, parents=p, desc=log, branch=branch) self.changeset[id] = c @@ -102,9 +118,14 @@ colon = l.rfind(':') file = l[1:colon] rev = l[colon+1:-2] - rev = rev.split("->")[1] + oldrev, rev = rev.split("->") files[file] = rev + + # save some information for identifying branch points + oldrevs.append("%s:%s" % (oldrev, file)) + filerevids["%s:%s" % (rev, file)] = id elif state == 3: + # swallow all input continue self.heads = self.lastbranch.values() diff -r 528c986f0162 -r 597d8402087d hgext/convert/hg.py --- a/hgext/convert/hg.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/convert/hg.py Fri Jan 25 16:04:46 2008 -0800 @@ -30,6 +30,8 @@ if os.path.isdir(path) and len(os.listdir(path)) > 0: try: self.repo = hg.repository(self.ui, path) + if not self.repo.local(): + raise NoRepo(_('%s is not a local Mercurial repo') % path) except hg.RepoError, err: ui.print_exc() raise NoRepo(err.args[0]) @@ -37,6 +39,8 @@ try: ui.status(_('initializing destination %s repository\n') % path) self.repo = hg.repository(self.ui, path, create=True) + if not self.repo.local(): + raise NoRepo(_('%s is not a local Mercurial repo') % path) self.created.append(path) except hg.RepoError, err: ui.print_exc() diff -r 528c986f0162 -r 597d8402087d hgext/convert/subversion.py --- a/hgext/convert/subversion.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/convert/subversion.py Fri Jan 25 16:04:46 2008 -0800 @@ -89,6 +89,9 @@ receiver) except SubversionException, (inst, num): pickle.dump(num, fp, protocol) + except IOError: + # Caller may interrupt the iteration + pickle.dump(None, fp, protocol) else: pickle.dump(None, fp, protocol) fp.close() @@ -102,7 +105,53 @@ args = decodeargs(sys.stdin.read()) get_log_child(sys.stdout, *args) +class logstream: + """Interruptible revision log iterator.""" + def __init__(self, stdout): + self._stdout = stdout + + def __iter__(self): + while True: + entry = pickle.load(self._stdout) + try: + orig_paths, revnum, author, date, message = entry + except: + if entry is None: + break + raise SubversionException("child raised exception", entry) + yield entry + + def close(self): + if self._stdout: + self._stdout.close() + self._stdout = None + +def get_log(url, paths, start, end, limit=0, discover_changed_paths=True, + strict_node_history=False): + args = [url, paths, start, end, limit, discover_changed_paths, + strict_node_history] + arg = encodeargs(args) + hgexe = util.hgexecutable() + cmd = '%s debugsvnlog' % util.shellquote(hgexe) + stdin, stdout = os.popen2(cmd, 'b') + stdin.write(arg) + stdin.close() + return logstream(stdout) + # SVN conversion code stolen from bzr-svn and tailor +# +# Subversion looks like a versioned filesystem, branches structures +# are defined by conventions and not enforced by the tool. First, +# we define the potential branches (modules) as "trunk" and "branches" +# children directories. Revisions are then identified by their +# module and revision number (and a repository identifier). +# +# The revision graph is really a tree (or a forest). By default, a +# revision parent is the previous revision in the same module. If the +# module directory is copied/moved from another module then the +# revision is the module root and its parent the source revision in +# the parent module. A revision has at most one parent. +# class svn_source(converter_source): def __init__(self, ui, url, rev=None): super(svn_source, self).__init__(ui, url, rev=rev) @@ -133,7 +182,6 @@ self.ctx = self.transport.client self.base = svn.ra.get_repos_root(self.ra) self.module = self.url[len(self.base):] - self.modulemap = {} # revision, module self.commits = {} self.paths = {} self.uuid = svn.ra.get_uuid(self.ra).decode(self.encoding) @@ -257,45 +305,26 @@ uuid, module, revnum = self.revsplit(rev) self.module = module self.reparent(module) + # We assume that: + # - requests for revisions after "stop" come from the + # revision graph backward traversal. Cache all of them + # down to stop, they will be used eventually. + # - requests for revisions before "stop" come to get + # isolated branches parents. Just fetch what is needed. stop = self.lastrevs.get(module, 0) - self._fetch_revisions(from_revnum=revnum, to_revnum=stop) + if revnum < stop: + stop = revnum + 1 + self._fetch_revisions(revnum, stop) commit = self.commits[rev] # caller caches the result, so free it here to release memory del self.commits[rev] return commit - def get_log(self, paths, start, end, limit=0, discover_changed_paths=True, - strict_node_history=False): - - def parent(fp): - while True: - entry = pickle.load(fp) - try: - orig_paths, revnum, author, date, message = entry - except: - if entry is None: - break - raise SubversionException("child raised exception", entry) - yield entry - - args = [self.url, paths, start, end, limit, discover_changed_paths, - strict_node_history] - arg = encodeargs(args) - hgexe = util.hgexecutable() - cmd = '%s debugsvnlog' % util.shellquote(hgexe) - stdin, stdout = os.popen2(cmd, 'b') - - stdin.write(arg) - stdin.close() - - for p in parent(stdout): - yield p - def gettags(self): tags = {} start = self.revnum(self.head) try: - for entry in self.get_log([self.tags], 0, start): + for entry in get_log(self.url, [self.tags], 0, start): orig_paths, revnum, author, date, message = entry for path in orig_paths: if not path.startswith(self.tags+'/'): @@ -400,13 +429,11 @@ entries = [] copyfrom = {} # Map of entrypath, revision for finding source of deleted revisions. copies = {} - revnum = self.revnum(rev) - if revnum in self.modulemap: - new_module = self.modulemap[revnum] - if new_module != self.module: - self.module = new_module - self.reparent(self.module) + new_module, revnum = self.revsplit(rev)[1:] + if new_module != self.module: + self.module = new_module + self.reparent(self.module) for path, ent in paths: entrypath = get_entry_from_path(path, module=self.module) @@ -432,12 +459,9 @@ # if a branch is created but entries are removed in the same # changeset, get the right fromrev - if parents: - uuid, old_module, fromrev = self.revsplit(parents[0]) - else: - fromrev = revnum - 1 - # might always need to be revnum - 1 in these 3 lines? - old_module = self.modulemap.get(fromrev, self.module) + # parents cannot be empty here, you cannot remove things from + # a root revision. + uuid, old_module, fromrev = self.revsplit(parents[0]) basepath = old_module + "/" + get_entry_from_path(path, module=self.module) entrypath = old_module + "/" + get_entry_from_path(path, module=self.module) @@ -466,7 +490,12 @@ fromrev = froment.copyfrom_rev self.ui.debug("Info: %s %s %s %s\n" % (frompath, froment, ent, entrypath)) - fromkind = svn.ra.check_path(self.ra, entrypath, fromrev) + # We can avoid the reparent calls if the module has not changed + # but it probably does not worth the pain. + self.reparent('') + fromkind = svn.ra.check_path(self.ra, entrypath.strip('/'), fromrev) + self.reparent(self.module) + if fromkind == svn.core.svn_node_file: # a deleted file entries.append(self.recode(entry)) elif fromkind == svn.core.svn_node_dir: @@ -508,6 +537,9 @@ # If the directory just had a prop change, # then we shouldn't need to look for its children. + if ent.action == 'M': + continue + # Also this could create duplicate entries. Not sure # whether this will matter. Maybe should make entries a set. # print "Changed directory", revnum, path, ent.action, ent.copyfrom_path, ent.copyfrom_rev @@ -566,25 +598,25 @@ copies[self.recode(copyto_entry)] = self.recode(entry) # copy from quux splort/quuxfile - return (entries, copies) + return (util.unique(entries), copies) - def _fetch_revisions(self, from_revnum = 0, to_revnum = 347): + def _fetch_revisions(self, from_revnum, to_revnum): + if from_revnum < to_revnum: + from_revnum, to_revnum = to_revnum, from_revnum + self.child_cset = None def parselogentry(orig_paths, revnum, author, date, message): + """Return the parsed commit object or None, and True if + the revision is a branch root. + """ self.ui.debug("parsing revision %d (%d changes)\n" % (revnum, len(orig_paths))) - if revnum in self.modulemap: - new_module = self.modulemap[revnum] - if new_module != self.module: - self.module = new_module - self.reparent(self.module) - rev = self.revid(revnum) # branch log might return entries for a parent we already have - if (rev in self.commits or - (revnum < self.lastrevs.get(self.module, 0))): - return + + if (rev in self.commits or revnum < to_revnum): + return None, False parents = [] # check whether this revision is the start of a branch @@ -593,15 +625,12 @@ if ent.copyfrom_path: # ent.copyfrom_rev may not be the actual last revision prev = self.latest(ent.copyfrom_path, ent.copyfrom_rev) - self.modulemap[prev] = ent.copyfrom_path parents = [self.revid(prev, ent.copyfrom_path)] self.ui.note('found parent of branch %s at %d: %s\n' % \ (self.module, prev, ent.copyfrom_path)) else: self.ui.debug("No copyfrom path, don't know what to do.\n") - self.modulemap[revnum] = self.module # track backwards in time - orig_paths = orig_paths.items() orig_paths.sort() paths = [] @@ -612,14 +641,12 @@ continue paths.append((path, ent)) - self.paths[rev] = (paths, parents) - # Example SVN datetime. Includes microseconds. # ISO-8601 conformant # '2007-01-04T17:35:00.902377Z' date = util.parsedate(date[:19] + " UTC", ["%Y-%m-%dT%H:%M:%S"]) - log = message and self.recode(message) + log = message and self.recode(message) or '' author = author and self.recode(author) or '' try: branch = self.module.split("/")[-1] @@ -636,23 +663,50 @@ rev=rev.encode('utf-8')) self.commits[rev] = cset + # The parents list is *shared* among self.paths and the + # commit object. Both will be updated below. + self.paths[rev] = (paths, cset.parents) if self.child_cset and not self.child_cset.parents: - self.child_cset.parents = [rev] + self.child_cset.parents[:] = [rev] self.child_cset = cset + return cset, len(parents) > 0 self.ui.note('fetching revision log for "%s" from %d to %d\n' % (self.module, from_revnum, to_revnum)) try: - for entry in self.get_log([self.module], from_revnum, to_revnum): - orig_paths, revnum, author, date, message = entry - if self.is_blacklisted(revnum): - self.ui.note('skipping blacklisted revision %d\n' % revnum) - continue - if orig_paths is None: - self.ui.debug('revision %d has no entries\n' % revnum) - continue - parselogentry(orig_paths, revnum, author, date, message) + firstcset = None + stream = get_log(self.url, [self.module], from_revnum, to_revnum) + try: + for entry in stream: + paths, revnum, author, date, message = entry + if self.is_blacklisted(revnum): + self.ui.note('skipping blacklisted revision %d\n' + % revnum) + continue + if paths is None: + self.ui.debug('revision %d has no entries\n' % revnum) + continue + cset, branched = parselogentry(paths, revnum, author, + date, message) + if cset: + firstcset = cset + if branched: + break + finally: + stream.close() + + if firstcset and not firstcset.parents: + # The first revision of the sequence (the last fetched one) + # has invalid parents if not a branch root. Find the parent + # revision now, if any. + try: + firstrevnum = self.revnum(firstcset.rev) + if firstrevnum > 1: + latest = self.latest(self.module, firstrevnum - 1) + firstcset.parents.append(self.revid(latest)) + except util.Abort: + pass except SubversionException, (inst, num): if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(branch=self, @@ -664,9 +718,9 @@ # TODO: ra.get_file transmits the whole file instead of diffs. mode = '' try: - revnum = self.revnum(rev) - if self.module != self.modulemap[revnum]: - self.module = self.modulemap[revnum] + new_module, revnum = self.revsplit(rev)[1:] + if self.module != new_module: + self.module = new_module self.reparent(self.module) info = svn.ra.get_file(self.ra, file, revnum, io) if isinstance(info, list): diff -r 528c986f0162 -r 597d8402087d hgext/graphlog.py --- a/hgext/graphlog.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/graphlog.py Fri Jan 25 16:04:46 2008 -0800 @@ -5,11 +5,12 @@ # This software may be used and distributed according to the terms of # the GNU General Public License, incorporated herein by reference. +import os import sys from mercurial.cmdutil import revrange, show_changeset from mercurial.i18n import _ from mercurial.node import nullid, nullrev -from mercurial.util import Abort +from mercurial.util import Abort, canonpath def revision_grapher(repo, start_rev, stop_rev): """incremental revision grapher @@ -63,6 +64,62 @@ revs = next_revs curr_rev -= 1 +def filelog_grapher(repo, path, start_rev, stop_rev): + """incremental file log grapher + + This generator function walks through the revision history of a + single file from revision start_rev to revision stop_rev (which must + be less than or equal to start_rev) and for each revision emits + tuples with the following elements: + + - Current revision. + - Current node. + - Column of the current node in the set of ongoing edges. + - Edges; a list of (col, next_col) indicating the edges between + the current node and its parents. + - Number of columns (ongoing edges) in the current revision. + - The difference between the number of columns (ongoing edges) + in the next revision and the number of columns (ongoing edges) + in the current revision. That is: -1 means one column removed; + 0 means no columns added or removed; 1 means one column added. + """ + + assert start_rev >= stop_rev + curr_rev = start_rev + revs = [] + filerev = repo.file(path).count() - 1 + while filerev >= 0: + fctx = repo.filectx(path, fileid=filerev) + + # Compute revs and next_revs. + if filerev not in revs: + revs.append(filerev) + rev_index = revs.index(filerev) + next_revs = revs[:] + + # Add parents to next_revs. + parents = [f.filerev() for f in fctx.parents()] + parents_to_add = [] + for parent in parents: + if parent not in next_revs: + parents_to_add.append(parent) + parents_to_add.sort() + next_revs[rev_index:rev_index + 1] = parents_to_add + + edges = [] + for parent in parents: + edges.append((rev_index, next_revs.index(parent))) + + changerev = fctx.linkrev() + if changerev <= start_rev: + node = repo.changelog.node(changerev) + n_columns_diff = len(next_revs) - len(revs) + yield (changerev, node, rev_index, edges, len(revs), n_columns_diff) + if changerev <= stop_rev: + break + revs = next_revs + filerev -= 1 + def get_rev_parents(repo, rev): return [x for x in repo.changelog.parentrevs(rev) if x != nullrev] @@ -141,7 +198,7 @@ else: return (repo.changelog.count() - 1, 0) -def graphlog(ui, repo, **opts): +def graphlog(ui, repo, path=None, **opts): """show revision history alongside an ASCII revision graph Print a revision history alongside a revision graph drawn with @@ -157,7 +214,11 @@ if start_rev == nullrev: return cs_printer = show_changeset(ui, repo, opts) - grapher = revision_grapher(repo, start_rev, stop_rev) + if path: + cpath = canonpath(repo.root, os.getcwd(), path) + grapher = filelog_grapher(repo, cpath, start_rev, stop_rev) + else: + grapher = revision_grapher(repo, start_rev, stop_rev) repo_parents = repo.dirstate.parents() prev_n_columns_diff = 0 prev_node_index = 0 @@ -261,5 +322,5 @@ ('r', 'rev', [], _('show the specified revision or range')), ('', 'style', '', _('display using template map file')), ('', 'template', '', _('display with template'))], - _('hg glog [OPTION]...')), + _('hg glog [OPTION]... [FILE]')), } diff -r 528c986f0162 -r 597d8402087d hgext/hgk.py --- a/hgext/hgk.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/hgk.py Fri Jan 25 16:04:46 2008 -0800 @@ -45,7 +45,7 @@ # Revisions context menu will now display additional entries to fire # vdiff on hovered and selected revisions. -import sys, os +import os from mercurial import hg, fancyopts, commands, ui, util, patch, revlog def difftree(ui, repo, node1=None, node2=None, *files, **opts): @@ -61,17 +61,14 @@ for f in modified: # TODO get file permissions - print ":100664 100664 %s %s M\t%s\t%s" % (hg.short(mmap[f]), - hg.short(mmap2[f]), - f, f) + ui.write(":100664 100664 %s %s M\t%s\t%s\n" % + (hg.short(mmap[f]), hg.short(mmap2[f]), f, f)) for f in added: - print ":000000 100664 %s %s N\t%s\t%s" % (empty, - hg.short(mmap2[f]), - f, f) + ui.write(":000000 100664 %s %s N\t%s\t%s\n" % + (empty, hg.short(mmap2[f]), f, f)) for f in removed: - print ":100664 000000 %s %s D\t%s\t%s" % (hg.short(mmap[f]), - empty, - f, f) + ui.write(":100664 000000 %s %s D\t%s\t%s\n" % + (hg.short(mmap[f]), empty, f, f)) ## while True: @@ -93,7 +90,7 @@ node1 = repo.changelog.parents(node1)[0] if opts['patch']: if opts['pretty']: - catcommit(repo, node2, "") + catcommit(ui, repo, node2, "") patch.diff(repo, node1, node2, files=files, opts=patch.diffopts(ui, {'git': True})) @@ -102,14 +99,14 @@ if not opts['stdin']: break -def catcommit(repo, n, prefix, ctx=None): +def catcommit(ui, repo, n, prefix, ctx=None): nlprefix = '\n' + prefix; if ctx is None: ctx = repo.changectx(n) (p1, p2) = ctx.parents() - print "tree %s" % (hg.short(ctx.changeset()[0])) # use ctx.node() instead ?? - if p1: print "parent %s" % (hg.short(p1.node())) - if p2: print "parent %s" % (hg.short(p2.node())) + ui.write("tree %s\n" % hg.short(ctx.changeset()[0])) # use ctx.node() instead ?? + if p1: ui.write("parent %s\n" % hg.short(p1.node())) + if p2: ui.write("parent %s\n" % hg.short(p2.node())) date = ctx.date() description = ctx.description().replace("\0", "") lines = description.splitlines() @@ -118,24 +115,24 @@ else: committer = ctx.user() - print "author %s %s %s" % (ctx.user(), int(date[0]), date[1]) - print "committer %s %s %s" % (committer, int(date[0]), date[1]) - print "revision %d" % ctx.rev() - print "branch %s" % ctx.branch() - print "" + ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1])) + ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1])) + ui.write("revision %d\n" % ctx.rev()) + ui.write("branch %s\n\n" % ctx.branch()) + if prefix != "": - print "%s%s" % (prefix, description.replace('\n', nlprefix).strip()) + ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip())) else: - print description + ui.write(description + "\n") if prefix: - sys.stdout.write('\0') + ui.write('\0') def base(ui, repo, node1, node2): """Output common ancestor information""" node1 = repo.lookup(node1) node2 = repo.lookup(node2) n = repo.changelog.ancestor(node1, node2) - print hg.short(n) + ui.write(hg.short(n) + "\n") def catfile(ui, repo, type=None, r=None, **opts): """cat a specific revision""" @@ -158,10 +155,10 @@ while r: if type != "commit": - sys.stderr.write("aborting hg cat-file only understands commits\n") - sys.exit(1); + ui.warn("aborting hg cat-file only understands commits\n") + return 1; n = repo.lookup(r) - catcommit(repo, n, prefix) + catcommit(ui, repo, n, prefix) if opts['stdin']: try: (type, r) = raw_input().split(' '); @@ -175,7 +172,7 @@ # telling you which commits are reachable from the supplied ones via # a bitmask based on arg position. # you can specify a commit to stop at by starting the sha1 with ^ -def revtree(args, repo, full="tree", maxnr=0, parents=False): +def revtree(ui, args, repo, full="tree", maxnr=0, parents=False): def chlogwalk(): count = repo.changelog.count() i = count @@ -260,24 +257,24 @@ if pp[1] != hg.nullid: parentstr += " " + hg.short(pp[1]) if not full: - print hg.short(n) + parentstr + ui.write("%s%s\n" % (hg.short(n), parentstr)) elif full == "commit": - print hg.short(n) + parentstr - catcommit(repo, n, ' ', ctx) + ui.write("%s%s\n" % (hg.short(n), parentstr)) + catcommit(ui, repo, n, ' ', ctx) else: (p1, p2) = repo.changelog.parents(n) (h, h1, h2) = map(hg.short, (n, p1, p2)) (i1, i2) = map(repo.changelog.rev, (p1, p2)) date = ctx.date()[0] - print "%s %s:%s" % (date, h, mask), + ui.write("%s %s:%s" % (date, h, mask)) mask = is_reachable(want_sha1, reachable, p1) if i1 != hg.nullrev and mask > 0: - print "%s:%s " % (h1, mask), + ui.write("%s:%s " % (h1, mask)), mask = is_reachable(want_sha1, reachable, p2) if i2 != hg.nullrev and mask > 0: - print "%s:%s " % (h2, mask), - print "" + ui.write("%s:%s " % (h2, mask)) + ui.write("\n") if maxnr and count >= maxnr: break count += 1 @@ -305,7 +302,7 @@ else: full = None copy = [x for x in revs] - revtree(copy, repo, full, opts['max_count'], opts['parents']) + revtree(ui, copy, repo, full, opts['max_count'], opts['parents']) def config(ui, repo, **opts): """print extension options""" diff -r 528c986f0162 -r 597d8402087d hgext/keyword.py --- a/hgext/keyword.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/keyword.py Fri Jan 25 16:04:46 2008 -0800 @@ -69,12 +69,16 @@ To force expansion after enabling it, or a configuration change, run "hg kwexpand". +Also, when committing with the record extension or using mq's qrecord, be aware +that keywords cannot be updated. Again, run "hg kwexpand" on the files in +question to update keyword expansions after all changes have been checked in. + Expansions spanning more than one line and incremental expansions, like CVS' $Log$, are not supported. A keyword template map "Log = {desc}" expands to the first line of the changeset description. ''' -from mercurial import commands, cmdutil, context, fancyopts, filelog +from mercurial import commands, cmdutil, context, dispatch, filelog from mercurial import patch, localrepo, revlog, templater, util from mercurial.node import * from mercurial.i18n import _ @@ -86,6 +90,14 @@ '''Returns hgdate in cvs-like UTC format.''' return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) +def _kwrestrict(cmd): + '''Returns True if cmd should trigger restricted expansion. + Keywords will only expanded when writing to working dir. + Crucial for mq as expanded keywords should not make it into patches.''' + return cmd in ('diff1', 'record', + 'qfold', 'qimport', 'qnew', 'qpush', 'qrefresh', 'qrecord') + + _kwtemplater = None class kwtemplater(object): @@ -103,10 +115,11 @@ 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', } - def __init__(self, ui, repo, inc, exc): + def __init__(self, ui, repo, inc, exc, hgcmd): self.ui = ui self.repo = repo self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] + self.hgcmd = hgcmd self.commitnode = None self.path = '' @@ -144,7 +157,7 @@ def expand(self, node, data): '''Returns data with keywords expanded.''' - if util.binary(data): + if util.binary(data) or _kwrestrict(self.hgcmd): return data return self.substitute(node, data, self.re_kw.sub) @@ -230,7 +243,7 @@ mf = ctx.manifest() if node is not None: # commit _kwtemplater.commitnode = node - files = [f for f in ctx.files() if mf.has_key(f)] + files = [f for f in ctx.files() if f in mf] notify = ui.debug else: # kwexpand/kwshrink notify = ui.note @@ -297,7 +310,7 @@ kwmaps = kwtemplater.templates if ui.configitems('keywordmaps'): # override maps from optional rcfile - for k, v in kwmaps.items(): + for k, v in kwmaps.iteritems(): ui.setconfig('keywordmaps', k, v) elif args: # simulate hgrc parsing @@ -316,7 +329,7 @@ demostatus('config using %s keyword template maps' % kwstatus) ui.write('[extensions]\n%s\n' % extension) demoitems('keyword', ui.configitems('keyword')) - demoitems('keywordmaps', kwmaps.items()) + demoitems('keywordmaps', kwmaps.iteritems()) keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n' repo.wopener(fn, 'w').write(keywords) repo.add([fn]) @@ -395,22 +408,27 @@ This is done for local repos only, and only if there are files configured at all for keyword substitution.''' - def kwbailout(): - '''Obtains command via simplified cmdline parsing, - returns True if keyword expansion not needed.''' - nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', - 'export', 'grep', 'identify', 'incoming', 'init', - 'log', 'outgoing', 'push', 'remove', 'rename', - 'rollback', 'tip', - 'convert') - args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {}) - if args: - aliases, i = cmdutil.findcmd(ui, args[0], commands.table) - return aliases[0] in nokwcommands + if not repo.local(): + return - if not repo.local() or kwbailout(): + nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', + 'export', 'grep', 'identify', 'incoming', 'init', + 'log', 'outgoing', 'push', 'remove', 'rename', + 'rollback', 'tip', + 'convert') + hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:]) + if hgcmd in nokwcommands: return + if hgcmd == 'diff': + # only expand if comparing against working dir + node1, node2 = cmdutil.revpair(repo, cmdopts.get('rev')) + if node2 is not None: + return + # shrink if rev is not current node + if node1 is not None and node1 != repo.changectx().node(): + hgcmd = 'diff1' + inc, exc = [], ['.hgtags'] for pat, opt in ui.configitems('keyword'): if opt != 'ignore': @@ -421,7 +439,7 @@ return global _kwtemplater - _kwtemplater = kwtemplater(ui, repo, inc, exc) + _kwtemplater = kwtemplater(ui, repo, inc, exc, hgcmd) class kwrepo(repo.__class__): def file(self, f, kwmatch=False): @@ -431,6 +449,12 @@ return kwfilelog(self.sopener, f) return filelog.filelog(self.sopener, f) + def wread(self, filename): + data = super(kwrepo, self).wread(filename) + if _kwrestrict(hgcmd) and _kwtemplater.matcher(filename): + return _kwtemplater.shrink(data) + return data + def commit(self, files=None, text='', user=None, date=None, match=util.always, force=False, force_editor=False, p1=None, p2=None, extra={}): @@ -440,10 +464,10 @@ wlock = self.wlock() lock = self.lock() # store and postpone commit hooks - commithooks = [] + commithooks = {} for name, cmd in ui.configitems('hooks'): if name.split('.', 1)[0] == 'commit': - commithooks.append((name, cmd)) + commithooks[name] = cmd ui.setconfig('hooks', name, None) if commithooks: # store parents for commit hook environment @@ -464,7 +488,7 @@ p1=p1, p2=p2, extra=extra) # restore commit hooks - for name, cmd in commithooks: + for name, cmd in commithooks.iteritems(): ui.setconfig('hooks', name, cmd) if node is not None: _overwrite(ui, self, node=node) diff -r 528c986f0162 -r 597d8402087d hgext/mq.py --- a/hgext/mq.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/mq.py Fri Jan 25 16:04:46 2008 -0800 @@ -224,7 +224,7 @@ def write_list(items, path): fp = self.opener(path, 'w') for i in items: - print >> fp, i + fp.write("%s\n" % i) fp.close() if self.applied_dirty: write_list(map(str, self.applied), self.status_path) if self.series_dirty: write_list(self.full_series, self.series_path) @@ -1267,7 +1267,7 @@ self.ui.warn("saved queue repository parents: %s %s\n" % (hg.short(qpp[0]), hg.short(qpp[1]))) if qupdate: - print "queue directory updating" + self.ui.status(_("queue directory updating\n")) r = self.qrepo() if not r: self.ui.warn("Unable to load queue repository\n") diff -r 528c986f0162 -r 597d8402087d hgext/patchbomb.py --- a/hgext/patchbomb.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/patchbomb.py Fri Jan 25 16:04:46 2008 -0800 @@ -417,8 +417,7 @@ fp.close() elif opts.get('mbox'): ui.status('Writing ', m['Subject'], ' ...\n') - fp = open(opts.get('mbox'), - m.has_key('In-Reply-To') and 'ab+' or 'wb+') + fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+') date = util.datestr(date=start_time, format='%a %b %d %H:%M:%S %Y', timezone=False) fp.write('From %s %s\n' % (sender_addr, date)) diff -r 528c986f0162 -r 597d8402087d hgext/record.py --- a/hgext/record.py Fri Jan 25 16:04:32 2008 -0800 +++ b/hgext/record.py Fri Jan 25 16:04:46 2008 -0800 @@ -364,10 +364,10 @@ dorecord(ui, repo, record_committer, *pats, **opts) -def qrecord(ui, repo, *pats, **opts): - '''interactively select changes for qrefresh +def qrecord(ui, repo, patch, *pats, **opts): + '''interactively record a new patch - see 'hg help record' for more information and usage + see 'hg help qnew' & 'hg help record' for more information and usage ''' try: @@ -376,8 +376,10 @@ raise util.Abort(_("'mq' extension not loaded")) def qrecord_committer(ui, repo, pats, opts): - mq.refresh(ui, repo, *pats, **opts) + mq.new(ui, repo, patch, *pats, **opts) + opts = opts.copy() + opts['force'] = True # always 'qnew -f' dorecord(ui, repo, qrecord_committer, *pats, **opts) @@ -513,10 +515,10 @@ "qrecord": (qrecord, - # add qrefresh options - mq.cmdtable['^qrefresh'][1], + # add qnew options, except '--force' + [opt for opt in mq.cmdtable['qnew'][1] if opt[1] != 'force'], - _('hg qrecord [OPTION]... [FILE]...')), + _('hg qrecord [OPTION]... PATCH [FILE]...')), } cmdtable.update(qcmdtable) diff -r 528c986f0162 -r 597d8402087d mercurial/byterange.py --- a/mercurial/byterange.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/byterange.py Fri Jan 25 16:04:46 2008 -0800 @@ -233,7 +233,7 @@ size = (lb - fb) fo = RangeableFileObject(fo, (fb, lb)) headers = mimetools.Message(StringIO( - 'Content-Type: %s\nContent-Length: %d\nLast-modified: %s\n' % + 'Content-Type: %s\nContent-Length: %d\nLast-Modified: %s\n' % (mtype or 'text/plain', size, modified))) return urllib.addinfourl(fo, headers, 'file:'+file) diff -r 528c986f0162 -r 597d8402087d mercurial/changegroup.py --- a/mercurial/changegroup.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/changegroup.py Fri Jan 25 16:04:46 2008 -0800 @@ -80,9 +80,13 @@ # in case of sshrepo because we don't know the end of the stream # an empty chunkiter is the end of the changegroup + # a changegroup has at least 2 chunkiters (changelog and manifest). + # after that, an empty chunkiter is the end of the changegroup empty = False - while not empty: + count = 0 + while not empty or count <= 2: empty = True + count += 1 for chunk in chunkiter(cg): empty = False fh.write(z.compress(chunkheader(len(chunk)))) diff -r 528c986f0162 -r 597d8402087d mercurial/cmdutil.py --- a/mercurial/cmdutil.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/cmdutil.py Fri Jan 25 16:04:46 2008 -0800 @@ -50,7 +50,7 @@ """Return (aliases, command table entry) for command string.""" choice = findpossible(ui, cmd, table) - if choice.has_key(cmd): + if cmd in choice: return choice[cmd] if len(choice) > 1: diff -r 528c986f0162 -r 597d8402087d mercurial/commands.py --- a/mercurial/commands.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/commands.py Fri Jan 25 16:04:46 2008 -0800 @@ -1528,12 +1528,13 @@ files=files) finally: files = patch.updatedir(ui, repo, files) - n = repo.commit(files, message, user, date) - if opts.get('exact'): - if hex(n) != nodeid: - repo.rollback() - raise util.Abort(_('patch is damaged' - ' or loses information')) + if not opts.get('no_commit'): + n = repo.commit(files, message, user, date) + if opts.get('exact'): + if hex(n) != nodeid: + repo.rollback() + raise util.Abort(_('patch is damaged' + ' or loses information')) finally: os.unlink(tmpname) finally: @@ -2896,6 +2897,7 @@ ('b', 'base', '', _('base path')), ('f', 'force', None, _('skip check for outstanding uncommitted changes')), + ('', 'no-commit', None, _("don't commit, just update the working directory")), ('', 'exact', None, _('apply patch to the nodes from which it was generated')), ('', 'import-branch', None, diff -r 528c986f0162 -r 597d8402087d mercurial/demandimport.py --- a/mercurial/demandimport.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/demandimport.py Fri Jan 25 16:04:46 2008 -0800 @@ -77,7 +77,7 @@ self._load() setattr(self._module, attr, val) -def _demandimport(name, globals=None, locals=None, fromlist=None): +def _demandimport(name, globals=None, locals=None, fromlist=None, level=None): if not locals or name in ignore or fromlist == ('*',): # these cases we can't really delay return _origimport(name, globals, locals, fromlist) @@ -95,6 +95,9 @@ return locals[base] return _demandmod(name, globals, locals) else: + if level is not None: + # from . import b,c,d or from .a import b,c,d + return _origimport(name, globals, locals, fromlist, level) # from a import b,c,d mod = _origimport(name, globals, locals) # recurse down the module chain diff -r 528c986f0162 -r 597d8402087d mercurial/dirstate.py --- a/mercurial/dirstate.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/dirstate.py Fri Jan 25 16:04:46 2008 -0800 @@ -235,7 +235,7 @@ self._changepath(f, 'n', True) s = os.lstat(self._join(f)) self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0) - if self._copymap.has_key(f): + if f in self._copymap: del self._copymap[f] def normallookup(self, f): diff -r 528c986f0162 -r 597d8402087d mercurial/dispatch.py --- a/mercurial/dispatch.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/dispatch.py Fri Jan 25 16:04:46 2008 -0800 @@ -354,12 +354,12 @@ d = lambda: func(ui, *args, **cmdoptions) # run pre-hook, and abort if it fails - ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs)) + ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs)) if ret: return ret ret = _runcommand(ui, options, cmd, d) # run post-hook, passing command result - hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs), + hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs), result = ret) return ret diff -r 528c986f0162 -r 597d8402087d mercurial/fancyopts.py --- a/mercurial/fancyopts.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/fancyopts.py Fri Jan 25 16:04:46 2008 -0800 @@ -38,7 +38,6 @@ if isinstance(default, list): state[name] = default[:] elif callable(default): - print "whoa", name, default state[name] = None else: state[name] = default diff -r 528c986f0162 -r 597d8402087d mercurial/filelog.py --- a/mercurial/filelog.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/filelog.py Fri Jan 25 16:04:46 2008 -0800 @@ -58,7 +58,7 @@ if self.parents(node)[0] != nullid: return False m = self._readmeta(node) - if m and m.has_key("copy"): + if m and "copy" in m: return (m["copy"], bin(m["copyrev"])) return False diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/common.py Fri Jan 25 16:04:46 2008 -0800 @@ -36,11 +36,11 @@ return os.stat(store_path).st_mtime def staticfile(directory, fname, req): - """return a file inside directory with guessed content-type header + """return a file inside directory with guessed Content-Type header fname always uses '/' as directory separator and isn't allowed to contain unusual path components. - Content-type is guessed using the mimetypes module. + Content-Type is guessed using the mimetypes module. Return an empty string if fname is illegal or file not found. """ @@ -54,8 +54,10 @@ try: os.stat(path) ct = mimetypes.guess_type(path)[0] or "text/plain" - req.header([('Content-type', ct), - ('Content-length', str(os.path.getsize(path)))]) + req.header([ + ('Content-Type', ct), + ('Content-Length', str(os.path.getsize(path))) + ]) return file(path, 'rb').read() except TypeError: raise ErrorResponse(500, 'illegal file name') diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/hgweb_mod.py Fri Jan 25 16:04:46 2008 -0800 @@ -6,7 +6,7 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os, mimetypes, re, mimetools, cStringIO +import os, mimetypes, re from mercurial.node import * from mercurial import mdiff, ui, hg, util, archival, patch, hook from mercurial import revlog, templater @@ -153,7 +153,7 @@ req.url = req.env['SCRIPT_NAME'] if not req.url.endswith('/'): req.url += '/' - if req.env.has_key('REPO_NAME'): + if 'REPO_NAME' in req.env: req.url += req.env['REPO_NAME'] + '/' if req.env.get('PATH_INFO'): @@ -206,12 +206,17 @@ method = getattr(protocol, cmd) method(self, req) else: + tmpl = self.templater(req) if cmd == '': req.form['cmd'] = [tmpl.cache['default']] cmd = req.form['cmd'][0] - method = getattr(webcommands, cmd) - method(self, req, tmpl) + + if cmd == 'file' and 'raw' in req.form.get('style', []): + webcommands.rawfile(self, req, tmpl) + else: + getattr(webcommands, cmd)(self, req, tmpl) + del tmpl except revlog.LookupError, err: @@ -248,17 +253,9 @@ # some functions for the templater def header(**map): - header_file = cStringIO.StringIO( - ''.join(tmpl("header", encoding=self.encoding, **map))) - msg = mimetools.Message(header_file, 0) - req.header(msg.items()) - yield header_file.read() - - def rawfileheader(**map): - req.header([('Content-type', map['mimetype']), - ('Content-disposition', 'filename=%s' % map['file']), - ('Content-length', str(len(map['raw'])))]) - yield '' + ctype = tmpl('mimetype', encoding=self.encoding) + req.httphdr(templater.stringify(ctype)) + yield tmpl('header', encoding=self.encoding, **map) def footer(**map): yield tmpl("footer", **map) @@ -268,7 +265,7 @@ def sessionvars(**map): fields = [] - if req.form.has_key('style'): + if 'style' in req.form: style = req.form['style'][0] if style != self.config('web', 'style', ''): fields.append(('style', style)) @@ -281,7 +278,7 @@ # figure out which style to use style = self.config("web", "style", "") - if req.form.has_key('style'): + if 'style' in req.form: style = req.form['style'][0] mapfile = style_map(self.templatepath, style) @@ -300,7 +297,6 @@ "header": header, "footer": footer, "motd": motd, - "rawfileheader": rawfileheader, "sessionvars": sessionvars }) return tmpl @@ -446,13 +442,13 @@ changenav = revnavgen(pos, maxchanges, count, self.repo.changectx) - yield tmpl(shortlog and 'shortlog' or 'changelog', - changenav=changenav, - node=hex(cl.tip()), - rev=pos, changesets=count, - entries=lambda **x: changelist(limit=0,**x), - latestentry=lambda **x: changelist(limit=1,**x), - archives=self.archivelist("tip")) + return tmpl(shortlog and 'shortlog' or 'changelog', + changenav=changenav, + node=hex(cl.tip()), + rev=pos, changesets=count, + entries=lambda **x: changelist(limit=0,**x), + latestentry=lambda **x: changelist(limit=1,**x), + archives=self.archivelist("tip")) def search(self, tmpl, query): @@ -505,11 +501,11 @@ cl = self.repo.changelog parity = paritygen(self.stripecount) - yield tmpl('search', - query=query, - node=hex(cl.tip()), - entries=changelist, - archives=self.archivelist("tip")) + return tmpl('search', + query=query, + node=hex(cl.tip()), + entries=changelist, + archives=self.archivelist("tip")) def changeset(self, tmpl, ctx): n = ctx.node() @@ -526,20 +522,20 @@ def diff(**map): yield self.diff(tmpl, p1, n, None) - yield tmpl('changeset', - diff=diff, - rev=ctx.rev(), - node=hex(n), - parent=self.siblings(parents), - child=self.siblings(ctx.children()), - changesettag=self.showtag("changesettag",n), - author=ctx.user(), - desc=ctx.description(), - date=ctx.date(), - files=files, - archives=self.archivelist(hex(n)), - tags=self.nodetagsdict(n), - branches=self.nodebranchdict(ctx)) + return tmpl('changeset', + diff=diff, + rev=ctx.rev(), + node=hex(n), + parent=self.siblings(parents), + child=self.siblings(ctx.children()), + changesettag=self.showtag("changesettag",n), + author=ctx.user(), + desc=ctx.description(), + date=ctx.date(), + files=files, + archives=self.archivelist(hex(n)), + tags=self.nodetagsdict(n), + branches=self.nodebranchdict(ctx)) def filelog(self, tmpl, fctx): f = fctx.path() @@ -578,9 +574,9 @@ nodefunc = lambda x: fctx.filectx(fileid=x) nav = revnavgen(pos, pagelen, count, nodefunc) - yield tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav, - entries=lambda **x: entries(limit=0, **x), - latestentry=lambda **x: entries(limit=1, **x)) + return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav, + entries=lambda **x: entries(limit=0, **x), + latestentry=lambda **x: entries(limit=1, **x)) def filerevision(self, tmpl, fctx): f = fctx.path() @@ -602,21 +598,21 @@ "linenumber": "% 6d" % (l + 1), "parity": parity.next()} - yield tmpl("filerevision", - file=f, - path=_up(f), - text=lines(), - raw=rawtext, - mimetype=mt, - rev=fctx.rev(), - node=hex(fctx.node()), - author=fctx.user(), - date=fctx.date(), - desc=fctx.description(), - parent=self.siblings(fctx.parents()), - child=self.siblings(fctx.children()), - rename=self.renamelink(fl, n), - permissions=fctx.manifest().flags(f)) + return tmpl("filerevision", + file=f, + path=_up(f), + text=lines(), + raw=rawtext, + mimetype=mt, + rev=fctx.rev(), + node=hex(fctx.node()), + author=fctx.user(), + date=fctx.date(), + desc=fctx.description(), + parent=self.siblings(fctx.parents()), + child=self.siblings(fctx.children()), + rename=self.renamelink(fl, n), + permissions=fctx.manifest().flags(f)) def fileannotate(self, tmpl, fctx): f = fctx.path() @@ -640,19 +636,19 @@ "file": f.path(), "line": l} - yield tmpl("fileannotate", - file=f, - annotate=annotate, - path=_up(f), - rev=fctx.rev(), - node=hex(fctx.node()), - author=fctx.user(), - date=fctx.date(), - desc=fctx.description(), - rename=self.renamelink(fl, n), - parent=self.siblings(fctx.parents()), - child=self.siblings(fctx.children()), - permissions=fctx.manifest().flags(f)) + return tmpl("fileannotate", + file=f, + annotate=annotate, + path=_up(f), + rev=fctx.rev(), + node=hex(fctx.node()), + author=fctx.user(), + date=fctx.date(), + desc=fctx.description(), + rename=self.renamelink(fl, n), + parent=self.siblings(fctx.parents()), + child=self.siblings(fctx.children()), + permissions=fctx.manifest().flags(f)) def manifest(self, tmpl, ctx, path): mf = ctx.manifest() @@ -708,17 +704,17 @@ "path": "%s%s" % (abspath, f), "basename": f[:-1]} - yield tmpl("manifest", - rev=ctx.rev(), - node=hex(node), - path=abspath, - up=_up(abspath), - upparity=parity.next(), - fentries=filelist, - dentries=dirlist, - archives=self.archivelist(hex(node)), - tags=self.nodetagsdict(node), - branches=self.nodebranchdict(ctx)) + return tmpl("manifest", + rev=ctx.rev(), + node=hex(node), + path=abspath, + up=_up(abspath), + upparity=parity.next(), + fentries=filelist, + dentries=dirlist, + archives=self.archivelist(hex(node)), + tags=self.nodetagsdict(node), + branches=self.nodebranchdict(ctx)) def tags(self, tmpl): i = self.repo.tagslist() @@ -738,11 +734,11 @@ "date": self.repo.changectx(n).date(), "node": hex(n)} - yield tmpl("tags", - node=hex(self.repo.changelog.tip()), - entries=lambda **x: entries(False,0, **x), - entriesnotip=lambda **x: entries(True,0, **x), - latestentry=lambda **x: entries(True,1, **x)) + return tmpl("tags", + node=hex(self.repo.changelog.tip()), + entries=lambda **x: entries(False,0, **x), + entriesnotip=lambda **x: entries(True,0, **x), + latestentry=lambda **x: entries(True,1, **x)) def summary(self, tmpl): i = self.repo.tagslist() @@ -807,15 +803,15 @@ start = max(0, count - self.maxchanges) end = min(count, start + self.maxchanges) - yield tmpl("summary", - desc=self.config("web", "description", "unknown"), - owner=get_contact(self.config) or "unknown", - lastchange=cl.read(cl.tip())[2], - tags=tagentries, - branches=branches, - shortlog=changelist, - node=hex(cl.tip()), - archives=self.archivelist("tip")) + return tmpl("summary", + desc=self.config("web", "description", "unknown"), + owner=get_contact(self.config) or "unknown", + lastchange=cl.read(cl.tip())[2], + tags=tagentries, + branches=branches, + shortlog=changelist, + node=hex(cl.tip()), + archives=self.archivelist("tip")) def filediff(self, tmpl, fctx): n = fctx.node() @@ -826,13 +822,13 @@ def diff(**map): yield self.diff(tmpl, p1, n, [path]) - yield tmpl("filediff", - file=path, - node=hex(n), - rev=fctx.rev(), - parent=self.siblings(parents), - child=self.siblings(fctx.children()), - diff=diff) + return tmpl("filediff", + file=path, + node=hex(n), + rev=fctx.rev(), + parent=self.siblings(parents), + child=self.siblings(fctx.children()), + diff=diff) archive_specs = { 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None), @@ -848,13 +844,15 @@ arch_version = short(cnode) name = "%s-%s" % (reponame, arch_version) mimetype, artype, extension, encoding = self.archive_specs[type_] - headers = [('Content-type', mimetype), - ('Content-disposition', 'attachment; filename=%s%s' % - (name, extension))] + headers = [ + ('Content-Type', mimetype), + ('Content-Disposition', 'attachment; filename=%s%s' % + (name, extension)) + ] if encoding: - headers.append(('Content-encoding', encoding)) + headers.append(('Content-Encoding', encoding)) req.header(headers) - archival.archive(self.repo, req.out, cnode, artype, prefix=name) + archival.archive(self.repo, req, cnode, artype, prefix=name) # add tags to things # tags -> list of changesets corresponding to tags @@ -865,9 +863,9 @@ return util.canonpath(self.repo.root, '', path) def changectx(self, req): - if req.form.has_key('node'): + if 'node' in req.form: changeid = req.form['node'][0] - elif req.form.has_key('manifest'): + elif 'manifest' in req.form: changeid = req.form['manifest'][0] else: changeid = self.repo.changelog.count() - 1 @@ -883,7 +881,7 @@ def filectx(self, req): path = self.cleanpath(req.form['file'][0]) - if req.form.has_key('node'): + if 'node' in req.form: changeid = req.form['node'][0] else: changeid = req.form['filenode'][0] diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/hgwebdir_mod.py Fri Jan 25 16:04:46 2008 -0800 @@ -6,7 +6,7 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os, mimetools, cStringIO +import os from mercurial.i18n import gettext as _ from mercurial import ui, hg, util, templater from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen, \ @@ -143,7 +143,7 @@ def entries(sortcolumn="", descending=False, subdir="", **map): def sessionvars(**map): fields = [] - if req.form.has_key('style'): + if 'style' in req.form: style = req.form['style'][0] if style != get('web', 'style', ''): fields.append(('style', style)) @@ -214,7 +214,7 @@ sortable = ["name", "description", "contact", "lastchange"] sortcolumn, descending = self.repos_sorted - if req.form.has_key('sort'): + if 'sort' in req.form: sortcolumn = req.form['sort'][0] descending = sortcolumn.startswith('-') if descending: @@ -226,6 +226,7 @@ "%s%s" % ((not descending and column == sortcolumn) and "-" or "", column)) for column in sortable] + req.write(tmpl("index", entries=entries, subdir=subdir, sortcolumn=sortcolumn, descending=descending, **dict(sort))) @@ -233,11 +234,9 @@ def templater(self, req): def header(**map): - header_file = cStringIO.StringIO( - ''.join(tmpl("header", encoding=util._encoding, **map))) - msg = mimetools.Message(header_file, 0) - req.header(msg.items()) - yield header_file.read() + ctype = tmpl('mimetype', encoding=util._encoding) + req.httphdr(templater.stringify(ctype)) + yield tmpl('header', encoding=util._encoding, **map) def footer(**map): yield tmpl("footer", **map) @@ -262,7 +261,7 @@ style = self.style if style is None: style = config('web', 'style', '') - if req.form.has_key('style'): + if 'style' in req.form: style = req.form['style'][0] if self.stripecount is None: self.stripecount = int(config('web', 'stripes', 1)) diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/protocol.py Fri Jan 25 16:04:46 2008 -0800 @@ -28,7 +28,7 @@ def branches(web, req): nodes = [] - if req.form.has_key('nodes'): + if 'nodes' in req.form: nodes = map(bin, req.form['nodes'][0].split(" ")) resp = cStringIO.StringIO() for b in web.repo.branches(nodes): @@ -38,7 +38,7 @@ req.write(resp) def between(web, req): - if req.form.has_key('pairs'): + if 'pairs' in req.form: pairs = [map(bin, p.split("-")) for p in req.form['pairs'][0].split(" ")] resp = cStringIO.StringIO() @@ -54,7 +54,7 @@ if not web.allowpull: return - if req.form.has_key('roots'): + if 'roots' in req.form: nodes = map(bin, req.form['roots'][0].split(" ")) z = zlib.compressobj() @@ -74,9 +74,9 @@ if not web.allowpull: return - if req.form.has_key('bases'): + if 'bases' in req.form: bases = [bin(x) for x in req.form['bases'][0].split(' ')] - if req.form.has_key('heads'): + if 'heads' in req.form: heads = [bin(x) for x in req.form['heads'][0].split(' ')] z = zlib.compressobj() diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/request.py Fri Jan 25 16:04:46 2008 -0800 @@ -24,35 +24,43 @@ self.run_once = wsgienv['wsgi.run_once'] self.env = wsgienv self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) - self.start_response = start_response + self._start_response = start_response self.headers = [] - out = property(lambda self: self) - def __iter__(self): return iter([]) def read(self, count=-1): return self.inp.read(count) + def start_response(self, status): + if self._start_response is not None: + if not self.headers: + raise RuntimeError("request.write called before headers sent") + + for k, v in self.headers: + if not isinstance(v, str): + raise TypeError('header value must be string: %r' % v) + + if isinstance(status, ErrorResponse): + status = statusmessage(status.code) + elif isinstance(status, int): + status = statusmessage(status) + + self.server_write = self._start_response(status, self.headers) + self._start_response = None + self.headers = [] + def respond(self, status, *things): + if not things: + self.start_response(status) for thing in things: if hasattr(thing, "__iter__"): for part in thing: self.respond(status, part) else: thing = str(thing) - if self.server_write is None: - if not self.headers: - raise RuntimeError("request.write called before headers sent (%s)." % thing) - if isinstance(status, ErrorResponse): - status = statusmessage(status.code) - elif isinstance(status, int): - status = statusmessage(status) - self.server_write = self.start_response(status, - self.headers) - self.start_response = None - self.headers = [] + self.start_response(status) try: self.server_write(thing) except socket.error, inst: @@ -72,21 +80,23 @@ def close(self): return None - def header(self, headers=[('Content-type','text/html')]): + def header(self, headers=[('Content-Type','text/html')]): self.headers.extend(headers) def httphdr(self, type, filename=None, length=0, headers={}): headers = headers.items() - headers.append(('Content-type', type)) + headers.append(('Content-Type', type)) if filename: - headers.append(('Content-disposition', 'attachment; filename=%s' % + headers.append(('Content-Disposition', 'inline; filename=%s' % filename)) if length: - headers.append(('Content-length', str(length))) + headers.append(('Content-Length', str(length))) self.header(headers) def wsgiapplication(app_maker): + '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir() + can and should now be used as a WSGI application.''' application = app_maker() def run_wsgi(env, respond): - application(env, respond) + return application(env, respond) return run_wsgi diff -r 528c986f0162 -r 597d8402087d mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hgweb/webcommands.py Fri Jan 25 16:04:46 2008 -0800 @@ -5,16 +5,37 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os -from mercurial import revlog -from common import staticfile +import os, mimetypes +from mercurial import revlog, util +from common import staticfile, ErrorResponse def log(web, req, tmpl): - if req.form.has_key('file') and req.form['file'][0]: + if 'file' in req.form and req.form['file'][0]: filelog(web, req, tmpl) else: changelog(web, req, tmpl) +def rawfile(web, req, tmpl): + path = web.cleanpath(req.form.get('file', [''])[0]) + if not path: + req.write(web.manifest(tmpl, web.changectx(req), path)) + return + + try: + fctx = web.filectx(req) + except revlog.LookupError: + req.write(web.manifest(tmpl, web.changectx(req), path)) + return + + path = fctx.path() + text = fctx.data() + mt = mimetypes.guess_type(path)[0] + if mt is None or util.binary(text): + mt = mt or 'application/octet-stream' + + req.httphdr(mt, path, len(text)) + req.write(text) + def file(web, req, tmpl): path = web.cleanpath(req.form.get('file', [''])[0]) if path: @@ -27,10 +48,10 @@ req.write(web.manifest(tmpl, web.changectx(req), path)) def changelog(web, req, tmpl, shortlog = False): - if req.form.has_key('node'): + if 'node' in req.form: ctx = web.changectx(req) else: - if req.form.has_key('rev'): + if 'rev' in req.form: hi = req.form['rev'][0] else: hi = web.repo.changelog.count() - 1 @@ -79,8 +100,7 @@ web.archive(tmpl, req, req.form['node'][0], type_) return - req.respond(400, tmpl('error', - error='Unsupported archive type: %s' % type_)) + raise ErrorResponse(400, 'Unsupported archive type: %s' % type_) def static(web, req, tmpl): fname = req.form['file'][0] diff -r 528c986f0162 -r 597d8402087d mercurial/hook.py --- a/mercurial/hook.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/hook.py Fri Jan 25 16:04:46 2008 -0800 @@ -71,7 +71,11 @@ def _exthook(ui, repo, name, cmd, args, throw): ui.note(_("running hook %s: %s\n") % (name, cmd)) env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()]) - r = util.system(cmd, environ=env, cwd=repo.root) + if repo: + cwd = repo.root + else: + cwd = os.getcwd() + r = util.system(cmd, environ=env, cwd=cwd) if r: desc, r = util.explain_exit(r) if throw: diff -r 528c986f0162 -r 597d8402087d mercurial/httprepo.py --- a/mercurial/httprepo.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/httprepo.py Fri Jan 25 16:04:46 2008 -0800 @@ -247,7 +247,7 @@ # will take precedence if found, so drop them for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]: try: - if os.environ.has_key(env): + if env in os.environ: del os.environ[env] except OSError: pass @@ -343,7 +343,7 @@ version = proto.split('-', 1)[1] version_info = tuple([int(n) for n in version.split('.')]) except ValueError: - raise repo.RepoError(_("'%s' sent a broken Content-type " + raise repo.RepoError(_("'%s' sent a broken Content-Type " "header (%s)") % (self._url, proto)) if version_info > (0, 1): raise repo.RepoError(_("'%s' uses newer protocol %s") % @@ -428,7 +428,7 @@ try: rfp = self.do_cmd( 'unbundle', data=fp, - headers={'content-type': 'application/octet-stream'}, + headers={'Content-Type': 'application/octet-stream'}, heads=' '.join(map(hex, heads))) try: ret = int(rfp.readline()) diff -r 528c986f0162 -r 597d8402087d mercurial/keepalive.py --- a/mercurial/keepalive.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/keepalive.py Fri Jan 25 16:04:46 2008 -0800 @@ -129,7 +129,7 @@ def add(self, host, connection, ready): self._lock.acquire() try: - if not self._hostmap.has_key(host): self._hostmap[host] = [] + if not host in self._hostmap: self._hostmap[host] = [] self._hostmap[host].append(connection) self._connmap[connection] = host self._readymap[connection] = ready @@ -159,7 +159,7 @@ conn = None self._lock.acquire() try: - if self._hostmap.has_key(host): + if host in self._hostmap: for c in self._hostmap[host]: if self._readymap[c]: self._readymap[c] = 0 diff -r 528c986f0162 -r 597d8402087d mercurial/localrepo.py --- a/mercurial/localrepo.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/localrepo.py Fri Jan 25 16:04:46 2008 -0800 @@ -687,6 +687,8 @@ p1=None, p2=None, extra={}, empty_ok=False): wlock = lock = tr = None valid = 0 # don't save the dirstate if this isn't set + if files: + files = util.unique(files) try: commit = [] remove = [] @@ -996,7 +998,7 @@ mf2keys.sort() getnode = lambda fn: mf1.get(fn, nullid) for fn in mf2keys: - if mf1.has_key(fn): + if fn in mf1: if (mf1.flags(fn) != mf2.flags(fn) or (mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, getnode)))): @@ -1510,7 +1512,7 @@ for node in nodes: self.ui.debug("%s\n" % hex(node)) - def changegroupsubset(self, bases, heads, source): + def changegroupsubset(self, bases, heads, source, extranodes=None): """This function generates a changegroup consisting of all the nodes that are descendents of any of the bases, and ancestors of any of the heads. @@ -1520,7 +1522,15 @@ is non-trivial. Another wrinkle is doing the reverse, figuring out which changeset in - the changegroup a particular filenode or manifestnode belongs to.""" + the changegroup a particular filenode or manifestnode belongs to. + + The caller can specify some nodes that must be included in the + changegroup using the extranodes argument. It should be a dict + where the keys are the filenames (or 1 for the manifest), and the + values are lists of (node, linknode) tuples, where node is a wanted + node and linknode is the changelog node that should be transmitted as + the linkrev. + """ self.hook('preoutgoing', throw=True, source=source) @@ -1713,6 +1723,15 @@ return msngset[fnode] return lookup_filenode_link + # Add the nodes that were explicitly requested. + def add_extra_nodes(name, nodes): + if not extranodes or name not in extranodes: + return + + for node, linknode in extranodes[name]: + if node not in nodes: + nodes[node] = linknode + # Now that we have all theses utility functions to help out and # logically divide up the task, generate the group. def gengroup(): @@ -1728,6 +1747,7 @@ # The list of manifests has been collected by the generator # calling our functions back. prune_manifests() + add_extra_nodes(1, msng_mnfst_set) msng_mnfst_lst = msng_mnfst_set.keys() # Sort the manifestnodes by revision number. msng_mnfst_lst.sort(cmp_by_rev_func(mnfst)) @@ -1743,6 +1763,13 @@ msng_mnfst_lst = None msng_mnfst_set.clear() + if extranodes: + for fname in extranodes: + if isinstance(fname, int): + continue + add_extra_nodes(fname, + msng_filenode_set.setdefault(fname, {})) + changedfiles[fname] = 1 changedfiles = changedfiles.keys() changedfiles.sort() # Go through all our files in order sorted by name. @@ -1752,7 +1779,7 @@ raise util.Abort(_("empty or missing revlog for %s") % fname) # Toss out the filenodes that the recipient isn't really # missing. - if msng_filenode_set.has_key(fname): + if fname in msng_filenode_set: prune_filenodes(fname, filerevlog) msng_filenode_lst = msng_filenode_set[fname].keys() else: @@ -1771,7 +1798,7 @@ lookup_filenode_link_func(fname)) for chnk in group: yield chnk - if msng_filenode_set.has_key(fname): + if fname in msng_filenode_set: # Don't need this anymore, toss it to free memory. del msng_filenode_set[fname] # Signal that no more groups are left. @@ -1852,7 +1879,7 @@ return util.chunkbuffer(gengroup()) - def addchangegroup(self, source, srctype, url): + def addchangegroup(self, source, srctype, url, emptyok=False): """add changegroup to repo. return values: @@ -1888,7 +1915,7 @@ self.ui.status(_("adding changesets\n")) cor = cl.count() - 1 chunkiter = changegroup.chunkiter(source) - if cl.addgroup(chunkiter, csmap, trp, 1) is None: + if cl.addgroup(chunkiter, csmap, trp, 1) is None and not emptyok: raise util.Abort(_("received changelog group is empty")) cnr = cl.count() - 1 changesets = cnr - cor diff -r 528c986f0162 -r 597d8402087d mercurial/patch.py --- a/mercurial/patch.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/patch.py Fri Jan 25 16:04:46 2008 -0800 @@ -1372,7 +1372,8 @@ try: p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) try: - for line in patchlines: print >> p.tochild, line + for line in patchlines: + p.tochild.write(line + "\n") p.tochild.close() if p.wait(): return fp = os.fdopen(fd, 'r') diff -r 528c986f0162 -r 597d8402087d mercurial/repair.py --- a/mercurial/repair.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/repair.py Fri Jan 25 16:04:46 2008 -0800 @@ -6,71 +6,86 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import changegroup, revlog, os, commands +import changegroup, os +from node import * -def strip(ui, repo, rev, backup="all"): - def limitheads(chlog, stop): - """return the list of all nodes that have no children""" - p = {} - h = [] - stoprev = 0 - if stop in chlog.nodemap: - stoprev = chlog.rev(stop) +def _limitheads(cl, stoprev): + """return the list of all revs >= stoprev that have no children""" + seen = {} + heads = [] + + for r in xrange(cl.count() - 1, stoprev - 1, -1): + if r not in seen: + heads.append(r) + for p in cl.parentrevs(r): + seen[p] = 1 + return heads - for r in xrange(chlog.count() - 1, -1, -1): - n = chlog.node(r) - if n not in p: - h.append(n) - if n == stop: - break - if r < stoprev: - break - for pn in chlog.parents(n): - p[pn] = 1 - return h +def _bundle(repo, bases, heads, node, suffix, extranodes=None): + """create a bundle with the specified revisions as a backup""" + cg = repo.changegroupsubset(bases, heads, 'strip', extranodes) + backupdir = repo.join("strip-backup") + if not os.path.isdir(backupdir): + os.mkdir(backupdir) + name = os.path.join(backupdir, "%s-%s" % (short(node), suffix)) + repo.ui.warn("saving bundle to %s\n" % name) + return changegroup.writebundle(cg, name, "HG10BZ") - def bundle(repo, bases, heads, rev, suffix): - cg = repo.changegroupsubset(bases, heads, 'strip') - backupdir = repo.join("strip-backup") - if not os.path.isdir(backupdir): - os.mkdir(backupdir) - name = os.path.join(backupdir, "%s-%s" % (revlog.short(rev), suffix)) - ui.warn("saving bundle to %s\n" % name) - return changegroup.writebundle(cg, name, "HG10BZ") +def _collectfiles(repo, striprev): + """find out the filelogs affected by the strip""" + files = {} + + for x in xrange(striprev, repo.changelog.count()): + for name in repo.changectx(x).files(): + if name in files: + continue + files[name] = 1 + + files = files.keys() + files.sort() + return files - def stripall(revnum): - mm = repo.changectx(rev).manifest() - seen = {} +def _collectextranodes(repo, files, link): + """return the nodes that have to be saved before the strip""" + def collectone(revlog): + extra = [] + startrev = count = revlog.count() + # find the truncation point of the revlog + for i in xrange(0, count): + node = revlog.node(i) + lrev = revlog.linkrev(node) + if lrev >= link: + startrev = i + 1 + break + + # see if any revision after that point has a linkrev less than link + # (we have to manually save these guys) + for i in xrange(startrev, count): + node = revlog.node(i) + lrev = revlog.linkrev(node) + if lrev < link: + extra.append((node, cl.node(lrev))) - for x in xrange(revnum, repo.changelog.count()): - for f in repo.changectx(x).files(): - if f in seen: - continue - seen[f] = 1 - if f in mm: - filerev = mm[f] - else: - filerev = 0 - seen[f] = filerev - # we go in two steps here so the strip loop happens in a - # sensible order. When stripping many files, this helps keep - # our disk access patterns under control. - seen_list = seen.keys() - seen_list.sort() - for f in seen_list: - ff = repo.file(f) - filerev = seen[f] - if filerev != 0: - if filerev in ff.nodemap: - filerev = ff.rev(filerev) - else: - filerev = 0 - ff.strip(filerev, revnum) + return extra - chlog = repo.changelog + extranodes = {} + cl = repo.changelog + extra = collectone(repo.manifest) + if extra: + extranodes[1] = extra + for fname in files: + f = repo.file(fname) + extra = collectone(f) + if extra: + extranodes[fname] = extra + + return extranodes + +def strip(ui, repo, node, backup="all"): + cl = repo.changelog # TODO delete the undo files, and handle undo of merge sets - pp = chlog.parents(rev) - revnum = chlog.rev(rev) + pp = cl.parents(node) + striprev = cl.rev(node) # save is a list of all the branches we are truncating away # that we actually want to keep. changegroup will be used @@ -78,7 +93,7 @@ saveheads = [] savebases = {} - heads = limitheads(chlog, rev) + heads = [cl.node(r) for r in _limitheads(cl, striprev)] seen = {} # search through all the heads, finding those where the revision @@ -89,39 +104,48 @@ n = h while True: seen[n] = 1 - pp = chlog.parents(n) - if pp[1] != revlog.nullid: + pp = cl.parents(n) + if pp[1] != nullid: for p in pp: - if chlog.rev(p) > revnum and p not in seen: + if cl.rev(p) > striprev and p not in seen: heads.append(p) - if pp[0] == revlog.nullid: + if pp[0] == nullid: break - if chlog.rev(pp[0]) < revnum: + if cl.rev(pp[0]) < striprev: break n = pp[0] - if n == rev: + if n == node: break - r = chlog.reachable(h, rev) - if rev not in r: + r = cl.reachable(h, node) + if node not in r: saveheads.append(h) for x in r: - if chlog.rev(x) > revnum: + if cl.rev(x) > striprev: savebases[x] = 1 + files = _collectfiles(repo, striprev) + + extranodes = _collectextranodes(repo, files, striprev) + # create a changegroup for all the branches we need to keep if backup == "all": - bundle(repo, [rev], chlog.heads(), rev, 'backup') - if saveheads: - chgrpfile = bundle(repo, savebases.keys(), saveheads, rev, 'temp') - - stripall(revnum) + _bundle(repo, [node], cl.heads(), node, 'backup') + if saveheads or extranodes: + chgrpfile = _bundle(repo, savebases.keys(), saveheads, node, 'temp', + extranodes) - change = chlog.read(rev) - chlog.strip(revnum, revnum) - repo.manifest.strip(repo.manifest.rev(change[0]), revnum) - if saveheads: + cl.strip(striprev) + repo.manifest.strip(striprev) + for name in files: + f = repo.file(name) + f.strip(striprev) + + if saveheads or extranodes: ui.status("adding branch\n") - commands.unbundle(ui, repo, "file:%s" % chgrpfile, update=False) + f = open(chgrpfile, "rb") + gen = changegroup.readbundle(f, chgrpfile) + repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True) + f.close() if backup != "strip": os.unlink(chgrpfile) diff -r 528c986f0162 -r 597d8402087d mercurial/revlog.py --- a/mercurial/revlog.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/revlog.py Fri Jan 25 16:04:46 2008 -0800 @@ -1237,21 +1237,31 @@ return node - def strip(self, rev, minlink): - if self.count() == 0 or rev >= self.count(): + def strip(self, minlink): + """truncate the revlog on the first revision with a linkrev >= minlink + + This function is called when we're stripping revision minlink and + its descendants from the repository. + + We have to remove all revisions with linkrev >= minlink, because + the equivalent changelog revisions will be renumbered after the + strip. + + So we truncate the revlog on the first of these revisions, and + trust that the caller has saved the revisions that shouldn't be + removed and that it'll readd them after this truncation. + """ + if self.count() == 0: return if isinstance(self.index, lazyindex): self._loadindexmap() - # When stripping away a revision, we need to make sure it - # does not actually belong to an older changeset. - # The minlink parameter defines the oldest revision - # we're allowed to strip away. - while minlink > self.index[rev][4]: - rev += 1 - if rev >= self.count(): - return + for rev in xrange(0, self.count()): + if self.index[rev][4] >= minlink: + break + else: + return # first truncate the files on disk end = self.start(rev) diff -r 528c986f0162 -r 597d8402087d mercurial/sshrepo.py --- a/mercurial/sshrepo.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/sshrepo.py Fri Jan 25 16:04:46 2008 -0800 @@ -195,7 +195,7 @@ r = self.pipei.read(l) if r: # remote may send "unsynced changes" - self.raise_(hg.RepoError(_("push failed: %s") % r)) + self.raise_(repo.RepoError(_("push failed: %s") % r)) self.readerr() l = int(self.pipei.readline()) diff -r 528c986f0162 -r 597d8402087d mercurial/templater.py --- a/mercurial/templater.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/templater.py Fri Jan 25 16:04:46 2008 -0800 @@ -82,7 +82,7 @@ '''perform expansion. t is name of map element to expand. map is added elements to use during expansion.''' - if not self.cache.has_key(t): + if not t in self.cache: try: self.cache[t] = file(self.map[t]).read() except IOError, inst: diff -r 528c986f0162 -r 597d8402087d mercurial/ui.py --- a/mercurial/ui.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/ui.py Fri Jan 25 16:04:46 2008 -0800 @@ -204,7 +204,8 @@ pathsitems = items for n, path in pathsitems: if path and "://" not in path and not os.path.isabs(path): - cdata.set("paths", n, os.path.join(root, path)) + cdata.set("paths", n, + os.path.normpath(os.path.join(root, path))) # update verbosity/interactive/report_untrusted settings if section is None or section == 'ui': diff -r 528c986f0162 -r 597d8402087d mercurial/util.py --- a/mercurial/util.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/util.py Fri Jan 25 16:04:46 2008 -0800 @@ -15,7 +15,7 @@ from i18n import _ import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile, strutil import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil -import re, urlparse +import urlparse try: set = set diff -r 528c986f0162 -r 597d8402087d mercurial/util_win32.py --- a/mercurial/util_win32.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/util_win32.py Fri Jan 25 16:04:46 2008 -0800 @@ -147,9 +147,18 @@ self.win_strerror) def os_link(src, dst): - # NB will only succeed on NTFS try: win32file.CreateHardLink(dst, src) + # CreateHardLink sometimes succeeds on mapped drives but + # following nlinks() returns 1. Check it now and bail out. + if nlinks(src) < 2: + try: + win32file.DeleteFile(dst) + except: + pass + # Fake hardlinking error + raise WinOSError((18, 'CreateHardLink', 'The system cannot ' + 'move the file to a different disk drive')) except pywintypes.error, details: raise WinOSError(details) diff -r 528c986f0162 -r 597d8402087d mercurial/version.py --- a/mercurial/version.py Fri Jan 25 16:04:32 2008 -0800 +++ b/mercurial/version.py Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,4 @@ -# Copyright (C) 2005, 2006 by Intevation GmbH +# Copyright (C) 2005, 2006, 2008 by Intevation GmbH # Author(s): # Thomas Arendsen Hein # @@ -10,7 +10,6 @@ """ import os -import os.path import re import time import util diff -r 528c986f0162 -r 597d8402087d templates/atom/header.tmpl --- a/templates/atom/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/atom/header.tmpl Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,2 @@ -Content-type: application/atom+xml; charset={encoding} - \ No newline at end of file diff -r 528c986f0162 -r 597d8402087d templates/atom/map --- a/templates/atom/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/atom/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,5 +1,6 @@ default = 'changelog' feedupdated = '#date|rfc3339date#' +mimetype = 'application/atom+xml; charset={encoding}' header = header.tmpl changelog = changelog.tmpl changelogentry = changelogentry.tmpl diff -r 528c986f0162 -r 597d8402087d templates/gitweb/header.tmpl --- a/templates/gitweb/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/gitweb/header.tmpl Fri Jan 25 16:04:46 2008 -0800 @@ -1,5 +1,3 @@ -Content-type: text/html; charset={encoding} - diff -r 528c986f0162 -r 597d8402087d templates/gitweb/map --- a/templates/gitweb/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/gitweb/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,5 @@ default = 'summary' +mimetype = 'text/html; charset={encoding}' header = header.tmpl footer = footer.tmpl search = search.tmpl diff -r 528c986f0162 -r 597d8402087d templates/header.tmpl --- a/templates/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/header.tmpl Fri Jan 25 16:04:46 2008 -0800 @@ -1,5 +1,3 @@ -Content-type: text/html; charset={encoding} - diff -r 528c986f0162 -r 597d8402087d templates/map --- a/templates/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,5 @@ default = 'shortlog' +mimetype = 'text/html; charset={encoding}' header = header.tmpl footer = footer.tmpl search = search.tmpl diff -r 528c986f0162 -r 597d8402087d templates/old/header.tmpl --- a/templates/old/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/old/header.tmpl Fri Jan 25 16:04:46 2008 -0800 @@ -1,5 +1,3 @@ -Content-type: text/html - diff -r 528c986f0162 -r 597d8402087d templates/old/map --- a/templates/old/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/old/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,5 @@ default = 'changelog' +mimetype = 'text/html' header = header.tmpl footer = footer.tmpl search = search.tmpl diff -r 528c986f0162 -r 597d8402087d templates/raw/header.tmpl --- a/templates/raw/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -Content-type: text/plain; charset={encoding} - diff -r 528c986f0162 -r 597d8402087d templates/raw/map --- a/templates/raw/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/raw/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,5 @@ -header = header.tmpl +mimetype = 'text/plain; charset={encoding}' +header = '' footer = '' changeset = changeset.tmpl difflineplus = '#line#' @@ -8,7 +9,6 @@ changesetparent = '# Parent #node#' changesetchild = '# Child #node#' filenodelink = '' -filerevision = '#rawfileheader##raw#' fileline = '#line#' diffblock = '#lines#' filediff = filediff.tmpl diff -r 528c986f0162 -r 597d8402087d templates/rss/header.tmpl --- a/templates/rss/header.tmpl Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/rss/header.tmpl Fri Jan 25 16:04:46 2008 -0800 @@ -1,5 +1,3 @@ -Content-type: text/xml; charset={encoding} - diff -r 528c986f0162 -r 597d8402087d templates/rss/map --- a/templates/rss/map Fri Jan 25 16:04:32 2008 -0800 +++ b/templates/rss/map Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,5 @@ default = 'changelog' +mimetype = 'text/xml; charset={encoding}' header = header.tmpl changelog = changelog.tmpl changelogentry = changelogentry.tmpl diff -r 528c986f0162 -r 597d8402087d tests/coverage.py --- a/tests/coverage.py Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/coverage.py Fri Jan 25 16:04:46 2008 -0800 @@ -186,9 +186,9 @@ return 0 # If this line is excluded, or suite_spots maps this line to # another line that is exlcuded, then we're excluded. - elif self.excluded.has_key(lineno) or \ - self.suite_spots.has_key(lineno) and \ - self.excluded.has_key(self.suite_spots[lineno][1]): + elif lineno in self.excluded or \ + lineno in self.suite_spots and \ + self.suite_spots[lineno][1] in self.excluded: return 0 # Otherwise, this is an executable line. else: @@ -217,8 +217,8 @@ lastprev = self.getLastLine(prevsuite) firstelse = self.getFirstLine(suite) for l in range(lastprev+1, firstelse): - if self.suite_spots.has_key(l): - self.doSuite(None, suite, exclude=self.excluded.has_key(l)) + if l in self.suite_spots: + self.doSuite(None, suite, l in exclude=self.excluded) break else: self.doSuite(None, suite) @@ -353,9 +353,9 @@ long_opts = optmap.values() options, args = getopt.getopt(argv, short_opts, long_opts) for o, a in options: - if optmap.has_key(o): + if o in optmap: settings[optmap[o]] = 1 - elif optmap.has_key(o + ':'): + elif o + ':' in optmap: settings[optmap[o + ':']] = a elif o[2:] in long_opts: settings[o[2:]] = 1 @@ -512,14 +512,14 @@ def merge_data(self, new_data): for file_name, file_data in new_data.items(): - if self.cexecuted.has_key(file_name): + if file_name in self.cexecuted: self.merge_file_data(self.cexecuted[file_name], file_data) else: self.cexecuted[file_name] = file_data def merge_file_data(self, cache_data, new_data): for line_number in new_data.keys(): - if not cache_data.has_key(line_number): + if not line_number in cache_data: cache_data[line_number] = new_data[line_number] # canonical_filename(filename). Return a canonical filename for the @@ -527,7 +527,7 @@ # normalized case). See [GDR 2001-12-04b, 3.3]. def canonical_filename(self, filename): - if not self.canonical_filename_cache.has_key(filename): + if not filename in self.canonical_filename_cache: f = filename if os.path.isabs(f) and not os.path.exists(f): f = os.path.basename(f) @@ -550,7 +550,7 @@ # Can't do anything useful with exec'd strings, so skip them. continue f = self.canonical_filename(filename) - if not self.cexecuted.has_key(f): + if not f in self.cexecuted: self.cexecuted[f] = {} self.cexecuted[f][lineno] = 1 self.c = {} @@ -575,7 +575,7 @@ # statements that cross lines. def analyze_morf(self, morf): - if self.analysis_cache.has_key(morf): + if morf in self.analysis_cache: return self.analysis_cache[morf] filename = self.morf_filename(morf) ext = os.path.splitext(filename)[1] @@ -752,13 +752,13 @@ def analysis2(self, morf): filename, statements, excluded, line_map = self.analyze_morf(morf) self.canonicalize_filenames() - if not self.cexecuted.has_key(filename): + if not filename in self.cexecuted: self.cexecuted[filename] = {} missing = [] for line in statements: lines = line_map.get(line, [line, line]) for l in range(lines[0], lines[1]+1): - if self.cexecuted[filename].has_key(l): + if l in self.cexecuted[filename]: break else: missing.append(line) diff -r 528c986f0162 -r 597d8402087d tests/test-archive --- a/tests/test-archive Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-archive Fri Jan 25 16:04:46 2008 -0800 @@ -13,7 +13,7 @@ echo "[web]" >> .hg/hgrc echo "name = test-archive" >> .hg/hgrc echo "allow_archive = gz bz2, zip" >> .hg/hgrc -hg serve -p $HGPORT -d --pid-file=hg.pid +hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log cat hg.pid >> $DAEMON_PIDS TIP=`hg id -v | cut -f1 -d' '` @@ -69,8 +69,12 @@ echo 'rev-0.tar created' fi +echo % server errors +cat errors.log + echo '% empty repo' hg init ../empty cd ../empty hg archive ../test-empty + exit 0 diff -r 528c986f0162 -r 597d8402087d tests/test-archive.out --- a/tests/test-archive.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-archive.out Fri Jan 25 16:04:46 2008 -0800 @@ -39,5 +39,6 @@ test-TIP/baz/bletch test-TIP/foo rev-0.tar created +% server errors % empty repo abort: repository has no revisions diff -r 528c986f0162 -r 597d8402087d tests/test-convert-cvs --- a/tests/test-convert-cvs Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-convert-cvs Fri Jan 25 16:04:46 2008 -0800 @@ -71,3 +71,25 @@ cat src-hg/b/c hg -R src-filemap log --template '#rev# #desc# files: #files#\n' +echo % commit branch +cd src +cvs -q update -r1.1 b/c +cvs -q tag -b branch +cvs -q update -r branch +echo d >> b/c +cvs -q commit -mci2 . | grep '<--' |\ + sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g' +cd .. + +echo % convert again +hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g' +cat src-hg/a +cat src-hg/b/c + +echo % convert again with --filemap +hg convert --filemap filemap src src-filemap | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g' +cat src-hg/b/c +hg -R src-filemap log --template '#rev# #desc# files: #files#\n' + +echo "graphlog = " >> $HGRCPATH +hg -R src-hg glog --template '#rev# (#branches#) #desc# files: #files#\n' diff -r 528c986f0162 -r 597d8402087d tests/test-convert-cvs.out --- a/tests/test-convert-cvs.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-convert-cvs.out Fri Jan 25 16:04:46 2008 -0800 @@ -67,3 +67,43 @@ 2 update tags files: .hgtags 1 ci0 files: b/c 0 Initial revision files: b/c +% commit branch +U b/c +T a +T b/c +checking in src/b/c,v +% convert again +connecting to cvsrepo +scanning source... +sorting... +converting... +0 ci2 +a +a +c +d +% convert again with --filemap +connecting to cvsrepo +scanning source... +sorting... +converting... +0 ci2 +c +d +4 ci2 files: b/c +3 ci1 files: b/c +2 update tags files: .hgtags +1 ci0 files: b/c +0 Initial revision files: b/c +o 5 (branch) ci2 files: b/c +| +| o 4 () ci1 files: a b/c +| | +| o 3 () update tags files: .hgtags +| | +| o 2 () ci0 files: b/c +|/ +| o 1 (INITIAL) import files: +|/ +o 0 () Initial revision files: a b/c + diff -r 528c986f0162 -r 597d8402087d tests/test-convert-svn-branches --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-svn-branches Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,89 @@ +#!/bin/sh + +"$TESTDIR/hghave" svn svn-bindings || exit 80 + +fix_path() +{ + tr '\\' / +} + +echo "[extensions]" >> $HGRCPATH +echo "convert = " >> $HGRCPATH +echo "hgext.graphlog =" >> $HGRCPATH + +svnadmin create svn-repo + +svnpath=`pwd | fix_path` +# SVN wants all paths to start with a slash. Unfortunately, +# Windows ones don't. Handle that. +expr $svnpath : "\/" > /dev/null +if [ $? -ne 0 ]; then + svnpath='/'$svnpath +fi + +echo % initial svn import +mkdir projA +cd projA +mkdir trunk +mkdir branches +mkdir tags +cd .. + +svnurl=file://$svnpath/svn-repo/projA +svn import -m "init projA" projA $svnurl | fix_path + +echo % update svn repository +svn co $svnurl A | fix_path +cd A +echo hello > trunk/letter.txt +echo hey > trunk/letter2.txt +echo ho > trunk/letter3.txt +svn add trunk/letter.txt trunk/letter2.txt trunk/letter3.txt +svn ci -m hello + +echo % branch to old letters +svn copy trunk branches/old +svn rm branches/old/letter3.txt +svn ci -m "branch trunk, remove letter3" +svn up + +echo % update trunk +echo "what can I say ?" >> trunk/letter.txt +svn ci -m "change letter" + +echo % update old branch +echo "what's up ?" >> branches/old/letter2.txt +svn ci -m "change letter2" + +echo % create a cross-branch revision +svn move -m "move letter2" trunk/letter2.txt \ + branches/old/letter3.txt +echo "I am fine" >> branches/old/letter3.txt +svn ci -m "move and update letter3.txt" + +echo % update old branch again +echo "bye" >> branches/old/letter2.txt +svn ci -m "change letter2 again" + +echo % update trunk again +echo "how are you ?" >> trunk/letter.txt +svn ci -m "last change to letter" +cd .. + +echo % convert trunk and branches +hg convert --datesort $svnurl A-hg + +echo % branch again from a converted revision +cd A +svn copy -r 1 $svnurl/trunk branches/old2 +svn ci -m "branch trunk@1 into old2" +cd .. + +echo % convert again +hg convert --datesort $svnurl A-hg + +cd A-hg +hg glog --template '#rev# #desc|firstline# files: #files#\n' +hg branches | sed 's/:.*/:/' +hg tags -q +cd .. diff -r 528c986f0162 -r 597d8402087d tests/test-convert-svn-branches.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-svn-branches.out Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,101 @@ +% initial svn import +Adding projA/trunk +Adding projA/branches +Adding projA/tags + +Committed revision 1. +% update svn repository +A A/trunk +A A/branches +A A/tags +Checked out revision 1. +A trunk/letter.txt +A trunk/letter2.txt +A trunk/letter3.txt +Adding trunk/letter.txt +Adding trunk/letter2.txt +Adding trunk/letter3.txt +Transmitting file data ... +Committed revision 2. +% branch to old letters +A branches/old +D branches/old/letter3.txt +Adding branches/old +Adding branches/old/letter.txt +Adding branches/old/letter2.txt +Deleting branches/old/letter3.txt + +Committed revision 3. +At revision 3. +% update trunk +Sending trunk/letter.txt +Transmitting file data . +Committed revision 4. +% update old branch +Sending branches/old/letter2.txt +Transmitting file data . +Committed revision 5. +% create a cross-branch revision +A branches/old/letter3.txt +D trunk/letter2.txt +Adding branches/old/letter3.txt +Deleting trunk/letter2.txt +Transmitting file data . +Committed revision 6. +% update old branch again +Sending branches/old/letter2.txt +Transmitting file data . +Committed revision 7. +% update trunk again +Sending trunk/letter.txt +Transmitting file data . +Committed revision 8. +% convert trunk and branches +initializing destination A-hg repository +scanning source... +sorting... +converting... +8 init projA +7 hello +6 branch trunk, remove letter3 +5 change letter +4 change letter2 +3 move and update letter3.txt +2 move and update letter3.txt +1 change letter2 again +0 last change to letter +% branch again from a converted revision +Checked out revision 1. +A branches/old2 +Adding branches/old2 + +Committed revision 9. +% convert again +scanning source... +sorting... +converting... +0 branch trunk@1 into old2 +o 9 branch trunk@1 into old2 files: +| +| o 8 last change to letter files: letter.txt +| | +| | o 7 change letter2 again files: letter2.txt +| | | +| o | 6 move and update letter3.txt files: letter2.txt +| | | +| | o 5 move and update letter3.txt files: letter3.txt +| | | +| | o 4 change letter2 files: letter2.txt +| | | +| o | 3 change letter files: letter.txt +| | | ++---o 2 branch trunk, remove letter3 files: letter.txt letter2.txt +| | +| o 1 hello files: letter.txt letter2.txt letter3.txt +|/ +o 0 init projA files: + +old2 9: +default 8: +old 7: +tip diff -r 528c986f0162 -r 597d8402087d tests/test-convert-svn-source --- a/tests/test-convert-svn-source Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-convert-svn-source Fri Jan 25 16:04:46 2008 -0800 @@ -103,13 +103,16 @@ echo % update svn repository again cd A echo "see second letter" >> letter.txt -echo "nice to meet you" > letter2.txt -svn add letter2.txt +# Put it in a subdirectory to test duplicate file records +# from svn source (issue 714) +mkdir todo +echo "nice to meet you" > todo/letter2.txt +svn add todo svn ci -m "second letter" svn copy -m "tag v0.2" $svnurl/trunk $svnurl/tags/v0.2 -echo "blah-blah-blah" >> letter2.txt +echo "blah-blah-blah" >> todo/letter2.txt svn ci -m "work in progress" cd .. diff -r 528c986f0162 -r 597d8402087d tests/test-convert-svn-source.out --- a/tests/test-convert-svn-source.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-convert-svn-source.out Fri Jan 25 16:04:46 2008 -0800 @@ -82,14 +82,16 @@ 0 nice day updating tags % update svn repository again -A letter2.txt +A todo +A todo/letter2.txt Sending letter.txt -Adding letter2.txt +Adding todo +Adding todo/letter2.txt Transmitting file data .. Committed revision 9. Committed revision 10. -Sending letter2.txt +Sending todo/letter2.txt Transmitting file data . Committed revision 11. % test incremental conversion @@ -101,9 +103,9 @@ updating tags o 7 update tags files: .hgtags | -o 6 work in progress files: letter2.txt +o 6 work in progress files: todo/letter2.txt | -o 5 second letter files: letter.txt letter2.txt +o 5 second letter files: letter.txt todo/letter2.txt | o 4 update tags files: .hgtags | diff -r 528c986f0162 -r 597d8402087d tests/test-glog --- a/tests/test-glog Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-glog Fri Jan 25 16:04:46 2008 -0800 @@ -139,5 +139,8 @@ echo % glog hg glog +echo % file glog +hg glog 5 + echo % unused arguments -hg glog -q foo || echo failed +hg glog -q foo bar || echo failed diff -r 528c986f0162 -r 597d8402087d tests/test-glog.out --- a/tests/test-glog.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-glog.out Fri Jan 25 16:04:46 2008 -0800 @@ -307,9 +307,17 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: (0) root +% file glog +o changeset: 5:3589c3c477ab + parent: 3:02173ffbf857 + parent: 4:e2cad8233c77 + user: test + date: Thu Jan 01 00:00:05 1970 +0000 + summary: (5) expand + % unused arguments hg glog: invalid arguments -hg glog [OPTION]... +hg glog [OPTION]... [FILE] show revision history alongside an ASCII revision graph failed diff -r 528c986f0162 -r 597d8402087d tests/test-hgweb --- a/tests/test-hgweb Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-hgweb Fri Jan 25 16:04:46 2008 -0800 @@ -7,7 +7,7 @@ echo foo > da/foo echo foo > foo hg ci -Ambase -d '0 0' -hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log +hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log cat hg.pid >> $DAEMON_PIDS echo % manifest ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/?style=raw') @@ -37,3 +37,6 @@ echo % static file "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/static/style-gitweb.css' + +echo % errors +cat errors.log diff -r 528c986f0162 -r 597d8402087d tests/test-hgweb-commands --- a/tests/test-hgweb-commands Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-hgweb-commands Fri Jan 25 16:04:46 2008 -0800 @@ -27,6 +27,7 @@ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo/?style=raw' "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/annotate/1/foo/?style=raw' "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/?style=raw' +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo' | sed "s/[0-9]* years/many years/" "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/filediff/1/foo/?style=raw' echo % Overviews diff -r 528c986f0162 -r 597d8402087d tests/test-hgweb-commands.out Binary file tests/test-hgweb-commands.out has changed diff -r 528c986f0162 -r 597d8402087d tests/test-hgweb-no-request-uri.out --- a/tests/test-hgweb-no-request-uri.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-hgweb-no-request-uri.out Fri Jan 25 16:04:46 2008 -0800 @@ -7,7 +7,7 @@ ---- HEADERS 200 Script output follows ---- DATA -[('content-type', 'application/atom+xml; charset=ascii')] +[('Content-Type', 'application/atom+xml; charset=ascii')] @@ -41,7 +41,7 @@ ---- HEADERS 200 Script output follows ---- DATA -[('content-type', 'text/plain; charset=ascii')] +[('Content-Type', 'text/plain; charset=ascii')] -rw-r--r-- 4 bar @@ -52,7 +52,7 @@ ---- HEADERS 200 Script output follows ---- DATA -[('content-type', 'text/plain; charset=ascii')] +[('Content-Type', 'text/plain; charset=ascii')] /repo/ @@ -62,7 +62,7 @@ ---- HEADERS 200 Script output follows ---- DATA -[('content-type', 'text/plain; charset=ascii')] +[('Content-Type', 'text/plain; charset=ascii')] -rw-r--r-- 4 bar diff -r 528c986f0162 -r 597d8402087d tests/test-hgweb.out --- a/tests/test-hgweb.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-hgweb.out Fri Jan 25 16:04:46 2008 -0800 @@ -136,3 +136,4 @@ background-color: #aaffaa; border-color: #ccffcc #00cc33 #00cc33 #ccffcc; } +% errors diff -r 528c986f0162 -r 597d8402087d tests/test-import --- a/tests/test-import Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-import Fri Jan 25 16:04:46 2008 -0800 @@ -32,6 +32,13 @@ hg --cwd b import -mpatch ../tip.patch rm -r b +echo % import of plain diff should be ok with --no-commit +hg clone -r0 a b +hg --cwd a diff -r0:1 > tip.patch +hg --cwd b import --no-commit ../tip.patch +hg --cwd b diff --nodates +rm -r b + echo % hg -R repo import # put the clone in a subdir - having a directory named "a" # used to hide a bug. diff -r 528c986f0162 -r 597d8402087d tests/test-import.out --- a/tests/test-import.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-import.out Fri Jan 25 16:04:46 2008 -0800 @@ -31,6 +31,20 @@ 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 of plain diff should be ok with --no-commit +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 +diff -r 80971e65b431 a +--- a/a ++++ b/a +@@ -1,1 +1,2 @@ + line 1 ++line 2 % hg -R repo import requesting all changes adding changesets diff -r 528c986f0162 -r 597d8402087d tests/test-journal-exists --- a/tests/test-journal-exists Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-journal-exists Fri Jan 25 16:04:46 2008 -0800 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh hg init echo a > a diff -r 528c986f0162 -r 597d8402087d tests/test-keyword --- a/tests/test-keyword Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-keyword Fri Jan 25 16:04:46 2008 -0800 @@ -3,6 +3,7 @@ cat <> $HGRCPATH [extensions] hgext.keyword = +hgext.mq = [keyword] * = b = ignore @@ -88,9 +89,19 @@ hg -v kwexpand echo % compare changenodes in a c cat a c -echo % rollback and remove c -hg rollback -rm c + +echo % qimport +hg qimport -r tip -n mqtest.diff +echo % keywords should not be expanded in patch +cat .hg/patches/mqtest.diff +echo % qpop +hg qpop +echo % qgoto - should imply qpush +hg qgoto mqtest.diff +echo % cat +cat c +echo % qpop and move on +hg qpop echo % copy hg cp a c diff -r 528c986f0162 -r 597d8402087d tests/test-keyword.out --- a/tests/test-keyword.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-keyword.out Fri Jan 25 16:04:46 2008 -0800 @@ -36,6 +36,10 @@ To force expansion after enabling it, or a configuration change, run "hg kwexpand". +Also, when committing with the record extension or using mq's qrecord, be aware +that keywords cannot be updated. Again, run "hg kwexpand" on the files in +question to update keyword expansions after all changes have been checked in. + Expansions spanning more than one line and incremental expansions, like CVS' $Log$, are not supported. A keyword template map "Log = {desc}" expands to the first line of the changeset description. @@ -158,8 +162,31 @@ xxx $ $Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $ tests for different changenodes -% rollback and remove c -rolling back last transaction +% qimport +% keywords should not be expanded in patch +# HG changeset patch +# User User Name +# Date 1 0 +# Node ID ba4426d1938ec9673e03ab274d88c44e24618f7f +# Parent f782df5f9602483b4e51c31a12315f353bba380c +cndiff + +diff -r f782df5f9602 -r ba4426d1938e c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/c Thu Jan 01 00:00:01 1970 +0000 +@@ -0,0 +1,2 @@ ++$Id$ ++tests for different changenodes +% qpop +Patch queue now empty +% qgoto - should imply qpush +applying mqtest.diff +Now at: mqtest.diff +% cat +$Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $ +tests for different changenodes +% qpop and move on +Patch queue now empty % copy % kwfiles added a @@ -184,7 +211,7 @@ diff -r f782df5f9602 c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -0,0 +1,3 @@ -+expand $Id: c,v 0ba462c0f077 1970/01/01 00:00:01 user $ ++expand $Id$ +do not process $Id: +xxx $ % rollback @@ -266,7 +293,7 @@ added 1 changesets with 3 changes to 3 files 3 files updated, 0 files merged, 0 files removed, 0 files unresolved % incoming -comparing with test-keyword/Test-a/../Test +comparing with test-keyword/Test searching for changes changeset: 1:0729690beff6 tag: tip diff -r 528c986f0162 -r 597d8402087d tests/test-mq.out --- a/tests/test-mq.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-mq.out Fri Jan 25 16:04:46 2008 -0800 @@ -310,7 +310,6 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files -(run 'hg update' to get a working copy) Patch queue now empty applying bar Now at: bar @@ -344,7 +343,6 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files -(run 'hg update' to get a working copy) Patch queue now empty applying bar Now at: bar @@ -419,7 +417,6 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files -(run 'hg update' to get a working copy) changeset: 1:20cbbe65cff7 tag: tip user: test diff -r 528c986f0162 -r 597d8402087d tests/test-no-symlinks.out --- a/tests/test-no-symlinks.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-no-symlinks.out Fri Jan 25 16:04:46 2008 -0800 @@ -6,6 +6,7 @@ a d/b % bundle +2 changesets found pulling from ../symlinks.hg requesting all changes adding changesets diff -r 528c986f0162 -r 597d8402087d tests/test-non-interactive-wsgi.out --- a/tests/test-non-interactive-wsgi.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-non-interactive-wsgi.out Fri Jan 25 16:04:46 2008 -0800 @@ -7,6 +7,6 @@ ---- HEADERS 200 Script output follows ---- DATA -[('content-type', 'text/html; charset=ascii')] +[('Content-Type', 'text/html; charset=ascii')] ---- ERRORS diff -r 528c986f0162 -r 597d8402087d tests/test-paths --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-paths Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,11 @@ +#!/bin/sh +base=`pwd` +hg init a +hg clone a b +cd a +echo '[paths]' >> .hg/hgrc +echo 'dupe = ../b' >> .hg/hgrc +hg in dupe | sed "s!$base!!g" +cd .. +hg -R a in dupe | sed "s!$base!!g" +true diff -r 528c986f0162 -r 597d8402087d tests/test-paths.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-paths.out Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,5 @@ +0 files updated, 0 files merged, 0 files removed, 0 files unresolved +comparing with /b +no changes found +comparing with /b +no changes found diff -r 528c986f0162 -r 597d8402087d tests/test-qrecord --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-qrecord Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,100 @@ +#!/bin/sh + +echo "[ui]" >> $HGRCPATH +echo "interactive=true" >> $HGRCPATH +echo "[extensions]" >> $HGRCPATH +echo "record=" >> $HGRCPATH + +echo "% help (no mq, so no qrecord)" + +hg help qrecord + +echo "mq=" >> $HGRCPATH + +echo "% help (mq present)" + +hg help qrecord + +hg init a +cd a + +echo % base commit + +cat > 1.txt < 2.txt < dir/a.txt < 1.txt.new +sed -e 's/b/b b/' 2.txt > 2.txt.new +sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new + +mv -f 1.txt.new 1.txt +mv -f 2.txt.new 2.txt +mv -f dir/a.txt.new dir/a.txt + +echo % whole diff + +hg diff --nodates + +echo % qrecord a.patch + +hg qrecord -d '0 0' -m aaa a.patch < as commit message + -l --logfile read commit message from + -U --currentuser add "From: " to patch + -u --user add "From: " to patch + -D --currentdate add "Date: " to patch + -d --date add "Date: " to patch + +use "hg -v help qrecord" to show global options +% base commit +% changing files +% whole diff +diff -r 1057167b20ef 1.txt +--- a/1.txt ++++ b/1.txt +@@ -1,5 +1,5 @@ + 1 +-2 ++2 2 + 3 +-4 ++4 4 + 5 +diff -r 1057167b20ef 2.txt +--- a/2.txt ++++ b/2.txt +@@ -1,5 +1,5 @@ + a +-b ++b b + c + d + e +diff -r 1057167b20ef dir/a.txt +--- a/dir/a.txt ++++ b/dir/a.txt +@@ -1,4 +1,4 @@ +-hello world ++hello world! + + someone + up +% qrecord a.patch +diff --git a/1.txt b/1.txt +2 hunks, 4 lines changed +examine changes to '1.txt'? [Ynsfdaq?] @@ -1,3 +1,3 @@ + 1 +-2 ++2 2 + 3 +record this change to '1.txt'? [Ynsfdaq?] @@ -3,3 +3,3 @@ + 3 +-4 ++4 4 + 5 +record this change to '1.txt'? [Ynsfdaq?] diff --git a/2.txt b/2.txt +1 hunks, 2 lines changed +examine changes to '2.txt'? [Ynsfdaq?] @@ -1,5 +1,5 @@ + a +-b ++b b + c + d + e +record this change to '2.txt'? [Ynsfdaq?] diff --git a/dir/a.txt b/dir/a.txt +1 hunks, 2 lines changed +examine changes to 'dir/a.txt'? [Ynsfdaq?] +% after qrecord a.patch 'tip' +changeset: 1:5d1ca63427ee +tag: qtip +tag: tip +tag: a.patch +tag: qbase +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: aaa + +diff -r 1057167b20ef -r 5d1ca63427ee 1.txt +--- a/1.txt Thu Jan 01 00:00:00 1970 +0000 ++++ b/1.txt Thu Jan 01 00:00:00 1970 +0000 +@@ -1,5 +1,5 @@ + 1 +-2 ++2 2 + 3 + 4 + 5 +diff -r 1057167b20ef -r 5d1ca63427ee 2.txt +--- a/2.txt Thu Jan 01 00:00:00 1970 +0000 ++++ b/2.txt Thu Jan 01 00:00:00 1970 +0000 +@@ -1,5 +1,5 @@ + a +-b ++b b + c + d + e + + +% after qrecord a.patch 'diff' +diff -r 5d1ca63427ee 1.txt +--- a/1.txt ++++ b/1.txt +@@ -1,5 +1,5 @@ + 1 + 2 2 + 3 +-4 ++4 4 + 5 +diff -r 5d1ca63427ee dir/a.txt +--- a/dir/a.txt ++++ b/dir/a.txt +@@ -1,4 +1,4 @@ +-hello world ++hello world! + + someone + up +% qrecord b.patch +diff --git a/1.txt b/1.txt +1 hunks, 2 lines changed +examine changes to '1.txt'? [Ynsfdaq?] @@ -1,5 +1,5 @@ + 1 + 2 2 + 3 +-4 ++4 4 + 5 +record this change to '1.txt'? [Ynsfdaq?] diff --git a/dir/a.txt b/dir/a.txt +1 hunks, 2 lines changed +examine changes to 'dir/a.txt'? [Ynsfdaq?] @@ -1,4 +1,4 @@ +-hello world ++hello world! + + someone + up +record this change to 'dir/a.txt'? [Ynsfdaq?] +% after qrecord b.patch 'tip' +changeset: 2:b056198bf878 +tag: qtip +tag: tip +tag: b.patch +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: bbb + +diff -r 5d1ca63427ee -r b056198bf878 1.txt +--- a/1.txt Thu Jan 01 00:00:00 1970 +0000 ++++ b/1.txt Thu Jan 01 00:00:00 1970 +0000 +@@ -1,5 +1,5 @@ + 1 + 2 2 + 3 +-4 ++4 4 + 5 +diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt +--- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000 ++++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000 +@@ -1,4 +1,4 @@ +-hello world ++hello world! + + someone + up + + +% after qrecord b.patch 'diff' + +% --- end --- diff -r 528c986f0162 -r 597d8402087d tests/test-strip-cross --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-strip-cross Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,68 @@ +#!/bin/sh + +# test stripping of filelogs where the linkrev doesn't always increase + +echo '[extensions]' >> $HGRCPATH +echo 'hgext.mq =' >> $HGRCPATH + +hg init orig +cd orig + +hidefilename() +{ + sed -e 's/saving bundle to .*strip-backup/saving bundle to strip-backup/' +} + +commit() +{ + hg up -qC null + count=1 + for i in "$@"; do + for f in $i; do + echo $count > $f + done + count=`expr $count + 1` + done + hg commit -qAm "$*" +} + +# 2 1 0 2 0 1 2 +commit '201 210' + +commit '102 120' '210' + +commit '021' + +commit '201' '021 120' + +commit '012 021' '102 201' '120 210' + +commit 'manifest-file' + +commit '102 120' '012 210' '021 201' + +commit '201 210' '021 120' '012 102' + +HGUSER=another-user; export HGUSER +commit 'manifest-file' + +commit '012' 'manifest-file' + +cd .. +hg clone -q -U -r -1 -r -2 -r -3 -r -4 -r -6 orig crossed + +for i in crossed/.hg/store/00manifest.i crossed/.hg/store/data/*.i; do + echo $i + hg debugindex $i + echo +done + +for i in 0 1 2 3 4; do + hg clone -q -U --pull crossed $i + echo "% Trying to strip revision $i" + hg --cwd $i strip $i 2>&1 | hidefilename + echo "% Verifying" + hg --cwd $i verify + echo +done + diff -r 528c986f0162 -r 597d8402087d tests/test-strip-cross.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-strip-cross.out Fri Jan 25 16:04:46 2008 -0800 @@ -0,0 +1,118 @@ +crossed/.hg/store/00manifest.i + rev offset length base linkrev nodeid p1 p2 + 0 0 112 0 0 6f105cbb914d 000000000000 000000000000 + 1 112 56 1 3 1b55917b3699 000000000000 000000000000 + 2 168 123 1 1 8f3d04e263e5 000000000000 000000000000 + 3 291 122 1 2 f0ef8726ac4f 000000000000 000000000000 + 4 413 87 4 4 0b76e38b4070 000000000000 000000000000 + +crossed/.hg/store/data/012.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 3 1 1 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 2 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/021.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 3 1 2 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 1 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/102.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 1 b8e02f643373 000000000000 000000000000 + 1 3 3 1 0 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 2 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/120.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 1 b8e02f643373 000000000000 000000000000 + 1 3 3 1 2 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 0 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/201.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 2 b8e02f643373 000000000000 000000000000 + 1 3 3 1 0 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 1 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/210.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 2 b8e02f643373 000000000000 000000000000 + 1 3 3 1 1 5d9299349fc0 000000000000 000000000000 + 2 6 3 2 0 2661d26c6496 000000000000 000000000000 + +crossed/.hg/store/data/manifest-file.i + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 3 b8e02f643373 000000000000 000000000000 + 1 3 3 1 4 5d9299349fc0 000000000000 000000000000 + +% Trying to strip revision 0 +saving bundle to strip-backup/cbb8c2f0a2e3-backup +saving bundle to strip-backup/cbb8c2f0a2e3-temp +adding branch +adding changesets +adding manifests +adding file changes +added 4 changesets with 15 changes to 7 files (+3 heads) +% Verifying +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +7 files, 4 changesets, 15 total revisions + +% Trying to strip revision 1 +saving bundle to strip-backup/124ecc0cbec9-backup +saving bundle to strip-backup/124ecc0cbec9-temp +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 12 changes to 7 files (+3 heads) +% Verifying +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +7 files, 4 changesets, 14 total revisions + +% Trying to strip revision 2 +saving bundle to strip-backup/f6439b304a1a-backup +saving bundle to strip-backup/f6439b304a1a-temp +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 8 changes to 6 files (+2 heads) +% Verifying +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +7 files, 4 changesets, 14 total revisions + +% Trying to strip revision 3 +saving bundle to strip-backup/6e54ec5db740-backup +saving bundle to strip-backup/6e54ec5db740-temp +adding branch +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 2 files (+1 heads) +% Verifying +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +7 files, 4 changesets, 19 total revisions + +% Trying to strip revision 4 +saving bundle to strip-backup/9147ea23c156-backup +% Verifying +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +7 files, 4 changesets, 19 total revisions + diff -r 528c986f0162 -r 597d8402087d tests/test-webraw.out --- a/tests/test-webraw.out Fri Jan 25 16:04:32 2008 -0800 +++ b/tests/test-webraw.out Fri Jan 25 16:04:46 2008 -0800 @@ -1,7 +1,7 @@ 200 Script output follows content-type: text/plain content-length: 157 -content-disposition: filename=sometext.txt +content-disposition: inline; filename=sometext.txt This is just some random text that will go inside the file and take a few lines.