# HG changeset patch # User Augie Fackler # Date 1354211062 21600 # Node ID e8c9b13c7799724e8fff21ae590c1e6ceda1437a # Parent 1683bca3175285d482633c4c7ed2231b338f6738# Parent 848345a8d6adaa58704baecbb7567b275df3cc9d Merge with stable. diff -r 848345a8d6ad -r e8c9b13c7799 Makefile --- a/Makefile Thu Nov 29 16:37:15 2012 +0100 +++ b/Makefile Thu Nov 29 11:44:22 2012 -0600 @@ -34,7 +34,7 @@ local: $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_hgexe -i build_mo - $(PYTHON) hg version + env HGRCPATH= $(PYTHON) hg version build: $(PYTHON) setup.py $(PURE) build diff -r 848345a8d6ad -r e8c9b13c7799 contrib/check-code.py --- a/contrib/check-code.py Thu Nov 29 16:37:15 2012 +0100 +++ b/contrib/check-code.py Thu Nov 29 11:44:22 2012 -0600 @@ -211,11 +211,11 @@ (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"), (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'), (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"), + (r'ui\.(status|progress|write|note|warn)\([\'\"]x', + "missing _() in ui message (use () to hide false-positives)"), ], # warnings [ - (r'ui\.(status|progress|write|note|warn)\([\'\"]x', - "warning: unwrapped ui message"), ] ] diff -r 848345a8d6ad -r e8c9b13c7799 contrib/hgk --- a/contrib/hgk Thu Nov 29 16:37:15 2012 +0100 +++ b/contrib/hgk Thu Nov 29 11:44:22 2012 -0600 @@ -15,8 +15,43 @@ # The whole snipped is activated only under windows, mouse wheel # bindings working already under MacOSX and Linux. +if {[catch {package require Ttk}]} { + # use a shim + namespace eval ttk { + proc style args {} + + proc entry args { + eval [linsert $args 0 ::entry] -relief flat + } + } + + interp alias {} ttk::button {} button + interp alias {} ttk::frame {} frame + interp alias {} ttk::label {} label + interp alias {} ttk::scrollbar {} scrollbar + interp alias {} ttk::optionMenu {} tk_optionMenu +} else { + proc ::ttk::optionMenu {w varName firstValue args} { + upvar #0 $varName var + + if {![info exists var]} { + set var $firstValue + } + ttk::menubutton $w -textvariable $varName -menu $w.menu \ + -direction flush + menu $w.menu -tearoff 0 + $w.menu add radiobutton -label $firstValue -variable $varName + foreach i $args { + $w.menu add radiobutton -label $i -variable $varName + } + return $w.menu + } +} + if {[tk windowingsystem] eq "win32"} { +ttk::style theme use xpnative + set mw_classes [list Text Listbox Table TreeCtrl] foreach class $mw_classes { bind $class {} } @@ -72,6 +107,12 @@ bind all [list ::tk::MouseWheel %W %X %Y %D 0] # end of win32 section +} else { + +if {[ttk::style theme use] eq "default"} { + ttk::style theme use clam +} + } @@ -480,7 +521,7 @@ wm transient $w . message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 - button $w.ok -text OK -command "destroy $w" + ttk::button $w.ok -text OK -command "destroy $w" pack $w.ok -side bottom -fill x bind $w "grab $w; focus $w" tkwait window $w @@ -526,11 +567,11 @@ set geometry(ctexth) [expr {($texth - 8) / [font metrics $textfont -linespace]}] } - frame .ctop.top - frame .ctop.top.bar + ttk::frame .ctop.top + ttk::frame .ctop.top.bar pack .ctop.top.bar -side bottom -fill x set cscroll .ctop.top.csb - scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 + ttk::scrollbar $cscroll -command {allcanvs yview} pack $cscroll -side right -fill y panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4 pack .ctop.top.clist -side top -fill both -expand 1 @@ -538,15 +579,15 @@ set canv .ctop.top.clist.canv canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ -bg $bgcolor -bd 0 \ - -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey + -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground "#c0c0c0" .ctop.top.clist add $canv set canv2 .ctop.top.clist.canv2 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ - -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground "#c0c0c0" .ctop.top.clist add $canv2 set canv3 .ctop.top.clist.canv3 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ - -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground "#c0c0c0" .ctop.top.clist add $canv3 bind .ctop.top.clist {resizeclistpanes %W %w} @@ -557,7 +598,7 @@ -command gotocommit -width 8 $sha1but conf -disabledforeground [$sha1but cget -foreground] pack .ctop.top.bar.sha1label -side left - entry $sha1entry -width 40 -font $textfont -textvariable sha1string + ttk::entry $sha1entry -width 40 -font $textfont -textvariable sha1string trace add variable sha1string write sha1change pack $sha1entry -side left -pady 2 @@ -577,25 +618,25 @@ 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01}; } - button .ctop.top.bar.leftbut -image bm-left -command goback \ + ttk::button .ctop.top.bar.leftbut -image bm-left -command goback \ -state disabled -width 26 pack .ctop.top.bar.leftbut -side left -fill y - button .ctop.top.bar.rightbut -image bm-right -command goforw \ + ttk::button .ctop.top.bar.rightbut -image bm-right -command goforw \ -state disabled -width 26 pack .ctop.top.bar.rightbut -side left -fill y - button .ctop.top.bar.findbut -text "Find" -command dofind + ttk::button .ctop.top.bar.findbut -text "Find" -command dofind pack .ctop.top.bar.findbut -side left set findstring {} set fstring .ctop.top.bar.findstring lappend entries $fstring - entry $fstring -width 30 -font $textfont -textvariable findstring + ttk::entry $fstring -width 30 -font $textfont -textvariable findstring pack $fstring -side left -expand 1 -fill x set findtype Exact - set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \ + set findtypemenu [ttk::optionMenu .ctop.top.bar.findtype \ findtype Exact IgnCase Regexp] set findloc "All fields" - tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ + ttk::optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ Comments Author Committer Files Pickaxe pack .ctop.top.bar.findloc -side right pack .ctop.top.bar.findtype -side right @@ -604,14 +645,14 @@ panedwindow .ctop.cdet -orient horizontal .ctop add .ctop.cdet - frame .ctop.cdet.left + ttk::frame .ctop.cdet.left set ctext .ctop.cdet.left.ctext text $ctext -fg $fgcolor -bg $bgcolor -state disabled -font $textfont \ -width $geometry(ctextw) -height $geometry(ctexth) \ -yscrollcommand ".ctop.cdet.left.sb set" \ -xscrollcommand ".ctop.cdet.left.hb set" -wrap none - scrollbar .ctop.cdet.left.sb -command "$ctext yview" - scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview" + ttk::scrollbar .ctop.cdet.left.sb -command "$ctext yview" + ttk::scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview" pack .ctop.cdet.left.sb -side right -fill y pack .ctop.cdet.left.hb -side bottom -fill x pack $ctext -side left -fill both -expand 1 @@ -643,12 +684,12 @@ $ctext tag conf found -back yellow } - frame .ctop.cdet.right + ttk::frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles listbox $cflist -fg $fgcolor -bg $bgcolor \ -selectmode extended -width $geometry(cflistw) \ -yscrollcommand ".ctop.cdet.right.sb set" - scrollbar .ctop.cdet.right.sb -command "$cflist yview" + ttk::scrollbar .ctop.cdet.right.sb -command "$cflist yview" pack .ctop.cdet.right.sb -side right -fill y pack $cflist -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.right @@ -901,7 +942,7 @@ Use and redistribute under the terms of the GNU General Public License} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 - button $w.ok -text Close -command "destroy $w" + ttk::button $w.ok -text Close -command "destroy $w" pack $w.ok -side bottom } @@ -1219,7 +1260,7 @@ } else { # draw a head or other ref if {[incr nheads -1] >= 0} { - set col green + set col "#00ff00" } else { set col "#ddddff" } @@ -2417,8 +2458,7 @@ set currentid $id $sha1entry delete 0 end $sha1entry insert 0 $id - $sha1entry selection from 0 - $sha1entry selection to end + $sha1entry selection range 0 end $ctext conf -state normal $ctext delete 0.0 end @@ -3675,36 +3715,36 @@ set patchtop $top catch {destroy $top} toplevel $top - label $top.title -text "Generate patch" + ttk::label $top.title -text "Generate patch" grid $top.title - -pady 10 - label $top.from -text "From:" - entry $top.fromsha1 -width 40 -relief flat + ttk::label $top.from -text "From:" + ttk::entry $top.fromsha1 -width 40 $top.fromsha1 insert 0 $oldid $top.fromsha1 conf -state readonly grid $top.from $top.fromsha1 -sticky w - entry $top.fromhead -width 60 -relief flat + ttk::entry $top.fromhead -width 60 $top.fromhead insert 0 $oldhead $top.fromhead conf -state readonly grid x $top.fromhead -sticky w - label $top.to -text "To:" - entry $top.tosha1 -width 40 -relief flat + ttk::label $top.to -text "To:" + ttk::entry $top.tosha1 -width 40 $top.tosha1 insert 0 $newid $top.tosha1 conf -state readonly grid $top.to $top.tosha1 -sticky w - entry $top.tohead -width 60 -relief flat + ttk::entry $top.tohead -width 60 $top.tohead insert 0 $newhead $top.tohead conf -state readonly grid x $top.tohead -sticky w - button $top.rev -text "Reverse" -command mkpatchrev -padx 5 + ttk::button $top.rev -text "Reverse" -command mkpatchrev grid $top.rev x -pady 10 - label $top.flab -text "Output file:" - entry $top.fname -width 60 + ttk::label $top.flab -text "Output file:" + ttk::entry $top.fname -width 60 $top.fname insert 0 [file normalize "patch$patchnum.patch"] incr patchnum grid $top.flab $top.fname -sticky w - frame $top.buts - button $top.buts.gen -text "Generate" -command mkpatchgo - button $top.buts.can -text "Cancel" -command mkpatchcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text "Generate" -command mkpatchgo + ttk::button $top.buts.can -text "Cancel" -command mkpatchcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@ -3755,23 +3795,23 @@ set mktagtop $top catch {destroy $top} toplevel $top - label $top.title -text "Create tag" + ttk::label $top.title -text "Create tag" grid $top.title - -pady 10 - label $top.id -text "ID:" - entry $top.sha1 -width 40 -relief flat + ttk::label $top.id -text "ID:" + ttk::entry $top.sha1 -width 40 $top.sha1 insert 0 $rowmenuid $top.sha1 conf -state readonly grid $top.id $top.sha1 -sticky w - entry $top.head -width 60 -relief flat + ttk::entry $top.head -width 60 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] $top.head conf -state readonly grid x $top.head -sticky w - label $top.tlab -text "Tag name:" - entry $top.tag -width 60 + ttk::label $top.tlab -text "Tag name:" + ttk::entry $top.tag -width 60 grid $top.tlab $top.tag -sticky w - frame $top.buts - button $top.buts.gen -text "Create" -command mktaggo - button $top.buts.can -text "Cancel" -command mktagcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text "Create" -command mktaggo + ttk::button $top.buts.can -text "Cancel" -command mktagcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a @@ -3835,27 +3875,27 @@ set wrcomtop $top catch {destroy $top} toplevel $top - label $top.title -text "Write commit to file" + ttk::label $top.title -text "Write commit to file" grid $top.title - -pady 10 - label $top.id -text "ID:" - entry $top.sha1 -width 40 -relief flat + ttk::label $top.id -text "ID:" + ttk::entry $top.sha1 -width 40 $top.sha1 insert 0 $rowmenuid $top.sha1 conf -state readonly grid $top.id $top.sha1 -sticky w - entry $top.head -width 60 -relief flat + ttk::entry $top.head -width 60 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] $top.head conf -state readonly grid x $top.head -sticky w - label $top.clab -text "Command:" - entry $top.cmd -width 60 -textvariable wrcomcmd + ttk::label $top.clab -text "Command:" + ttk::entry $top.cmd -width 60 -textvariable wrcomcmd grid $top.clab $top.cmd -sticky w -pady 10 - label $top.flab -text "Output file:" - entry $top.fname -width 60 + ttk::label $top.flab -text "Output file:" + ttk::entry $top.fname -width 60 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"] grid $top.flab $top.fname -sticky w - frame $top.buts - button $top.buts.gen -text "Write" -command wrcomgo - button $top.buts.can -text "Cancel" -command wrcomcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text "Write" -command wrcomgo + ttk::button $top.buts.can -text "Cancel" -command wrcomcan grid $top.buts.gen $top.buts.can grid columnconfigure $top.buts 0 -weight 1 -uniform a grid columnconfigure $top.buts 1 -weight 1 -uniform a diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/__init__.py --- a/hgext/convert/__init__.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/__init__.py Thu Nov 29 11:44:22 2012 -0600 @@ -191,6 +191,10 @@ branch indicated in the regex as the second parent of the changeset. Default is ``{{mergefrombranch ([-\\w]+)}}`` + :convert.localtimezone: use local time (as determined by the TZ + environment variable) for changeset date/times. The default + is False (use UTC). + :hook.cvslog: Specify a Python function to be called at the end of gathering the CVS log. The function is passed a list with the log entries, and can modify the entries in-place, or add or @@ -231,6 +235,10 @@ :convert.svn.trunk: specify the name of the trunk branch. The default is ``trunk``. + :convert.localtimezone: use local time (as determined by the TZ + environment variable) for changeset date/times. The default + is False (use UTC). + Source history can be retrieved starting at a specific revision, instead of being integrally converted. Only single branch conversions are supported. diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/common.py --- a/hgext/convert/common.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/common.py Thu Nov 29 11:44:22 2012 -0600 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import base64, errno, subprocess, os +import base64, errno, subprocess, os, datetime import cPickle as pickle from mercurial import util from mercurial.i18n import _ @@ -446,3 +446,10 @@ if e.errno != errno.ENOENT: raise return m + +def makedatetimestamp(t): + """Like util.makedate() but for time t instead of current time""" + delta = (datetime.datetime.utcfromtimestamp(t) - + datetime.datetime.fromtimestamp(t)) + tz = delta.days * 86400 + delta.seconds + return t, tz diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/cvs.py --- a/hgext/convert/cvs.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/cvs.py Thu Nov 29 11:44:22 2012 -0600 @@ -11,6 +11,7 @@ from mercurial.i18n import _ from common import NoRepo, commit, converter_source, checktool +from common import makedatetimestamp import cvsps class convert_cvs(converter_source): @@ -70,6 +71,8 @@ cs.author = self.recode(cs.author) self.lastbranch[cs.branch] = id cs.comment = self.recode(cs.comment) + if self.ui.configbool('convert', 'localtimezone'): + cs.date = makedatetimestamp(cs.date[0]) date = util.datestr(cs.date, '%Y-%m-%d %H:%M:%S %1%2') self.tags.update(dict.fromkeys(cs.tags, id)) diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/cvsps.py Thu Nov 29 11:44:22 2012 -0600 @@ -801,22 +801,22 @@ # Note: trailing spaces on several lines here are needed to have # bug-for-bug compatibility with cvsps. ui.write('---------------------\n') - ui.write('PatchSet %d \n' % cs.id) - ui.write('Date: %s\n' % util.datestr(cs.date, - '%Y/%m/%d %H:%M:%S %1%2')) - ui.write('Author: %s\n' % cs.author) - ui.write('Branch: %s\n' % (cs.branch or 'HEAD')) - ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1], - ','.join(cs.tags) or '(none)')) + ui.write(('PatchSet %d \n' % cs.id)) + ui.write(('Date: %s\n' % util.datestr(cs.date, + '%Y/%m/%d %H:%M:%S %1%2'))) + ui.write(('Author: %s\n' % cs.author)) + ui.write(('Branch: %s\n' % (cs.branch or 'HEAD'))) + ui.write(('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1], + ','.join(cs.tags) or '(none)'))) branchpoints = getattr(cs, 'branchpoints', None) if branchpoints: - ui.write('Branchpoints: %s \n' % ', '.join(branchpoints)) + ui.write(('Branchpoints: %s \n' % ', '.join(branchpoints))) if opts["parents"] and cs.parents: if len(cs.parents) > 1: - ui.write('Parents: %s\n' % - (','.join([str(p.id) for p in cs.parents]))) + ui.write(('Parents: %s\n' % + (','.join([str(p.id) for p in cs.parents])))) else: - ui.write('Parent: %d\n' % cs.parents[0].id) + ui.write(('Parent: %d\n' % cs.parents[0].id)) if opts["ancestors"]: b = cs.branch @@ -825,11 +825,11 @@ b, c = ancestors[b] r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) if r: - ui.write('Ancestors: %s\n' % (','.join(r))) + ui.write(('Ancestors: %s\n' % (','.join(r)))) - ui.write('Log:\n') + ui.write(('Log:\n')) ui.write('%s\n\n' % cs.comment) - ui.write('Members: \n') + ui.write(('Members: \n')) for f in cs.entries: fn = f.file if fn.startswith(opts["prefix"]): diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/git.py --- a/hgext/convert/git.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/git.py Thu Nov 29 11:44:22 2012 -0600 @@ -6,12 +6,24 @@ # GNU General Public License version 2 or any later version. import os -from mercurial import util +from mercurial import util, config from mercurial.node import hex, nullid from mercurial.i18n import _ from common import NoRepo, commit, converter_source, checktool +class submodule(object): + def __init__(self, path, node, url): + self.path = path + self.node = node + self.url = url + + def hgsub(self): + return "%s = [git]%s" % (self.path, self.url) + + def hgsubstate(self): + return "%s %s" % (self.node, self.path) + class convert_git(converter_source): # Windows does not support GIT_DIR= construct while other systems # cannot remove environment variable. Just assume none have @@ -55,6 +67,7 @@ checktool('git', 'git') self.path = path + self.submodules = [] def getheads(self): if not self.rev: @@ -76,16 +89,57 @@ return data def getfile(self, name, rev): - data = self.catfile(rev, "blob") - mode = self.modecache[(name, rev)] + if name == '.hgsub': + data = '\n'.join([m.hgsub() for m in self.submoditer()]) + mode = '' + elif name == '.hgsubstate': + data = '\n'.join([m.hgsubstate() for m in self.submoditer()]) + mode = '' + else: + data = self.catfile(rev, "blob") + mode = self.modecache[(name, rev)] return data, mode + def submoditer(self): + null = hex(nullid) + for m in sorted(self.submodules, key=lambda p: p.path): + if m.node != null: + yield m + + def parsegitmodules(self, content): + """Parse the formatted .gitmodules file, example file format: + [submodule "sub"]\n + \tpath = sub\n + \turl = git://giturl\n + """ + self.submodules = [] + c = config.config() + # Each item in .gitmodules starts with \t that cant be parsed + c.parse('.gitmodules', content.replace('\t','')) + for sec in c.sections(): + s = c[sec] + if 'url' in s and 'path' in s: + self.submodules.append(submodule(s['path'], '', s['url'])) + + def retrievegitmodules(self, version): + modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules')) + if ret: + raise util.Abort(_('cannot read submodules config file in %s') % + version) + self.parsegitmodules(modules) + for m in self.submodules: + node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path)) + if ret: + continue + m.node = node.strip() + def getchanges(self, version): self.modecache = {} fh = self.gitopen("git diff-tree -z --root -m -r %s" % version) changes = [] seen = set() entry = None + subexists = False for l in fh.read().split('\x00'): if not entry: if not l.startswith(':'): @@ -97,15 +151,24 @@ seen.add(f) entry = entry.split() h = entry[3] - if entry[1] == '160000': - raise util.Abort('git submodules are not supported!') p = (entry[1] == "100755") s = (entry[1] == "120000") - self.modecache[(f, h)] = (p and "x") or (s and "l") or "" - changes.append((f, h)) + + if f == '.gitmodules': + subexists = True + changes.append(('.hgsub', '')) + elif entry[1] == '160000' or entry[0] == ':160000': + subexists = True + else: + self.modecache[(f, h)] = (p and "x") or (s and "l") or "" + changes.append((f, h)) entry = None if fh.close(): raise util.Abort(_('cannot read changes in %s') % version) + + if subexists: + self.retrievegitmodules(version) + changes.append(('.hgsubstate', '')) return (changes, {}) def getcommit(self, version): diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/hg.py --- a/hgext/convert/hg.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/hg.py Thu Nov 29 11:44:22 2012 -0600 @@ -219,9 +219,10 @@ return self.ui.status(_("updating bookmarks\n")) + destmarks = self.repo._bookmarks for bookmark in updatedbookmark: - self.repo._bookmarks[bookmark] = bin(updatedbookmark[bookmark]) - bookmarks.write(self.repo) + destmarks[bookmark] = bin(updatedbookmark[bookmark]) + destmarks.write() def hascommit(self, rev): if rev not in self.repo and self.clonebranches: diff -r 848345a8d6ad -r e8c9b13c7799 hgext/convert/subversion.py --- a/hgext/convert/subversion.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/convert/subversion.py Thu Nov 29 11:44:22 2012 -0600 @@ -18,6 +18,7 @@ from common import NoRepo, MissingTool, commit, encodeargs, decodeargs from common import commandline, converter_source, converter_sink, mapfile +from common import makedatetimestamp try: from svn.core import SubversionException, Pool @@ -802,6 +803,8 @@ # ISO-8601 conformant # '2007-01-04T17:35:00.902377Z' date = util.parsedate(date[:19] + " UTC", ["%Y-%m-%dT%H:%M:%S"]) + if self.ui.configbool('convert', 'localtimezone'): + date = makedatetimestamp(date[0]) log = message and self.recode(message) or '' author = author and self.recode(author) or '' diff -r 848345a8d6ad -r e8c9b13c7799 hgext/eol.py --- a/hgext/eol.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/eol.py Thu Nov 29 11:44:22 2012 -0600 @@ -307,7 +307,7 @@ eolmtime = 0 if eolmtime > cachemtime: - ui.debug("eol: detected change in .hgeol\n") + self.ui.debug("eol: detected change in .hgeol\n") wlock = None try: wlock = self.wlock() diff -r 848345a8d6ad -r e8c9b13c7799 hgext/hgk.py --- a/hgext/hgk.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/hgk.py Thu Nov 29 11:44:22 2012 -0600 @@ -98,9 +98,9 @@ if ctx is None: ctx = repo[n] # use ctx.node() instead ?? - ui.write("tree %s\n" % short(ctx.changeset()[0])) + ui.write(("tree %s\n" % short(ctx.changeset()[0]))) for p in ctx.parents(): - ui.write("parent %s\n" % p) + ui.write(("parent %s\n" % p)) date = ctx.date() description = ctx.description().replace("\0", "") @@ -108,12 +108,13 @@ if lines and lines[-1].startswith('committer:'): committer = lines[-1].split(': ')[1].rstrip() else: - committer = ctx.user() + committer = "" - 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()) + ui.write(("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))) + if committer != '': + 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 != "": ui.write("%s%s\n" % (prefix, @@ -302,7 +303,7 @@ def config(ui, repo, **opts): """print extension options""" def writeopt(name, value): - ui.write('k=%s\nv=%s\n' % (name, value)) + ui.write(('k=%s\nv=%s\n' % (name, value))) writeopt('vdiff', ui.config('hgk', 'vdiff', '')) diff -r 848345a8d6ad -r e8c9b13c7799 hgext/histedit.py --- a/hgext/histedit.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/histedit.py Thu Nov 29 11:44:22 2012 -0600 @@ -144,7 +144,6 @@ import pickle import os -from mercurial import bookmarks from mercurial import cmdutil from mercurial import discovery from mercurial import error @@ -740,12 +739,13 @@ # nothing to move moves.append((bk, new[-1])) if moves: + marks = repo._bookmarks for mark, new in moves: - old = repo._bookmarks[mark] + old = marks[mark] ui.note(_('histedit: moving bookmarks %s from %s to %s\n') % (mark, node.short(old), node.short(new))) - repo._bookmarks[mark] = new - bookmarks.write(repo) + marks[mark] = new + marks.write() def cleanupnode(ui, repo, name, nodes): """strip a group of nodes from the repository diff -r 848345a8d6ad -r e8c9b13c7799 hgext/mq.py --- a/hgext/mq.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/mq.py Thu Nov 29 11:44:22 2012 -0600 @@ -63,7 +63,7 @@ from mercurial.node import bin, hex, short, nullid, nullrev from mercurial.lock import release from mercurial import commands, cmdutil, hg, scmutil, util, revset -from mercurial import repair, extensions, error, phases, bookmarks +from mercurial import repair, extensions, error, phases from mercurial import patch as patchmod import os, re, errno, shutil @@ -1675,9 +1675,10 @@ patchf.write(chunk) patchf.close() + marks = repo._bookmarks for bm in bmlist: - repo._bookmarks[bm] = n - bookmarks.write(repo) + marks[bm] = n + marks.write() self.applied.append(statusentry(n, patchfn)) except: # re-raises @@ -2999,7 +3000,7 @@ revs.update(set(rsrevs)) if not revs: del marks[mark] - repo._writebookmarks(mark) + marks.write() ui.write(_("bookmark '%s' deleted\n") % mark) if not revs: @@ -3049,7 +3050,7 @@ if opts.get('bookmark'): del marks[mark] - repo._writebookmarks(marks) + marks.write() ui.write(_("bookmark '%s' deleted\n") % mark) repo.mq.strip(repo, revs, backup=backup, update=update, @@ -3435,7 +3436,7 @@ outapplied.pop() # looking for pushed and shared changeset for node in outapplied: - if repo[node].phase() < phases.secret: + if self[node].phase() < phases.secret: raise util.Abort(_('source has mq patches applied')) # no non-secret patches pushed super(mqrepo, self).checkpush(force, revs) diff -r 848345a8d6ad -r e8c9b13c7799 hgext/patchbomb.py --- a/hgext/patchbomb.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/patchbomb.py Thu Nov 29 11:44:22 2012 -0600 @@ -474,11 +474,11 @@ if opts.get('diffstat') or opts.get('confirm'): ui.write(_('\nFinal summary:\n\n')) - ui.write('From: %s\n' % sender) + ui.write(('From: %s\n' % sender)) for addr in showaddrs: ui.write('%s\n' % addr) for m, subj, ds in msgs: - ui.write('Subject: %s\n' % subj) + ui.write(('Subject: %s\n' % subj)) if ds: ui.write(ds) ui.write('\n') diff -r 848345a8d6ad -r e8c9b13c7799 hgext/rebase.py --- a/hgext/rebase.py Thu Nov 29 16:37:15 2012 +0100 +++ b/hgext/rebase.py Thu Nov 29 11:44:22 2012 -0600 @@ -479,13 +479,14 @@ def updatebookmarks(repo, nstate, originalbookmarks, **opts): 'Move bookmarks to their correct changesets' + marks = repo._bookmarks for k, v in originalbookmarks.iteritems(): if v in nstate: if nstate[v] != nullmerge: # update the bookmarks for revs that have moved - repo._bookmarks[k] = nstate[v] + marks[k] = nstate[v] - bookmarks.write(repo) + marks.write() def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches, external): @@ -655,9 +656,12 @@ # # The actual abort is handled by `defineparents` if len(root.parents()) <= 1: - # (strict) ancestors of not ancestors of - detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root) + # ancestors of not ancestors of + detachset = repo.changelog.findmissingrevs([commonbase.rev()], + [root.rev()]) state.update(dict.fromkeys(detachset, nullmerge)) + # detachset can have root, and we definitely want to rebase that + state[root.rev()] = nullrev return repo['.'].rev(), dest.rev(), state def clearrebased(ui, repo, state, collapsedas=None): diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/ancestor.py --- a/mercurial/ancestor.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/ancestor.py Thu Nov 29 11:44:22 2012 -0600 @@ -6,6 +6,7 @@ # GNU General Public License version 2 or any later version. import heapq +from node import nullrev def ancestor(a, b, pfunc): """ @@ -89,3 +90,166 @@ gx = x.next() except StopIteration: return None + +def missingancestors(revs, bases, pfunc): + """Return all the ancestors of revs that are not ancestors of bases. + + This may include elements from revs. + + Equivalent to the revset (::revs - ::bases). Revs are returned in + revision number order, which is a topological order. + + revs and bases should both be iterables. pfunc must return a list of + parent revs for a given revs. + + graph is a dict of child->parent adjacency lists for this graph: + o 13 + | + | o 12 + | | + | | o 11 + | | |\ + | | | | o 10 + | | | | | + | o---+ | 9 + | | | | | + o | | | | 8 + / / / / + | | o | 7 + | | | | + o---+ | 6 + / / / + | | o 5 + | |/ + | o 4 + | | + o | 3 + | | + | o 2 + |/ + o 1 + | + o 0 + >>> graph = {0: [-1], 1: [0], 2: [1], 3: [1], 4: [2], 5: [4], 6: [4], + ... 7: [4], 8: [-1], 9: [6, 7], 10: [5], 11: [3, 7], 12: [9], + ... 13: [8]} + >>> pfunc = graph.get + + Empty revs + >>> missingancestors([], [1], pfunc) + [] + >>> missingancestors([], [], pfunc) + [] + + If bases is empty, it's the same as if it were [nullrev] + >>> missingancestors([12], [], pfunc) + [0, 1, 2, 4, 6, 7, 9, 12] + + Trivial case: revs == bases + >>> missingancestors([0], [0], pfunc) + [] + >>> missingancestors([4, 5, 6], [6, 5, 4], pfunc) + [] + + With nullrev + >>> missingancestors([-1], [12], pfunc) + [] + >>> missingancestors([12], [-1], pfunc) + [0, 1, 2, 4, 6, 7, 9, 12] + + 9 is a parent of 12. 7 is a parent of 9, so an ancestor of 12. 6 is an + ancestor of 12 but not of 7. + >>> missingancestors([12], [9], pfunc) + [12] + >>> missingancestors([9], [12], pfunc) + [] + >>> missingancestors([12, 9], [7], pfunc) + [6, 9, 12] + >>> missingancestors([7, 6], [12], pfunc) + [] + + More complex cases + >>> missingancestors([10], [11, 12], pfunc) + [5, 10] + >>> missingancestors([11], [10], pfunc) + [3, 7, 11] + >>> missingancestors([11], [10, 12], pfunc) + [3, 11] + >>> missingancestors([12], [10], pfunc) + [6, 7, 9, 12] + >>> missingancestors([12], [11], pfunc) + [6, 9, 12] + >>> missingancestors([10, 11, 12], [13], pfunc) + [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12] + >>> missingancestors([13], [10, 11, 12], pfunc) + [8, 13] + """ + + revsvisit = set(revs) + basesvisit = set(bases) + if not revsvisit: + return [] + if not basesvisit: + basesvisit.add(nullrev) + start = max(max(revsvisit), max(basesvisit)) + bothvisit = revsvisit.intersection(basesvisit) + revsvisit.difference_update(bothvisit) + basesvisit.difference_update(bothvisit) + # At this point, we hold the invariants that: + # - revsvisit is the set of nodes we know are an ancestor of at least one + # of the nodes in revs + # - basesvisit is the same for bases + # - bothvisit is the set of nodes we know are ancestors of at least one of + # the nodes in revs and one of the nodes in bases + # - a node may be in none or one, but not more, of revsvisit, basesvisit + # and bothvisit at any given time + # Now we walk down in reverse topo order, adding parents of nodes already + # visited to the sets while maintaining the invariants. When a node is + # found in both revsvisit and basesvisit, it is removed from them and + # added to bothvisit instead. When revsvisit becomes empty, there are no + # more ancestors of revs that aren't also ancestors of bases, so exit. + + missing = [] + for curr in xrange(start, nullrev, -1): + if not revsvisit: + break + + if curr in bothvisit: + bothvisit.remove(curr) + # curr's parents might have made it into revsvisit or basesvisit + # through another path + for p in pfunc(curr): + revsvisit.discard(p) + basesvisit.discard(p) + bothvisit.add(p) + continue + + # curr will never be in both revsvisit and basesvisit, since if it + # were it'd have been pushed to bothvisit + if curr in revsvisit: + missing.append(curr) + thisvisit = revsvisit + othervisit = basesvisit + elif curr in basesvisit: + thisvisit = basesvisit + othervisit = revsvisit + else: + # not an ancestor of revs or bases: ignore + continue + + thisvisit.remove(curr) + for p in pfunc(curr): + if p == nullrev: + pass + elif p in othervisit or p in bothvisit: + # p is implicitly in thisvisit. This means p is or should be + # in bothvisit + revsvisit.discard(p) + basesvisit.discard(p) + bothvisit.add(p) + else: + # visit later + thisvisit.add(p) + + missing.reverse() + return missing diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/bookmarks.py --- a/mercurial/bookmarks.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/bookmarks.py Thu Nov 29 11:44:22 2012 -0600 @@ -7,35 +7,75 @@ from mercurial.i18n import _ from mercurial.node import hex -from mercurial import encoding, error, util, obsolete, phases +from mercurial import encoding, error, util, obsolete import errno, os -def read(repo): - '''Parse .hg/bookmarks file and return a dictionary +class bmstore(dict): + """Storage for bookmarks. + + This object should do all bookmark reads and writes, so that it's + fairly simple to replace the storage underlying bookmarks without + having to clone the logic surrounding bookmarks. + + This particular bmstore implementation stores bookmarks as + {hash}\s{name}\n (the same format as localtags) in + .hg/bookmarks. The mapping is stored as {name: nodeid}. + + This class does NOT handle the "current" bookmark state at this + time. + """ - Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values - in the .hg/bookmarks file. - Read the file and return a (name=>nodeid) dictionary - ''' - bookmarks = {} - try: - for line in repo.opener('bookmarks'): - line = line.strip() - if not line: - continue - if ' ' not in line: - repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line) - continue - sha, refspec = line.split(' ', 1) - refspec = encoding.tolocal(refspec) + def __init__(self, repo): + dict.__init__(self) + self._repo = repo + try: + for line in repo.vfs('bookmarks'): + line = line.strip() + if not line: + continue + if ' ' not in line: + repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') + % line) + continue + sha, refspec = line.split(' ', 1) + refspec = encoding.tolocal(refspec) + try: + self[refspec] = repo.changelog.lookup(sha) + except LookupError: + pass + except IOError, inst: + if inst.errno != errno.ENOENT: + raise + + def write(self): + '''Write bookmarks + + Write the given bookmark => hash dictionary to the .hg/bookmarks file + in a format equal to those of localtags. + + We also store a backup of the previous state in undo.bookmarks that + can be copied back on rollback. + ''' + repo = self._repo + if repo._bookmarkcurrent not in self: + setcurrent(repo, None) + + wlock = repo.wlock() + try: + + file = repo.vfs('bookmarks', 'w', atomictemp=True) + for name, node in self.iteritems(): + file.write("%s %s\n" % (hex(node), encoding.fromlocal(name))) + file.close() + + # touch 00changelog.i so hgweb reloads bookmarks (no lock needed) try: - bookmarks[refspec] = repo.changelog.lookup(sha) - except LookupError: + os.utime(repo.sjoin('00changelog.i'), None) + except OSError: pass - except IOError, inst: - if inst.errno != errno.ENOENT: - raise - return bookmarks + + finally: + wlock.release() def readcurrent(repo): '''Get the current bookmark @@ -60,37 +100,6 @@ file.close() return mark -def write(repo): - '''Write bookmarks - - Write the given bookmark => hash dictionary to the .hg/bookmarks file - in a format equal to those of localtags. - - We also store a backup of the previous state in undo.bookmarks that - can be copied back on rollback. - ''' - refs = repo._bookmarks - - if repo._bookmarkcurrent not in refs: - setcurrent(repo, None) - - wlock = repo.wlock() - try: - - file = repo.opener('bookmarks', 'w', atomictemp=True) - for refspec, node in refs.iteritems(): - file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec))) - file.close() - - # touch 00changelog.i so hgweb reloads bookmarks (no lock needed) - try: - os.utime(repo.sjoin('00changelog.i'), None) - except OSError: - pass - - finally: - wlock.release() - def setcurrent(repo, mark): '''Set the name of the bookmark that we are currently on @@ -152,7 +161,7 @@ if mark != cur: del marks[mark] if update: - repo._writebookmarks(marks) + marks.write() return update def listbookmarks(repo): @@ -179,7 +188,7 @@ if new not in repo: return False marks[key] = repo[new].node() - write(repo) + marks.write() return True finally: w.release() @@ -188,16 +197,17 @@ ui.debug("checking for updated bookmarks\n") rb = remote.listkeys('bookmarks') changed = False + localmarks = repo._bookmarks for k in rb.keys(): - if k in repo._bookmarks: - nr, nl = rb[k], repo._bookmarks[k] + if k in localmarks: + nr, nl = rb[k], localmarks[k] if nr in repo: cr = repo[nr] cl = repo[nl] if cl.rev() >= cr.rev(): continue if validdest(repo, cl, cr): - repo._bookmarks[k] = cr.node() + localmarks[k] = cr.node() changed = True ui.status(_("updating bookmark %s\n") % k) else: @@ -208,7 +218,7 @@ # find a unique @ suffix for x in range(1, 100): n = '%s@%d' % (kd, x) - if n not in repo._bookmarks: + if n not in localmarks: break # try to use an @pathalias suffix # if an @pathalias already exists, we overwrite (update) it @@ -216,17 +226,17 @@ if path == u: n = '%s@%s' % (kd, p) - repo._bookmarks[n] = cr.node() + localmarks[n] = cr.node() changed = True ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n)) elif rb[k] in repo: # add remote bookmarks for changes we already have - repo._bookmarks[k] = repo[rb[k]].node() + localmarks[k] = repo[rb[k]].node() changed = True ui.status(_("adding remote bookmark %s\n") % k) if changed: - write(repo) + localmarks.write() def diff(ui, dst, src): ui.status(_("searching for changed bookmarks\n")) @@ -263,14 +273,10 @@ while len(validdests) != plen: plen = len(validdests) succs = set(c.node() for c in validdests) - for c in validdests: - if c.phase() > phases.public: - # obsolescence marker does not apply to public changeset - succs.update(obsolete.allsuccessors(repo.obsstore, - [c.node()])) + mutable = [c.node() for c in validdests if c.mutable()] + succs.update(obsolete.allsuccessors(repo.obsstore, mutable)) known = (n for n in succs if n in nm) validdests = set(repo.set('%ln::', known)) - validdests.remove(old) return new in validdests else: return old.descendant(new) diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/bundlerepo.py Thu Nov 29 11:44:22 2012 -0600 @@ -33,6 +33,7 @@ self.basemap = {} n = len(self) chain = None + self.bundlenodes = [] while True: chunkdata = bundle.deltachunk(chain) if not chunkdata: @@ -48,6 +49,7 @@ start = bundle.tell() - size link = linkmapper(cs) + self.bundlenodes.append(node) if node in self.nodemap: # this can happen if two branches make the same change chain = node diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/cmdutil.py Thu Nov 29 11:44:22 2012 -0600 @@ -10,7 +10,7 @@ import os, sys, errno, re, tempfile import util, scmutil, templater, patch, error, templatekw, revlog, copies import match as matchmod -import subrepo, context, repair, bookmarks, graphmod, revset, phases, obsolete +import subrepo, context, repair, graphmod, revset, phases, obsolete import changelog import lock as lockmod @@ -1759,9 +1759,10 @@ # Move bookmarks from old parent to amend commit bms = repo.nodebookmarks(old.node()) if bms: + marks = repo._bookmarks for bm in bms: - repo._bookmarks[bm] = newid - bookmarks.write(repo) + marks[bm] = newid + marks.write() #commit the whole amend process if obsolete._enabled and newid != old.node(): # mark the new changeset as successor of the rewritten one diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/commands.py --- a/mercurial/commands.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/commands.py Thu Nov 29 11:44:22 2012 -0600 @@ -549,6 +549,10 @@ hg bisect --skip hg bisect --skip 23 + - skip all revisions that do not touch directories ``foo`` or ``bar`` + + hg bisect --skip '!( file("path:foo") & file("path:bar") )' + - forget the current bisection:: hg bisect --reset @@ -821,7 +825,7 @@ if mark == repo._bookmarkcurrent: bookmarks.setcurrent(repo, None) del marks[mark] - bookmarks.write(repo) + marks.write() elif rename: if mark is None: @@ -834,7 +838,7 @@ if repo._bookmarkcurrent == rename and not inactive: bookmarks.setcurrent(repo, mark) del marks[rename] - bookmarks.write(repo) + marks.write() elif mark is not None: mark = checkformat(mark) @@ -848,7 +852,7 @@ marks[mark] = cur if not inactive and cur == marks[mark]: bookmarks.setcurrent(repo, mark) - bookmarks.write(repo) + marks.write() # Same message whether trying to deactivate the current bookmark (-i # with no NAME) or listing bookmarks @@ -1322,11 +1326,12 @@ elif marks: ui.debug('moving bookmarks %r from %s to %s\n' % (marks, old.hex(), hex(node))) + newmarks = repo._bookmarks for bm in marks: - repo._bookmarks[bm] = node + newmarks[bm] = node if bm == current: bookmarks.setcurrent(repo, bm) - bookmarks.write(repo) + newmarks.write() else: e = cmdutil.commiteditor if opts.get('force_editor'): @@ -1513,7 +1518,7 @@ ui.progress(_('building'), id, unit=_('revisions'), total=total) for type, data in dagparser.parsedag(text): if type == 'n': - ui.note('node %s\n' % str(data)) + ui.note(('node %s\n' % str(data))) id, ps = data files = [] @@ -1574,10 +1579,10 @@ at = id elif type == 'l': id, name = data - ui.note('tag %s\n' % name) + ui.note(('tag %s\n' % name)) tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name)) elif type == 'a': - ui.note('branch %s\n' % data) + ui.note(('branch %s\n' % data)) atbranch = data ui.progress(_('building'), id, unit=_('revisions'), total=total) tr.close() @@ -1595,7 +1600,7 @@ try: gen = changegroup.readbundle(f, bundlepath) if all: - ui.write("format: id, p1, p2, cset, delta base, len(delta)\n") + ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n")) def showchunks(named): ui.write("\n%s\n" % named) @@ -1787,11 +1792,11 @@ d = util.parsedate(date, util.extendeddateformats) else: d = util.parsedate(date) - ui.write("internal: %s %s\n" % d) - ui.write("standard: %s\n" % util.datestr(d)) + ui.write(("internal: %s %s\n") % d) + ui.write(("standard: %s\n") % util.datestr(d)) if range: m = util.matchdate(range) - ui.write("match: %s\n" % m(d[0])) + ui.write(("match: %s\n") % m(d[0])) @command('debugdiscovery', [('', 'old', None, _('use old-style discovery')), @@ -1821,7 +1826,7 @@ force=True) common = set(common) if not opts.get('nonheads'): - ui.write("unpruned common: %s\n" % " ".join([short(n) + ui.write(("unpruned common: %s\n") % " ".join([short(n) for n in common])) dag = dagutil.revlogdag(repo.changelog) all = dag.ancestorset(dag.internalizeall(common)) @@ -1831,11 +1836,11 @@ common = set(common) rheads = set(hds) lheads = set(repo.heads()) - ui.write("common heads: %s\n" % " ".join([short(n) for n in common])) + ui.write(("common heads: %s\n") % " ".join([short(n) for n in common])) if lheads <= common: - ui.write("local is subset\n") + ui.write(("local is subset\n")) elif rheads <= common: - ui.write("remote is subset\n") + ui.write(("remote is subset\n")) serverlogs = opts.get('serverlog') if serverlogs: @@ -1879,9 +1884,9 @@ def debugfsinfo(ui, path = "."): """show information detected about current filesystem""" util.writefile('.debugfsinfo', '') - ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no')) - ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no')) - ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo') + ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no')) + ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no')) + ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo') and 'yes' or 'no')) os.unlink('.debugfsinfo') @@ -1979,7 +1984,7 @@ r = filelog if not r: r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_) - ui.write("digraph G {\n") + ui.write(("digraph G {\n")) for i in r: node = r.node(i) pp = r.parents(node) @@ -2325,52 +2330,54 @@ def pcfmt(value, total): return (value, 100 * float(value) / total) - ui.write('format : %d\n' % format) - ui.write('flags : %s\n' % ', '.join(flags)) + ui.write(('format : %d\n') % format) + ui.write(('flags : %s\n') % ', '.join(flags)) ui.write('\n') fmt = pcfmtstr(totalsize) fmt2 = dfmtstr(totalsize) - ui.write('revisions : ' + fmt2 % numrevs) - ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs)) - ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)) - ui.write('revisions : ' + fmt2 % numrevs) - ui.write(' full : ' + fmt % pcfmt(numfull, numrevs)) - ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs)) - ui.write('revision size : ' + fmt2 % totalsize) - ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize)) - ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize)) + ui.write(('revisions : ') + fmt2 % numrevs) + ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs)) + ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs)) + ui.write(('revisions : ') + fmt2 % numrevs) + ui.write((' full : ') + fmt % pcfmt(numfull, numrevs)) + ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs)) + ui.write(('revision size : ') + fmt2 % totalsize) + ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize)) + ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize)) ui.write('\n') fmt = dfmtstr(max(avgchainlen, compratio)) - ui.write('avg chain length : ' + fmt % avgchainlen) - ui.write('compression ratio : ' + fmt % compratio) + ui.write(('avg chain length : ') + fmt % avgchainlen) + ui.write(('compression ratio : ') + fmt % compratio) if format > 0: ui.write('\n') - ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n' + ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n') % tuple(datasize)) - ui.write('full revision size (min/max/avg) : %d / %d / %d\n' + ui.write(('full revision size (min/max/avg) : %d / %d / %d\n') % tuple(fullsize)) - ui.write('delta size (min/max/avg) : %d / %d / %d\n' + ui.write(('delta size (min/max/avg) : %d / %d / %d\n') % tuple(deltasize)) if numdeltas > 0: ui.write('\n') fmt = pcfmtstr(numdeltas) fmt2 = pcfmtstr(numdeltas, 4) - ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)) + ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas)) if numprev > 0: - ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, + ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev, numprev)) - ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, + ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev, numprev)) - ui.write(' other : ' + fmt2 % pcfmt(numoprev, + ui.write((' other : ') + fmt2 % pcfmt(numoprev, numprev)) if gdelta: - ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)) - ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)) - ui.write('deltas against other : ' + fmt % pcfmt(numother, + ui.write(('deltas against p1 : ') + + fmt % pcfmt(nump1, numdeltas)) + ui.write(('deltas against p2 : ') + + fmt % pcfmt(nump2, numdeltas)) + ui.write(('deltas against other : ') + fmt % pcfmt(numother, numdeltas)) @command('debugrevspec', [], ('REVSPEC')) @@ -2448,9 +2455,9 @@ def debugsub(ui, repo, rev=None): ctx = scmutil.revsingle(repo, rev, None) for k, v in sorted(ctx.substate.items()): - ui.write('path %s\n' % k) - ui.write(' source %s\n' % v[0]) - ui.write(' revision %s\n' % v[1]) + ui.write(('path %s\n') % k) + ui.write((' source %s\n') % v[0]) + ui.write((' revision %s\n') % v[1]) @command('debugwalk', walkopts, _('[OPTION]... [FILE]...')) def debugwalk(ui, repo, *pats, **opts): @@ -4207,6 +4214,9 @@ Returns 0 on success. """ + + fm = ui.formatter('manifest', opts) + if opts.get('all'): if rev or node: raise util.Abort(_("can't specify a revision with --all")) @@ -4224,7 +4234,9 @@ finally: lock.release() for f in res: - ui.write("%s\n" % f) + fm.startitem() + fm.write("path", '%s\n', f) + fm.end() return if rev and node: @@ -4233,14 +4245,17 @@ if not node: node = rev - decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '} + char = {'l': '@', 'x': '*', '': ''} + mode = {'l': '644', 'x': '755', '': '644'} ctx = scmutil.revsingle(repo, node) + mf = ctx.manifest() for f in ctx: - if ui.debugflag: - ui.write("%40s " % hex(ctx.manifest()[f])) - if ui.verbose: - ui.write(decor[ctx.flags(f)]) - ui.write("%s\n" % f) + fm.startitem() + fl = ctx[f].flags() + fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f])) + fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl]) + fm.write('path', '%s\n', f) + fm.end() @command('^merge', [('f', 'force', None, _('force a merge with outstanding changes')), @@ -4666,11 +4681,12 @@ # update specified bookmarks if opts.get('bookmark'): + marks = repo._bookmarks for b in opts['bookmark']: # explicit pull overrides local bookmark if any ui.status(_("importing bookmark %s\n") % b) - repo._bookmarks[b] = repo[rb[b]].node() - bookmarks.write(repo) + marks[b] = repo[rb[b]].node() + marks.write() return ret @@ -5427,17 +5443,16 @@ copy = copies.pathcopies(repo[node1], repo[node2]) fm = ui.formatter('status', opts) - format = '%s %s' + end - if opts.get('no_status'): - format = '%.0s%s' + end + fmt = '%s' + end + showchar = not opts.get('no_status') for state, char, files in changestates: if state in show: label = 'status.' + state for f in files: fm.startitem() - fm.write("status path", format, char, - repo.pathto(f, cwd), label=label) + fm.condwrite(showchar, 'status', '%s ', char, label=label) + fm.write('path', fmt, repo.pathto(f, cwd), label=label) if f in copy: fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd), label='status.copied') @@ -5743,7 +5758,7 @@ release(lock, wlock) @command('tags', [], '') -def tags(ui, repo): +def tags(ui, repo, **opts): """list repository tags This lists both regular and local tags. When the -v/--verbose @@ -5752,27 +5767,27 @@ Returns 0 on success. """ + fm = ui.formatter('tags', opts) hexfunc = ui.debugflag and hex or short tagtype = "" for t, n in reversed(repo.tagslist()): - if ui.quiet: - ui.write("%s\n" % t, label='tags.normal') - continue - hn = hexfunc(n) - r = "%5d:%s" % (repo.changelog.rev(n), hn) - rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr()) - spaces = " " * (30 - encoding.colwidth(t)) - - tag = ui.label(t, 'tags.normal') - if ui.verbose: - if repo.tagtype(t) == 'local': - tagtype = " local" - tag = ui.label(t, 'tags.local') - else: - tagtype = "" - ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype)) + label = 'tags.normal' + tagtype = '' + if repo.tagtype(t) == 'local': + label = 'tags.local' + tagtype = 'local' + + fm.startitem() + fm.write('tag', '%s', t, label=label) + fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s' + fm.condwrite(not ui.quiet, 'rev id', fmt, + repo.changelog.rev(n), hn, label=label) + fm.condwrite(ui.verbose and tagtype, 'type', ' %s', + tagtype, label=label) + fm.plain('\n') + fm.end() @command('tip', [('p', 'patch', None, _('show patch')), diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/dirstate.py --- a/mercurial/dirstate.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/dirstate.py Thu Nov 29 11:44:22 2012 -0600 @@ -260,7 +260,6 @@ return copies def setbranch(self, branch): - # no repo object here, just check for reserved names self._branch = encoding.fromlocal(branch) f = self._opener('branch', 'w', atomictemp=True) try: diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/formatter.py --- a/mercurial/formatter.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/formatter.py Thu Nov 29 11:44:22 2012 -0600 @@ -31,6 +31,10 @@ '''do default text output while assigning data to item''' for k, v in zip(fields.split(), fielddata): self._item[k] = v + def condwrite(self, cond, fields, deftext, *fielddata, **opts): + '''do conditional write (primarily for plain formatter)''' + for k, v in zip(fields.split(), fielddata): + self._item[k] = v def plain(self, text, **opts): '''show raw text for non-templated mode''' pass @@ -51,6 +55,10 @@ pass def write(self, fields, deftext, *fielddata, **opts): self._ui.write(deftext % fielddata, **opts) + def condwrite(self, cond, fields, deftext, *fielddata, **opts): + '''do conditional write''' + if cond: + self._ui.write(deftext % fielddata, **opts) def plain(self, text, **opts): self._ui.write(text, **opts) def end(self): diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/help/config.txt --- a/mercurial/help/config.txt Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/help/config.txt Thu Nov 29 11:44:22 2012 -0600 @@ -1295,6 +1295,10 @@ (DEPRECATED) Whether to allow .zip downloading of repository revisions. Default is False. This feature creates temporary files. +``archivesubrepos`` + Whether to recurse into subrepositories when archiving. Default is + False. + ``baseurl`` Base URL to use when publishing URLs in other locations, so third-party tools like email notification hooks can construct diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/hg.py --- a/mercurial/hg.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/hg.py Thu Nov 29 11:44:22 2012 -0600 @@ -171,11 +171,14 @@ r = repository(ui, root) default = srcrepo.ui.config('paths', 'default') - if default: - fp = r.opener("hgrc", "w", text=True) - fp.write("[paths]\n") - fp.write("default = %s\n" % default) - fp.close() + if not default: + # set default to source for being able to clone subrepos + default = os.path.abspath(util.urllocalpath(origsource)) + fp = r.opener("hgrc", "w", text=True) + fp.write("[paths]\n") + fp.write("default = %s\n" % default) + fp.close() + r.ui.setconfig('paths', 'default', default) if update: r.ui.status(_("updating working directory\n")) @@ -391,14 +394,15 @@ destrepo = destpeer.local() if destrepo and srcpeer.capable("pushkey"): rb = srcpeer.listkeys('bookmarks') + marks = destrepo._bookmarks for k, n in rb.iteritems(): try: m = destrepo.lookup(n) - destrepo._bookmarks[k] = m + marks[k] = m except error.RepoLookupError: pass if rb: - bookmarks.write(destrepo) + marks.write() elif srcrepo and destpeer.capable("pushkey"): for k, n in srcrepo._bookmarks.iteritems(): destpeer.pushkey('bookmarks', k, '', hex(n)) diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/hgweb/webcommands.py Thu Nov 29 11:44:22 2012 -0600 @@ -14,6 +14,7 @@ from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND from mercurial import graphmod, patch from mercurial import help as helpmod +from mercurial import scmutil from mercurial.i18n import _ # __all__ is populated with the allowed commands. Be sure to add to it if @@ -799,7 +800,11 @@ headers.append(('Content-Encoding', encoding)) req.header(headers) req.respond(HTTP_OK) - archival.archive(web.repo, req, cnode, artype, prefix=name) + + ctx = webutil.changectx(web.repo, req) + archival.archive(web.repo, req, cnode, artype, prefix=name, + matchfn=scmutil.match(ctx, []), + subrepos=web.configbool("web", "archivesubrepos")) return [] diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/localrepo.py --- a/mercurial/localrepo.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/localrepo.py Thu Nov 29 11:44:22 2012 -0600 @@ -265,15 +265,12 @@ @filecache('bookmarks') def _bookmarks(self): - return bookmarks.read(self) + return bookmarks.bmstore(self) @filecache('bookmarks.current') def _bookmarkcurrent(self): return bookmarks.readcurrent(self) - def _writebookmarks(self, marks): - bookmarks.write(self) - def bookmarkheads(self, bookmark): name = bookmark.split('@', 1)[0] heads = [] diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/manifest.py --- a/mercurial/manifest.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/manifest.py Thu Nov 29 11:44:22 2012 -0600 @@ -117,15 +117,23 @@ # apply the changes collected during the bisect loop to our addlist # return a delta suitable for addrevision def addlistdelta(addlist, x): - # start from the bottom up - # so changes to the offsets don't mess things up. - for start, end, content in reversed(x): + # for large addlist arrays, building a new array is cheaper + # than repeatedly modifying the existing one + currentposition = 0 + newaddlist = array.array('c') + + for start, end, content in x: + newaddlist += addlist[currentposition:start] if content: - addlist[start:end] = array.array('c', content) - else: - del addlist[start:end] - return "".join(struct.pack(">lll", start, end, len(content)) + newaddlist += array.array('c', content) + + currentposition = end + + newaddlist += addlist[currentposition:] + + deltatext = "".join(struct.pack(">lll", start, end, len(content)) + content for start, end, content in x) + return deltatext, newaddlist def checkforbidden(l): for f in l: @@ -194,7 +202,8 @@ if dstart is not None: delta.append([dstart, dend, "".join(dline)]) # apply the delta to the addlist, and get a delta for addrevision - cachedelta = (self.rev(p1), addlistdelta(addlist, delta)) + deltatext, addlist = addlistdelta(addlist, delta) + cachedelta = (self.rev(p1), deltatext) arraytext = addlist text = util.buffer(arraytext) diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/mdiff.py --- a/mercurial/mdiff.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/mdiff.py Thu Nov 29 11:44:22 2012 -0600 @@ -7,7 +7,7 @@ from i18n import _ import bdiff, mpatch, util -import re, struct +import re, struct, base85, zlib def splitnewlines(text): '''like str.splitlines, but only split on newlines.''' @@ -142,20 +142,7 @@ yield s, type yield s1, '=' -def diffline(revs, a, b, opts): - parts = ['diff'] - if opts.git: - parts.append('--git') - if revs and not opts.git: - parts.append(' '.join(["-r %s" % rev for rev in revs])) - if opts.git: - parts.append('a/%s' % a) - parts.append('b/%s' % b) - else: - parts.append(a) - return ' '.join(parts) + '\n' - -def unidiff(a, ad, b, bd, fn1, fn2, r=None, opts=defaultopts): +def unidiff(a, ad, b, bd, fn1, fn2, opts=defaultopts): def datetag(date, fn=None): if not opts.git and not opts.nodates: return '\t%s\n' % date @@ -206,9 +193,6 @@ if l[ln][-1] != '\n': l[ln] += "\n\ No newline at end of file\n" - if r: - l.insert(0, diffline(r, fn1, fn2, opts)) - return "".join(l) # creates a headerless unified diff @@ -314,6 +298,41 @@ for x in yieldhunk(hunk): yield x +def b85diff(to, tn): + '''print base85-encoded binary diff''' + def fmtline(line): + l = len(line) + if l <= 26: + l = chr(ord('A') + l - 1) + else: + l = chr(l - 26 + ord('a') - 1) + return '%c%s\n' % (l, base85.b85encode(line, True)) + + def chunk(text, csize=52): + l = len(text) + i = 0 + while i < l: + yield text[i:i + csize] + i += csize + + if to is None: + to = '' + if tn is None: + tn = '' + + if to == tn: + return '' + + # TODO: deltas + ret = [] + ret.append('GIT binary patch\n') + ret.append('literal %s\n' % len(tn)) + for l in chunk(zlib.compress(tn)): + ret.append(fmtline(l)) + ret.append('\n') + + return ''.join(ret) + def patchtext(bin): pos = 0 t = [] diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/patch.py --- a/mercurial/patch.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/patch.py Thu Nov 29 11:44:22 2012 -0600 @@ -6,7 +6,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import cStringIO, email.Parser, os, errno, re +import cStringIO, email.Parser, os, errno, re, posixpath import tempfile, zlib, shutil from i18n import _ @@ -1514,44 +1514,6 @@ finally: fp.close() -def b85diff(to, tn): - '''print base85-encoded binary diff''' - def gitindex(text): - if not text: - return hex(nullid) - l = len(text) - s = util.sha1('blob %d\0' % l) - s.update(text) - return s.hexdigest() - - def fmtline(line): - l = len(line) - if l <= 26: - l = chr(ord('A') + l - 1) - else: - l = chr(l - 26 + ord('a') - 1) - return '%c%s\n' % (l, base85.b85encode(line, True)) - - def chunk(text, csize=52): - l = len(text) - i = 0 - while i < l: - yield text[i:i + csize] - i += csize - - tohash = gitindex(to) - tnhash = gitindex(tn) - if tohash == tnhash: - return "" - - # TODO: deltas - ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' % - (tohash, tnhash, len(tn))] - for l in chunk(zlib.compress(tn)): - ret.append(fmtline(l)) - ret.append('\n') - return ''.join(ret) - class GitDiffRequired(Exception): pass @@ -1622,9 +1584,8 @@ return [] revs = None - if not repo.ui.quiet: - hexfunc = repo.ui.debugflag and hex or short - revs = [hexfunc(node) for node in [node1, node2] if node] + hexfunc = repo.ui.debugflag and hex or short + revs = [hexfunc(node) for node in [node1, node2] if node] copy = {} if opts.git or opts.upgrade: @@ -1690,17 +1651,45 @@ '''like diff(), but yields 2-tuples of (output, label) for ui.write()''' return difflabel(diff, *args, **kw) - -def _addmodehdr(header, omode, nmode): - if omode != nmode: - header.append('old mode %s\n' % omode) - header.append('new mode %s\n' % nmode) - def trydiff(repo, revs, ctx1, ctx2, modified, added, removed, copy, getfilectx, opts, losedatafn, prefix): def join(f): - return os.path.join(prefix, f) + return posixpath.join(prefix, f) + + def addmodehdr(header, omode, nmode): + if omode != nmode: + header.append('old mode %s\n' % omode) + header.append('new mode %s\n' % nmode) + + def addindexmeta(meta, revs): + if opts.git: + i = len(revs) + if i==2: + meta.append('index %s..%s\n' % tuple(revs)) + elif i==3: + meta.append('index %s,%s..%s\n' % tuple(revs)) + + def gitindex(text): + if not text: + return hex(nullid) + l = len(text) + s = util.sha1('blob %d\0' % l) + s.update(text) + return s.hexdigest() + + def diffline(a, b, revs): + if opts.git: + line = 'diff --git a/%s b/%s\n' % (a, b) + elif not repo.ui.quiet: + if revs: + revinfo = ' '.join(["-r %s" % rev for rev in revs]) + line = 'diff %s %s\n' % (revinfo, a) + else: + line = 'diff %s\n' % a + else: + line = '' + return line date1 = util.datestr(ctx1.date()) man1 = ctx1.manifest() @@ -1733,7 +1722,7 @@ else: a = copyto[f] omode = gitmode[man1.flags(a)] - _addmodehdr(header, omode, mode) + addmodehdr(header, omode, mode) if a in removed and a not in gone: op = 'rename' gone.add(a) @@ -1779,22 +1768,24 @@ nflag = ctx2.flags(f) binary = util.binary(to) or util.binary(tn) if opts.git: - _addmodehdr(header, gitmode[oflag], gitmode[nflag]) + addmodehdr(header, gitmode[oflag], gitmode[nflag]) if binary: dodiff = 'binary' elif binary or nflag != oflag: losedatafn(f) - if opts.git: - header.insert(0, mdiff.diffline(revs, join(a), join(b), opts)) if dodiff: + if opts.git or revs: + header.insert(0, diffline(join(a), join(b), revs)) if dodiff == 'binary': - text = b85diff(to, tn) + text = mdiff.b85diff(to, tn) + if text: + addindexmeta(header, [gitindex(to), gitindex(tn)]) else: text = mdiff.unidiff(to, date1, # ctx2 date may be dynamic tn, util.datestr(ctx2.date()), - join(a), join(b), revs, opts=opts) + join(a), join(b), opts=opts) if header and (text or len(header) > 1): yield ''.join(header) if text: diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/repair.py --- a/mercurial/repair.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/repair.py Thu Nov 29 11:44:22 2012 -0600 @@ -6,7 +6,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -from mercurial import changegroup, bookmarks +from mercurial import changegroup from mercurial.node import short from mercurial.i18n import _ import os @@ -181,7 +181,7 @@ for m in updatebm: bm[m] = repo[newbmtarget].node() - bookmarks.write(repo) + bm.write() except: # re-raises if backupfile: ui.warn(_("strip failed, full bundle stored in '%s'\n") diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/revlog.py --- a/mercurial/revlog.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/revlog.py Thu Nov 29 11:44:22 2012 -0600 @@ -257,11 +257,14 @@ return iter(xrange(len(self))) def revs(self, start=0, stop=None): """iterate over all rev in this revlog (from start to stop)""" - if stop is None: - stop = len(self) + step = 1 + if stop is not None: + if start > stop: + step = -1 + stop += step else: - stop += 1 - return xrange(start, stop) + stop = len(self) + return xrange(start, stop, step) @util.propertycache def nodemap(self): @@ -429,6 +432,29 @@ missing.sort() return has, [self.node(r) for r in missing] + def findmissingrevs(self, common=None, heads=None): + """Return the revision numbers of the ancestors of heads that + are not ancestors of common. + + More specifically, return a list of revision numbers corresponding to + nodes N such that every N satisfies the following constraints: + + 1. N is an ancestor of some node in 'heads' + 2. N is not an ancestor of any node in 'common' + + The list is sorted by revision number, meaning it is + topologically sorted. + + 'heads' and 'common' are both lists of revision numbers. If heads is + not supplied, uses all of the revlog's heads. If common is not + supplied, uses nullid.""" + if common is None: + common = [nullrev] + if heads is None: + heads = self.headrevs() + + return ancestor.missingancestors(heads, common, self.parentrevs) + def findmissing(self, common=None, heads=None): """Return the ancestors of heads that are not ancestors of common. @@ -444,8 +470,16 @@ 'heads' and 'common' are both lists of node IDs. If heads is not supplied, uses all of the revlog's heads. If common is not supplied, uses nullid.""" - _common, missing = self.findcommonmissing(common, heads) - return missing + if common is None: + common = [nullid] + if heads is None: + heads = self.heads() + + common = [self.rev(n) for n in common] + heads = [self.rev(n) for n in heads] + + return [self.node(r) for r in + ancestor.missingancestors(heads, common, self.parentrevs)] def nodesbetween(self, roots=None, heads=None): """Return a topological path from 'roots' to 'heads'. diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/revset.py --- a/mercurial/revset.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/revset.py Thu Nov 29 11:44:22 2012 -0600 @@ -442,6 +442,19 @@ bumped = obsmod.getrevs(repo, 'bumped') return [r for r in subset if r in bumped] +def bundle(repo, subset, x): + """``bundle()`` + Changesets in the bundle. + + Bundle must be specified by the -R option.""" + + try: + bundlenodes = repo.changelog.bundlenodes + except AttributeError: + raise util.Abort(_("no bundle provided - specify with -R")) + revs = set(repo[n].rev() for n in bundlenodes) + return [r for r in subset if r in revs] + def checkstatus(repo, subset, pat, field): m = None s = [] @@ -1513,6 +1526,7 @@ "branch": branch, "branchpoint": branchpoint, "bumped": bumped, + "bundle": bundle, "children": children, "closed": closed, "contains": contains, diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/scmutil.py --- a/mercurial/scmutil.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/scmutil.py Thu Nov 29 11:44:22 2012 -0600 @@ -279,37 +279,38 @@ mode += "b" # for that other OS nlink = -1 - dirname, basename = util.split(f) - # If basename is empty, then the path is malformed because it points - # to a directory. Let the posixfile() call below raise IOError. - if basename and mode not in ('r', 'rb'): - if atomictemp: - if not os.path.isdir(dirname): - util.makedirs(dirname, self.createmode) - return util.atomictempfile(f, mode, self.createmode) - try: - if 'w' in mode: - util.unlink(f) + if mode not in ('r', 'rb'): + dirname, basename = util.split(f) + # If basename is empty, then the path is malformed because it points + # to a directory. Let the posixfile() call below raise IOError. + if basename: + if atomictemp: + if not os.path.isdir(dirname): + util.makedirs(dirname, self.createmode) + return util.atomictempfile(f, mode, self.createmode) + try: + if 'w' in mode: + util.unlink(f) + nlink = 0 + else: + # nlinks() may behave differently for files on Windows + # shares if the file is open. + fd = util.posixfile(f) + nlink = util.nlinks(f) + if nlink < 1: + nlink = 2 # force mktempcopy (issue1922) + fd.close() + except (OSError, IOError), e: + if e.errno != errno.ENOENT: + raise nlink = 0 - else: - # nlinks() may behave differently for files on Windows - # shares if the file is open. - fd = util.posixfile(f) - nlink = util.nlinks(f) - if nlink < 1: - nlink = 2 # force mktempcopy (issue1922) - fd.close() - except (OSError, IOError), e: - if e.errno != errno.ENOENT: - raise - nlink = 0 - if not os.path.isdir(dirname): - util.makedirs(dirname, self.createmode) - if nlink > 0: - if self._trustnlink is None: - self._trustnlink = nlink > 1 or util.checknlink(f) - if nlink > 1 or not self._trustnlink: - util.rename(util.mktempcopy(f), f) + if not os.path.isdir(dirname): + util.makedirs(dirname, self.createmode) + if nlink > 0: + if self._trustnlink is None: + self._trustnlink = nlink > 1 or util.checknlink(f) + if nlink > 1 or not self._trustnlink: + util.rename(util.mktempcopy(f), f) fp = util.posixfile(f, mode) if nlink == 0: self._fixfilemode(f) diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/subrepo.py --- a/mercurial/subrepo.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/subrepo.py Thu Nov 29 11:44:22 2012 -0600 @@ -446,7 +446,7 @@ node2 = node.bin(node2) cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts, node1, node2, match, - prefix=os.path.join(prefix, self._path), + prefix=posixpath.join(prefix, self._path), listsubrepos=True, **opts) except error.RepoLookupError, inst: self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n') diff -r 848345a8d6ad -r e8c9b13c7799 mercurial/templater.py --- a/mercurial/templater.py Thu Nov 29 16:37:15 2012 +0100 +++ b/mercurial/templater.py Thu Nov 29 11:44:22 2012 -0600 @@ -8,6 +8,7 @@ from i18n import _ import sys, os, re import util, config, templatefilters, parser, error +import types # template parsing @@ -140,6 +141,10 @@ v = context._defaults.get(key, '') if util.safehasattr(v, '__call__'): return v(**mapping) + if isinstance(v, types.GeneratorType): + v = list(v) + mapping[key] = v + return v return v def buildfilter(exp, context): diff -r 848345a8d6ad -r e8c9b13c7799 setup.py --- a/setup.py Thu Nov 29 16:37:15 2012 +0100 +++ b/setup.py Thu Nov 29 11:44:22 2012 -0600 @@ -151,6 +151,8 @@ if not e.startswith(b('Not trusting file')) \ and not e.startswith(b('warning: Not importing'))] if err: + print >> sys.stderr, "stderr from '%s':" % (' '.join(cmd)) + print >> sys.stderr, '\n'.join([' ' + e for e in err]) return '' return out diff -r 848345a8d6ad -r e8c9b13c7799 tests/autodiff.py --- a/tests/autodiff.py Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/autodiff.py Thu Nov 29 11:44:22 2012 -0600 @@ -35,7 +35,7 @@ for chunk in it: ui.write(chunk) for fn in sorted(brokenfiles): - ui.write('data lost for: %s\n' % fn) + ui.write(('data lost for: %s\n' % fn)) cmdtable = { "autodiff": diff -r 848345a8d6ad -r e8c9b13c7799 tests/run-tests.py --- a/tests/run-tests.py Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/run-tests.py Thu Nov 29 11:44:22 2012 -0600 @@ -55,6 +55,7 @@ import re import threading import killdaemons as killmod +import cPickle as pickle processlock = threading.Lock() @@ -162,6 +163,8 @@ parser.add_option("-p", "--port", type="int", help="port on which servers should listen" " (default: $%s or %d)" % defaults['port']) + parser.add_option("--compiler", type="string", + help="compiler to build with") parser.add_option("--pure", action="store_true", help="use pure Python code instead of C extensions") parser.add_option("-R", "--restart", action="store_true", @@ -175,6 +178,8 @@ parser.add_option("-t", "--timeout", type="int", help="kill errant tests after TIMEOUT seconds" " (default: $%s or %d)" % defaults['timeout']) + parser.add_option("--time", action="store_true", + help="time how long each test takes") parser.add_option("--tmpdir", type="string", help="run tests in the given temporary directory" " (implies --keep-tmpdir)") @@ -263,6 +268,10 @@ sys.stderr.write( 'warning: --timeout option ignored with --debug\n') options.timeout = 0 + if options.time: + sys.stderr.write( + 'warning: --time option ignored with --debug\n') + options.time = False if options.py3k_warnings: if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0): parser.error('--py3k-warnings can only be used on Python 2.6+') @@ -364,6 +373,9 @@ def installhg(options): vlog("# Performing temporary installation of HG") installerrs = os.path.join("tests", "install.err") + compiler = '' + if options.compiler: + compiler = '--compiler ' + options.compiler pure = options.pure and "--pure" or "" # Run installer in hg root @@ -377,12 +389,14 @@ # least on Windows for now, deal with .pydistutils.cfg bugs # when they happen. nohome = '' - cmd = ('%s setup.py %s clean --all' - ' build --build-base="%s"' - ' install --force --prefix="%s" --install-lib="%s"' - ' --install-scripts="%s" %s >%s 2>&1' - % (sys.executable, pure, os.path.join(HGTMP, "build"), - INST, PYTHONDIR, BINDIR, nohome, installerrs)) + cmd = ('%(exe)s setup.py %(pure)s clean --all' + ' build %(compiler)s --build-base="%(base)s"' + ' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"' + ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1' + % dict(exe=sys.executable, pure=pure, compiler=compiler, + base=os.path.join(HGTMP, "build"), + prefix=INST, libdir=PYTHONDIR, bindir=BINDIR, + nohome=nohome, logfile=installerrs)) vlog("# Running", cmd) if os.system(cmd) == 0: if not options.verbose: @@ -447,6 +461,14 @@ fn = os.path.join(INST, '..', '.coverage') os.environ['COVERAGE_FILE'] = fn +def outputtimes(options): + vlog('# Producing time report') + times.sort(key=lambda t: (t[1], t[0]), reverse=True) + cols = '%7.3f %s' + print '\n%-7s %s' % ('Time', 'Test') + for test, timetaken in times: + print cols % (timetaken, test) + def outputcoverage(options): vlog('# Producing coverage report') @@ -891,7 +913,12 @@ replacements.append((re.escape(testtmp), '$TESTTMP')) os.mkdir(testtmp) + if options.time: + starttime = time.time() ret, out = runner(testpath, testtmp, options, replacements) + if options.time: + endtime = time.time() + times.append((test, endtime - starttime)) vlog("# Ret was:", ret) mark = '.' @@ -1056,29 +1083,30 @@ childopts += ['--tmpdir', childtmp] cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job vlog(' '.join(cmdline)) - fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r') + fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'rb') os.close(wfd) signal.signal(signal.SIGINT, signal.SIG_IGN) failures = 0 - tested, skipped, failed = 0, 0, 0 + passed, skipped, failed = 0, 0, 0 skips = [] fails = [] while fps: pid, status = os.wait() fp = fps.pop(pid) - l = fp.read().splitlines() try: - test, skip, fail = map(int, l[:3]) - except ValueError: - test, skip, fail = 0, 0, 0 - split = -fail or len(l) - for s in l[3:split]: - skips.append(s.split(" ", 1)) - for s in l[split:]: - fails.append(s.split(" ", 1)) - tested += test - skipped += skip - failed += fail + childresults = pickle.load(fp) + except pickle.UnpicklingError: + pass + else: + passed += len(childresults['p']) + skipped += len(childresults['s']) + failed += len(childresults['f']) + skips.extend(childresults['s']) + fails.extend(childresults['f']) + if options.time: + childtimes = pickle.load(fp) + times.extend(childtimes) + vlog('pid %d exited, status %d' % (pid, status)) failures |= status print @@ -1093,17 +1121,20 @@ _checkhglib("Tested") print "# Ran %d tests, %d skipped, %d failed." % ( - tested, skipped, failed) + passed + failed, skipped, failed) + if options.time: + outputtimes(options) if options.anycoverage: outputcoverage(options) sys.exit(failures != 0) results = dict(p=[], f=[], s=[], i=[]) resultslock = threading.Lock() +times = [] iolock = threading.Lock() -def runqueue(options, tests, results): +def runqueue(options, tests): for test in tests: ret = runone(options, test) if options.first and ret is not None and not ret: @@ -1129,7 +1160,7 @@ print "running all tests" tests = orig - runqueue(options, tests, results) + runqueue(options, tests) failed = len(results['f']) tested = len(results['p']) + failed @@ -1137,12 +1168,10 @@ ignored = len(results['i']) if options.child: - fp = os.fdopen(options.child, 'w') - fp.write('%d\n%d\n%d\n' % (tested, skipped, failed)) - for s in results['s']: - fp.write("%s %s\n" % s) - for s in results['f']: - fp.write("%s %s\n" % s) + fp = os.fdopen(options.child, 'wb') + pickle.dump(results, fp, pickle.HIGHEST_PROTOCOL) + if options.time: + pickle.dump(times, fp, pickle.HIGHEST_PROTOCOL) fp.close() else: print @@ -1153,6 +1182,8 @@ _checkhglib("Tested") print "# Ran %d tests, %d skipped, %d failed." % ( tested, skipped + ignored, failed) + if options.time: + outputtimes(options) if options.anycoverage: outputcoverage(options) @@ -1170,9 +1201,9 @@ checktools() - if len(args) == 0: - args = os.listdir(".") - args.sort() + if len(args) == 0: + args = os.listdir(".") + args.sort() tests = args diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-bundle.t --- a/tests/test-bundle.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-bundle.t Thu Nov 29 11:44:22 2012 -0600 @@ -444,6 +444,33 @@ added 1 changesets with 1 changes to 1 files 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +View full contents of the bundle + $ hg -R test bundle --base null -r 3 ../partial.hg + 4 changesets found + $ cd test + $ hg -R ../../partial.hg log -r "bundle()" + changeset: 0:f9ee2f85a263 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: 0.0 + + changeset: 1:34c2bf6b0626 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: 0.1 + + changeset: 2:e38ba6f5b7e0 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: 0.2 + + changeset: 3:eebf5a27f8ca + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: 0.3 + + $ cd .. + test for 540d1059c802 test for 540d1059c802 diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-check-code-hg.t --- a/tests/test-check-code-hg.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-check-code-hg.t Thu Nov 29 11:44:22 2012 -0600 @@ -5,163 +5,7 @@ > echo "skipped: not a Mercurial working dir" >&2 > exit 80 > fi - $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!' - $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true - hgext/convert/cvsps.py:0: - > ui.write('Ancestors: %s\n' % (','.join(r))) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Parent: %d\n' % cs.parents[0].id) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Parents: %s\n' % - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints)) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Author: %s\n' % cs.author) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Branch: %s\n' % (cs.branch or 'HEAD')) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Date: %s\n' % util.datestr(cs.date, - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Log:\n') - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Members: \n') - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('PatchSet %d \n' % cs.id) - warning: unwrapped ui message - hgext/convert/cvsps.py:0: - > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1], - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("parent %s\n" % p) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write('k=%s\nv=%s\n' % (name, value)) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1])) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("branch %s\n\n" % ctx.branch()) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1])) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("revision %d\n" % ctx.rev()) - warning: unwrapped ui message - hgext/hgk.py:0: - > ui.write("tree %s\n" % short(ctx.changeset()[0])) - warning: unwrapped ui message - hgext/patchbomb.py:0: - > ui.write('Subject: %s\n' % subj) - warning: unwrapped ui message - hgext/patchbomb.py:0: - > ui.write('From: %s\n' % sender) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.note('branch %s\n' % data) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.note('node %s\n' % str(data)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.note('tag %s\n' % name) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("unpruned common: %s\n" % " ".join([short(n) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n") - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("local is subset\n") - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("remote is subset\n") - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('deltas against other : ' + fmt % pcfmt(numother, - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("common heads: %s\n" % " ".join([short(n) for n in common])) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("match: %s\n" % m(d[0])) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('path %s\n' % k) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n' - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("digraph G {\n") - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("internal: %s %s\n" % d) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write("standard: %s\n" % util.datestr(d)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('avg chain length : ' + fmt % avgchainlen) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo') - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('compression ratio : ' + fmt % compratio) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('delta size (min/max/avg) : %d / %d / %d\n' - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no')) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('flags : %s\n' % ', '.join(flags)) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('format : %d\n' % format) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('full revision size (min/max/avg) : %d / %d / %d\n' - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('revision size : ' + fmt2 % totalsize) - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('revisions : ' + fmt2 % numrevs) - warning: unwrapped ui message - warning: unwrapped ui message - mercurial/commands.py:0: - > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no')) - warning: unwrapped ui message - tests/autodiff.py:0: - > ui.write('data lost for: %s\n' % fn) - warning: unwrapped ui message - tests/test-ui-color.py:0: - > testui.warn('warning\n') - warning: unwrapped ui message - tests/test-ui-color.py:0: - > testui.write('buffered\n') - warning: unwrapped ui message +New errors are not allowed. Warnings are strongly discouraged. + + $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-convert-cvs.t --- a/tests/test-convert-cvs.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-convert-cvs.t Thu Nov 29 11:44:22 2012 -0600 @@ -69,9 +69,16 @@ $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob) $ cd .. -convert fresh repo +convert fresh repo and also check localtimezone option + +NOTE: This doesn't check all time zones -- it merely determines that +the configuration option is taking effect. - $ hg convert src src-hg +An arbitrary (U.S.) time zone is used here. TZ=US/Hawaii is selected +since it does not use DST (unlike other U.S. time zones) and is always +a fixed difference from UTC. + + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True src src-hg initializing destination src-hg repository connecting to $TESTTMP/cvsrepo scanning source... @@ -161,7 +168,7 @@ convert again - $ hg convert src src-hg + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True src src-hg connecting to $TESTTMP/cvsrepo scanning source... collecting CVS rlog @@ -221,7 +228,7 @@ convert again - $ hg convert src src-hg + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True src src-hg connecting to $TESTTMP/cvsrepo scanning source... collecting CVS rlog @@ -239,7 +246,7 @@ convert again with --filemap - $ hg convert --filemap filemap src src-filemap + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True --filemap filemap src src-filemap connecting to $TESTTMP/cvsrepo scanning source... collecting CVS rlog @@ -286,7 +293,7 @@ convert again - $ hg convert --config convert.cvsps.fuzz=2 src src-hg + $ TZ=US/Hawaii hg convert --config convert.cvsps.fuzz=2 --config convert.localtimezone=True src src-hg connecting to $TESTTMP/cvsrepo scanning source... collecting CVS rlog @@ -300,25 +307,25 @@ 2 funny 1 fuzzy 0 fuzzy - $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n' - o 8 (branch) fuzzy files: b/c + $ hg -R src-hg glog --template '{rev} ({branches}) {desc} date: {date|date} files: {files}\n' + o 8 (branch) fuzzy date: * -1000 files: b/c (glob) | - o 7 (branch) fuzzy files: a + o 7 (branch) fuzzy date: * -1000 files: a (glob) | o 6 (branch) funny | ---------------------------- - | log message files: a - o 5 (branch) ci2 files: b/c + | log message date: * -1000 files: a (glob) + o 5 (branch) ci2 date: * -1000 files: b/c (glob) - o 4 () ci1 files: a b/c + o 4 () ci1 date: * -1000 files: a b/c (glob) | - o 3 () update tags files: .hgtags + o 3 () update tags date: * +0000 files: .hgtags (glob) | - o 2 () ci0 files: b/c + o 2 () ci0 date: * -1000 files: b/c (glob) | - | o 1 (INITIAL) import files: + | o 1 (INITIAL) import date: * -1000 files: (glob) |/ - o 0 () Initial revision files: a b/c + o 0 () Initial revision date: * -1000 files: a b/c (glob) testing debugcvsps diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-convert-git.t --- a/tests/test-convert-git.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-convert-git.t Thu Nov 29 11:44:22 2012 -0600 @@ -298,3 +298,50 @@ $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \ > grep 'abort:' | sed 's/abort:.*/abort:/g' abort: + +test sub modules + + $ mkdir git-repo5 + $ cd git-repo5 + $ git init-db >/dev/null 2>/dev/null + $ echo 'sub' >> foo + $ git add foo + $ commit -a -m 'addfoo' + $ BASE=${PWD} + $ cd .. + $ mkdir git-repo6 + $ cd git-repo6 + $ git init-db >/dev/null 2>/dev/null + $ git submodule add ${BASE} >/dev/null 2>/dev/null + $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null + $ cd .. + +convert sub modules + $ hg convert git-repo6 git-repo6-hg + initializing destination git-repo6-hg repository + scanning source... + sorting... + converting... + 0 addsubmodule + updating bookmarks + $ hg -R git-repo6-hg log -v + changeset: 0:* (glob) + bookmark: master + tag: tip + user: nottest + date: Mon Jan 01 00:00:23 2007 +0000 + files: .hgsub .hgsubstate + description: + addsubmodule + + committer: test + + + + $ cd git-repo6-hg + $ hg up >/dev/null 2>/dev/null + $ cat .hgsubstate + * git-repo5 (glob) + $ cd git-repo5 + $ cat foo + sub diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-convert-svn-source.t --- a/tests/test-convert-svn-source.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-convert-svn-source.t Thu Nov 29 11:44:22 2012 -0600 @@ -63,9 +63,16 @@ Committed revision 5. $ cd .. -Convert to hg once +Convert to hg once and also test localtimezone option + +NOTE: This doesn't check all time zones -- it merely determines that +the configuration option is taking effect. - $ hg convert "$SVNREPOURL/proj%20B" B-hg +An arbitrary (U.S.) time zone is used here. TZ=US/Hawaii is selected +since it does not use DST (unlike other U.S. time zones) and is always +a fixed difference from UTC. + + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True "$SVNREPOURL/proj%20B" B-hg initializing destination B-hg repository scanning source... sorting... @@ -109,7 +116,7 @@ Test incremental conversion - $ hg convert "$SVNREPOURL/proj%20B" B-hg + $ TZ=US/Hawaii hg convert --config convert.localtimezone=True "$SVNREPOURL/proj%20B" B-hg scanning source... sorting... converting... @@ -118,22 +125,22 @@ updating tags $ cd B-hg - $ hg glog --template '{rev} {desc|firstline} files: {files}\n' - o 7 update tags files: .hgtags + $ hg glog --template '{rev} {desc|firstline} date: {date|date} files: {files}\n' + o 7 update tags date: * +0000 files: .hgtags (glob) | - o 6 work in progress files: letter2.txt + o 6 work in progress date: * -1000 files: letter2.txt (glob) | - o 5 second letter files: letter .txt letter2.txt + o 5 second letter date: * -1000 files: letter .txt letter2.txt (glob) | - o 4 update tags files: .hgtags + o 4 update tags date: * +0000 files: .hgtags (glob) | - o 3 nice day files: letter .txt + o 3 nice day date: * -1000 files: letter .txt (glob) | - o 2 world files: letter .txt + o 2 world date: * -1000 files: letter .txt (glob) | - o 1 hello files: letter .txt + o 1 hello date: * -1000 files: letter .txt (glob) | - o 0 init projB files: + o 0 init projB date: * -1000 files: (glob) $ hg tags -q tip diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-convert.t --- a/tests/test-convert.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-convert.t Thu Nov 29 11:44:22 2012 -0600 @@ -172,6 +172,10 @@ will add the most recent revision on the branch indicated in the regex as the second parent of the changeset. Default is "{{mergefrombranch ([-\w]+)}}" + convert.localtimezone + use local time (as determined by the TZ environment + variable) for changeset date/times. The default is False + (use UTC). hook.cvslog Specify a Python function to be called at the end of gathering the CVS log. The function is passed a list with the log entries, and can modify the entries in-place, or add @@ -211,6 +215,10 @@ convert.svn.trunk specify the name of the trunk branch. The default is "trunk". + convert.localtimezone + use local time (as determined by the TZ environment + variable) for changeset date/times. The default is False + (use UTC). Source history can be retrieved starting at a specific revision, instead of being integrally converted. Only single branch conversions are diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-eolfilename.t --- a/tests/test-eolfilename.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-eolfilename.t Thu Nov 29 11:44:22 2012 -0600 @@ -68,9 +68,9 @@ $ touch "$A" $ touch "$B" $ hg status --color=always - \x1b[0;35;1;4m? foo\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc) \x1b[0;35;1;4mbar\x1b[0m (esc) - \x1b[0;35;1;4m? foo\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc) \x1b[0;35;1;4mbar.baz\x1b[0m (esc) $ cd .. diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-hgk.t --- a/tests/test-hgk.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-hgk.t Thu Nov 29 11:44:22 2012 -0600 @@ -11,7 +11,6 @@ tree a0c8bcbbb45c parent 000000000000 author test 0 0 - committer test 0 0 revision 0 branch default diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-mq-qrefresh.t --- a/tests/test-mq-qrefresh.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-mq-qrefresh.t Thu Nov 29 11:44:22 2012 -0600 @@ -209,6 +209,7 @@ $ hg add orphanchild $ hg qrefresh nonexistentfilename # clear patch nonexistentfilename: * (glob) + $ hg diff -c qtip $ hg qrefresh --short 1/base $ hg qrefresh --short 2/base diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-mq.t --- a/tests/test-mq.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-mq.t Thu Nov 29 11:44:22 2012 -0600 @@ -198,11 +198,11 @@ status --mq with color (issue2096) $ hg status --mq --config extensions.color= --config color.mode=ansi --color=always - \x1b[0;32;1mA .hgignore\x1b[0m (esc) - \x1b[0;32;1mA A\x1b[0m (esc) - \x1b[0;32;1mA B\x1b[0m (esc) - \x1b[0;32;1mA series\x1b[0m (esc) - \x1b[0;35;1;4m? flaf\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1m.hgignore\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mA\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mB\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mseries\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mflaf\x1b[0m (esc) try the --mq option on a command provided by an extension diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-pathencode.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-pathencode.py Thu Nov 29 11:44:22 2012 -0600 @@ -0,0 +1,193 @@ +# This is a randomized test that generates different pathnames every +# time it is invoked, and tests the encoding of those pathnames. +# +# It uses a simple probabilistic model to generate valid pathnames +# that have proven likely to expose bugs and divergent behaviour in +# different encoding implementations. + +from mercurial import parsers +from mercurial import store +import binascii, itertools, math, os, random, sys, time +import collections + +if sys.version_info[:2] < (2, 6): + sys.exit(0) + +def hybridencode(path): + return store._hybridencode(path, True) + +validchars = set(map(chr, range(0, 256))) +alphanum = range(ord('A'), ord('Z')) + +for c in '\0/': + validchars.remove(c) + +winreserved = ('aux con prn nul'.split() + + ['com%d' % i for i in xrange(1, 10)] + + ['lpt%d' % i for i in xrange(1, 10)]) + +def casecombinations(names): + '''Build all case-diddled combinations of names.''' + + combos = set() + + for r in names: + for i in xrange(len(r) + 1): + for c in itertools.combinations(xrange(len(r)), i): + d = r + for j in c: + d = ''.join((d[:j], d[j].upper(), d[j + 1:])) + combos.add(d) + return sorted(combos) + +def buildprobtable(fp, cmd='hg manifest tip'): + '''Construct and print a table of probabilities for path name + components. The numbers are percentages.''' + + counts = collections.defaultdict(lambda: 0) + for line in os.popen(cmd).read().splitlines(): + if line[-2:] in ('.i', '.d'): + line = line[:-2] + if line.startswith('data/'): + line = line[5:] + for c in line: + counts[c] += 1 + for c in '\r/\n': + counts.pop(c, None) + t = sum(counts.itervalues()) / 100.0 + fp.write('probtable = (') + for i, (k, v) in enumerate(sorted(counts.iteritems(), key=lambda x: x[1], + reverse=True)): + if (i % 5) == 0: + fp.write('\n ') + vt = v / t + if vt < 0.0005: + break + fp.write('(%r, %.03f), ' % (k, vt)) + fp.write('\n )\n') + +# A table of character frequencies (as percentages), gleaned by +# looking at filelog names from a real-world, very large repo. + +probtable = ( + ('t', 9.828), ('e', 9.042), ('s', 8.011), ('a', 6.801), ('i', 6.618), + ('g', 5.053), ('r', 5.030), ('o', 4.887), ('p', 4.363), ('n', 4.258), + ('l', 3.830), ('h', 3.693), ('_', 3.659), ('.', 3.377), ('m', 3.194), + ('u', 2.364), ('d', 2.296), ('c', 2.163), ('b', 1.739), ('f', 1.625), + ('6', 0.666), ('j', 0.610), ('y', 0.554), ('x', 0.487), ('w', 0.477), + ('k', 0.476), ('v', 0.473), ('3', 0.336), ('1', 0.335), ('2', 0.326), + ('4', 0.310), ('5', 0.305), ('9', 0.302), ('8', 0.300), ('7', 0.299), + ('q', 0.298), ('0', 0.250), ('z', 0.223), ('-', 0.118), ('C', 0.095), + ('T', 0.087), ('F', 0.085), ('B', 0.077), ('S', 0.076), ('P', 0.076), + ('L', 0.059), ('A', 0.058), ('N', 0.051), ('D', 0.049), ('M', 0.046), + ('E', 0.039), ('I', 0.035), ('R', 0.035), ('G', 0.028), ('U', 0.026), + ('W', 0.025), ('O', 0.017), ('V', 0.015), ('H', 0.013), ('Q', 0.011), + ('J', 0.007), ('K', 0.005), ('+', 0.004), ('X', 0.003), ('Y', 0.001), + ) + +for c, _ in probtable: + validchars.remove(c) +validchars = list(validchars) + +def pickfrom(rng, table): + c = 0 + r = rng.random() * sum(i[1] for i in table) + for i, p in table: + c += p + if c >= r: + return i + +reservedcombos = casecombinations(winreserved) + +# The first component of a name following a slash. + +firsttable = ( + (lambda rng: pickfrom(rng, probtable), 90), + (lambda rng: rng.choice(validchars), 5), + (lambda rng: rng.choice(reservedcombos), 5), + ) + +# Components of a name following the first. + +resttable = firsttable[:-1] + +# Special suffixes. + +internalsuffixcombos = casecombinations('.hg .i .d'.split()) + +# The last component of a path, before a slash or at the end of a name. + +lasttable = resttable + ( + (lambda rng: '', 95), + (lambda rng: rng.choice(internalsuffixcombos), 5), + ) + +def makepart(rng, k): + '''Construct a part of a pathname, without slashes.''' + + p = pickfrom(rng, firsttable)(rng) + l = len(p) + ps = [p] + while l <= k: + p = pickfrom(rng, resttable)(rng) + l += len(p) + ps.append(p) + ps.append(pickfrom(rng, lasttable)(rng)) + return ''.join(ps) + +def makepath(rng, j, k): + '''Construct a complete pathname.''' + + return ('data/' + '/'.join(makepart(rng, k) for _ in xrange(j)) + + rng.choice(['.d', '.i'])) + +def genpath(rng, count): + '''Generate random pathnames with gradually increasing lengths.''' + + mink, maxk = 1, 4096 + def steps(): + x, k = 0, mink + for i in xrange(count): + yield mink + int(round(math.sqrt((maxk - mink) * float(i) / count))) + for k in steps(): + x = rng.randint(1, k) + y = rng.randint(1, k) + yield makepath(rng, x, y) + +def runtests(rng, seed, count): + nerrs = 0 + for p in genpath(rng, count): + hybridencode(p) + return nerrs + +def main(): + import getopt + + # Empirically observed to take about a second to run + count = 100 + seed = None + opts, args = getopt.getopt(sys.argv[1:], 'c:s:', + ['build', 'count=', 'seed=']) + for o, a in opts: + if o in ('-c', '--count'): + count = int(a) + elif o in ('-s', '--seed'): + seed = long(a) + elif o == '--build': + buildprobtable(sys.stdout, + 'find .hg/store/data -type f && ' + 'cat .hg/store/fncache 2>/dev/null') + sys.exit(0) + + if seed is None: + try: + seed = long(binascii.hexlify(os.urandom(16)), 16) + except AttributeError: + seed = long(time.time() * 1000) + + rng = random.Random(seed) + if runtests(rng, seed, count): + sys.exit(1) + +if __name__ == '__main__': + main() diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-status-color.t --- a/tests/test-status-color.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-status-color.t Thu Nov 29 11:44:22 2012 -0600 @@ -15,100 +15,100 @@ hg status in repo root: $ hg status --color=always - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) hg status . in repo root: $ hg status --color=always . - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd a - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd a . - \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc) $ hg status --color=always --cwd a .. - \x1b[0;35;1;4m? 1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? in_a\x1b[0m (esc) - \x1b[0;35;1;4m? ../b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? ../b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? ../b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? ../in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../b/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc) $ hg status --color=always --cwd b - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd b . - \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc) $ hg status --color=always --cwd b .. - \x1b[0;35;1;4m? ../a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? ../a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? 1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? 2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? in_b\x1b[0m (esc) - \x1b[0;35;1;4m? ../in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../a/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_root\x1b[0m (esc) $ hg status --color=always --cwd a/1 - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd a/1 . - \x1b[0;35;1;4m? in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc) $ hg status --color=always --cwd a/1 .. - \x1b[0;35;1;4m? in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? ../in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_a\x1b[0m (esc) $ hg status --color=always --cwd b/1 - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd b/1 . - \x1b[0;35;1;4m? in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc) $ hg status --color=always --cwd b/1 .. - \x1b[0;35;1;4m? in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? ../2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? ../in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc) $ hg status --color=always --cwd b/2 - \x1b[0;35;1;4m? a/1/in_a_1\x1b[0m (esc) - \x1b[0;35;1;4m? a/in_a\x1b[0m (esc) - \x1b[0;35;1;4m? b/1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? b/2/in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? b/in_b\x1b[0m (esc) - \x1b[0;35;1;4m? in_root\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/1/in_a_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4ma/in_a\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/2/in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) $ hg status --color=always --cwd b/2 . - \x1b[0;35;1;4m? in_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc) $ hg status --color=always --cwd b/2 .. - \x1b[0;35;1;4m? ../1/in_b_1\x1b[0m (esc) - \x1b[0;35;1;4m? in_b_2\x1b[0m (esc) - \x1b[0;35;1;4m? ../in_b\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../1/in_b_1\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_b_2\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4m../in_b\x1b[0m (esc) $ cd .. $ hg init repo2 @@ -128,59 +128,59 @@ hg status: $ hg status --color=always - \x1b[0;32;1mA added\x1b[0m (esc) - \x1b[0;31;1mR removed\x1b[0m (esc) - \x1b[0;36;1;4m! deleted\x1b[0m (esc) - \x1b[0;35;1;4m? unknown\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc) + \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc) + \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc) hg status modified added removed deleted unknown never-existed ignored: $ hg status --color=always modified added removed deleted unknown never-existed ignored never-existed: * (glob) - \x1b[0;32;1mA added\x1b[0m (esc) - \x1b[0;31;1mR removed\x1b[0m (esc) - \x1b[0;36;1;4m! deleted\x1b[0m (esc) - \x1b[0;35;1;4m? unknown\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc) + \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc) + \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc) $ hg copy modified copied hg status -C: $ hg status --color=always -C - \x1b[0;32;1mA added\x1b[0m (esc) - \x1b[0;32;1mA copied\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc) \x1b[0;0m modified\x1b[0m (esc) - \x1b[0;31;1mR removed\x1b[0m (esc) - \x1b[0;36;1;4m! deleted\x1b[0m (esc) - \x1b[0;35;1;4m? unknown\x1b[0m (esc) + \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc) + \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc) hg status -A: $ hg status --color=always -A - \x1b[0;32;1mA added\x1b[0m (esc) - \x1b[0;32;1mA copied\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc) \x1b[0;0m modified\x1b[0m (esc) - \x1b[0;31;1mR removed\x1b[0m (esc) - \x1b[0;36;1;4m! deleted\x1b[0m (esc) - \x1b[0;35;1;4m? unknown\x1b[0m (esc) - \x1b[0;30;1mI ignored\x1b[0m (esc) - \x1b[0;0mC .hgignore\x1b[0m (esc) - \x1b[0;0mC modified\x1b[0m (esc) + \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc) + \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc) + \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignored\x1b[0m (esc) + \x1b[0;0mC \x1b[0m\x1b[0;0m.hgignore\x1b[0m (esc) + \x1b[0;0mC \x1b[0m\x1b[0;0mmodified\x1b[0m (esc) hg status -A (with terminfo color): $ mkdir "$TESTTMP/terminfo" $ TERMINFO="$TESTTMP/terminfo" tic "$TESTDIR/hgterm.ti" $ TERM=hgterm TERMINFO="$TESTTMP/terminfo" hg status --config color.mode=terminfo --color=always -A - \x1b[30m\x1b[32m\x1b[1mA added\x1b[30m (esc) - \x1b[30m\x1b[32m\x1b[1mA copied\x1b[30m (esc) + \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1madded\x1b[30m (esc) + \x1b[30m\x1b[32m\x1b[1mA \x1b[30m\x1b[30m\x1b[32m\x1b[1mcopied\x1b[30m (esc) \x1b[30m\x1b[30m modified\x1b[30m (esc) - \x1b[30m\x1b[31m\x1b[1mR removed\x1b[30m (esc) - \x1b[30m\x1b[36m\x1b[1m\x1b[4m! deleted\x1b[30m (esc) - \x1b[30m\x1b[35m\x1b[1m\x1b[4m? unknown\x1b[30m (esc) - \x1b[30m\x1b[30m\x1b[1mI ignored\x1b[30m (esc) - \x1b[30m\x1b[30mC .hgignore\x1b[30m (esc) - \x1b[30m\x1b[30mC modified\x1b[30m (esc) + \x1b[30m\x1b[31m\x1b[1mR \x1b[30m\x1b[30m\x1b[31m\x1b[1mremoved\x1b[30m (esc) + \x1b[30m\x1b[36m\x1b[1m\x1b[4m! \x1b[30m\x1b[30m\x1b[36m\x1b[1m\x1b[4mdeleted\x1b[30m (esc) + \x1b[30m\x1b[35m\x1b[1m\x1b[4m? \x1b[30m\x1b[30m\x1b[35m\x1b[1m\x1b[4munknown\x1b[30m (esc) + \x1b[30m\x1b[30m\x1b[1mI \x1b[30m\x1b[30m\x1b[30m\x1b[1mignored\x1b[30m (esc) + \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30m.hgignore\x1b[30m (esc) + \x1b[30m\x1b[30mC \x1b[30m\x1b[30m\x1b[30mmodified\x1b[30m (esc) $ echo "^ignoreddir$" > .hgignore @@ -194,7 +194,7 @@ hg status -i ignoreddir/file: $ hg status --color=always -i ignoreddir/file - \x1b[0;30;1mI ignoreddir/file\x1b[0m (esc) + \x1b[0;30;1mI \x1b[0m\x1b[0;30;1mignoreddir/file\x1b[0m (esc) $ cd .. check 'status -q' and some combinations @@ -220,11 +220,11 @@ $ hg --config color.status.modified=periwinkle status --color=always ignoring unknown color/effect 'periwinkle' (configured in color.status.modified) M modified - \x1b[0;32;1mA added\x1b[0m (esc) - \x1b[0;32;1mA copied\x1b[0m (esc) - \x1b[0;31;1mR removed\x1b[0m (esc) - \x1b[0;36;1;4m! deleted\x1b[0m (esc) - \x1b[0;35;1;4m? unknown\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1madded\x1b[0m (esc) + \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mcopied\x1b[0m (esc) + \x1b[0;31;1mR \x1b[0m\x1b[0;31;1mremoved\x1b[0m (esc) + \x1b[0;36;1;4m! \x1b[0m\x1b[0;36;1;4mdeleted\x1b[0m (esc) + \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4munknown\x1b[0m (esc) Run status with 2 different flags. Check if result is the same or different. diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-subrepo.t --- a/tests/test-subrepo.t Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-subrepo.t Thu Nov 29 11:44:22 2012 -0600 @@ -718,6 +718,14 @@ committing subrepository subrepo-2 $ hg st subrepo-2/file +Check that share works with subrepo + $ hg --config extensions.share= share . ../shared + updating working directory + cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2 + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ test -f ../shared/subrepo-1/.hg/sharedpath + [1] + Check hg update --clean $ cd $TESTTMP/t $ rm -r t/t.orig diff -r 848345a8d6ad -r e8c9b13c7799 tests/test-ui-color.py --- a/tests/test-ui-color.py Thu Nov 29 16:37:15 2012 +0100 +++ b/tests/test-ui-color.py Thu Nov 29 11:44:22 2012 -0600 @@ -5,8 +5,8 @@ # ensure errors aren't buffered testui = color.colorui() testui.pushbuffer() -testui.write('buffered\n') -testui.warn('warning\n') +testui.write(('buffered\n')) +testui.warn(('warning\n')) testui.write_err('error\n') print repr(testui.popbuffer())