# HG changeset patch # User Bryan O'Sullivan # Date 1202356672 28800 # Node ID 2da5b19a6460ef6b31c24eeb813a37d461a44444 # Parent dd714452c26e974fe650487bf1f7cc510eb63f6e# Parent dd3267698d84458686b3c5682ce027438900ffbd Merge with crew diff -r dd714452c26e -r 2da5b19a6460 .hgignore --- a/.hgignore Thu Jul 26 07:56:27 2007 -0400 +++ b/.hgignore Wed Feb 06 19:57:52 2008 -0800 @@ -4,6 +4,7 @@ *.orig *.rej *~ +*.mergebackup *.o *.so *.pyc @@ -21,8 +22,10 @@ MANIFEST patches mercurial/__version__.py +Output/Mercurial-*.exe .DS_Store +tags +cscope.* syntax: regexp ^\.pc/ -Output/Mercurial-[0-9.]*.exe diff -r dd714452c26e -r 2da5b19a6460 .hgsigs --- a/.hgsigs Thu Jul 26 07:56:27 2007 -0400 +++ b/.hgsigs Wed Feb 06 19:57:52 2008 -0800 @@ -3,3 +3,4 @@ 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys= 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4= fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I= +23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU= diff -r dd714452c26e -r 2da5b19a6460 .hgtags --- a/.hgtags Thu Jul 26 07:56:27 2007 -0400 +++ b/.hgtags Wed Feb 06 19:57:52 2008 -0800 @@ -15,3 +15,4 @@ 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4 +23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5 diff -r dd714452c26e -r 2da5b19a6460 CONTRIBUTORS --- a/CONTRIBUTORS Thu Jul 26 07:56:27 2007 -0400 +++ b/CONTRIBUTORS Wed Feb 06 19:57:52 2008 -0800 @@ -1,4 +1,7 @@ -Andrea Arcangeli +[This file is here for historical purposes, all recent contributors +should appear in the changelog directly] + +Andrea Arcangeli Thomas Arendsen Hein Goffredo Baroncelli Muli Ben-Yehuda @@ -36,5 +39,3 @@ Rafael Villar Burke Tristan Wibberley Mark Williamson - -If you are a contributor and don't see your name here, please let me know. diff -r dd714452c26e -r 2da5b19a6460 contrib/bash_completion --- a/contrib/bash_completion Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/bash_completion Wed Feb 06 19:57:52 2008 -0800 @@ -28,7 +28,7 @@ # cat ~/.patchbomb-$1 # fi # } -# +# # # Writing completion functions for additional commands: # @@ -50,7 +50,7 @@ # an argument (e.g. '--cwd|-R|--repository') # - $canonical - 1 if we canonicalized $cmd before calling the function # 0 otherwise -# +# shopt -s extglob @@ -305,6 +305,15 @@ _hg_ext_mq_patchlist qunapplied } +_hg_cmd_qgoto() +{ + if [[ "$prev" = @(-n|--name) ]]; then + _hg_ext_mq_queues + return + fi + _hg_ext_mq_patchlist qseries +} + _hg_cmd_qdelete() { local qcmd=qunapplied @@ -425,7 +434,7 @@ done if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then - COMPREPLY=(${COMPREPLY[@]:-} + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W 'bad good help init next reset' -- "$cur")) return fi @@ -445,7 +454,7 @@ { case "$prev" in -c|--cc|-t|--to|-f|--from|--bcc) - # we need an e-mail address. let the user provide a function + # we need an e-mail address. let the user provide a function # to get them if [ "$(type -t _hg_emails)" = function ]; then local arg=to diff -r dd714452c26e -r 2da5b19a6460 contrib/churn.py --- a/contrib/churn.py Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/churn.py Wed Feb 06 19:57:52 2008 -0800 @@ -12,7 +12,7 @@ # from mercurial.i18n import gettext as _ -from mercurial import hg, mdiff, cmdutil, ui, util, templater, node +from mercurial import hg, mdiff, cmdutil, ui, util, templatefilters, node import os, sys def get_tty_width(): @@ -22,20 +22,16 @@ except ValueError: pass try: - import termios, fcntl, struct - buf = 'abcd' + import termios, array, fcntl for dev in (sys.stdout, sys.stdin): try: - if buf != 'abcd': - break fd = dev.fileno() if not os.isatty(fd): continue - buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf) + arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8) + return array.array('h', arri)[1] except ValueError: pass - if buf != 'abcd': - return struct.unpack('hh', buf)[1] except ImportError: pass return 80 @@ -47,7 +43,7 @@ to = mmap1 and repo.file(f).read(mmap1[f]) or None tn = mmap2 and repo.file(f).read(mmap2[f]) or None - diff = mdiff.unidiff(to, "", tn, "", f).split("\n") + diff = mdiff.unidiff(to, "", tn, "", f, f).split("\n") for line in diff: if not line: @@ -73,7 +69,7 @@ modified, added, removed, deleted, unknown = changes who = repo.changelog.read(node2)[1] - who = templater.email(who) # get the email of the person + who = util.email(who) # get the email of the person mmap1 = repo.manifest.read(repo.changelog.read(node1)[0]) mmap2 = repo.manifest.read(repo.changelog.read(node2)[0]) @@ -118,23 +114,24 @@ who, lines = __gather(ui, repo, node1, node2) # remap the owner if possible - if amap.has_key(who): + if who in amap: ui.note("using '%s' alias for '%s'\n" % (amap[who], who)) who = amap[who] - if not stats.has_key(who): + if not who in stats: stats[who] = 0 stats[who] += lines ui.note("rev %d: %d lines by %s\n" % (rev, lines, who)) if progress: + nr_revs = max(nr_revs, 1) if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs): - ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),)) + ui.write("\rGenerating stats: %d%%" % (int(100.0*cur_rev/nr_revs),)) sys.stdout.flush() if progress: - ui.write("done\n") + ui.write("\r") sys.stdout.flush() return stats @@ -148,6 +145,7 @@ return s[0:l] def graph(n, maximum, width, char): + maximum = max(1, maximum) n = int(n * width / float(maximum)) return char * (n) @@ -182,6 +180,8 @@ ordered = stats.items() ordered.sort(lambda x, y: cmp(y[1], x[1])) + if not ordered: + return maximum = ordered[0][1] width = get_tty_width() diff -r dd714452c26e -r 2da5b19a6460 contrib/darcs2hg.py --- a/contrib/darcs2hg.py Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/darcs2hg.py Wed Feb 06 19:57:52 2008 -0800 @@ -3,18 +3,22 @@ # vim: tw=80 ts=4 sw=4 noet # ----------------------------------------------------------------------------- # Project : Basic Darcs to Mercurial conversion script +# +# *** DEPRECATED. Use the convert extension instead. This script will +# *** be removed soon. +# # ----------------------------------------------------------------------------- # Authors : Sebastien Pierre # TK Soh # ----------------------------------------------------------------------------- # Creation : 24-May-2006 -# Last mod : 05-Jun-2006 # ----------------------------------------------------------------------------- import os, sys import tempfile import xml.dom.minidom as xml_dom from time import strptime, mktime +import re DARCS_REPO = None HG_REPO = None @@ -93,11 +97,50 @@ def darcs_pull(hg_repo, darcs_repo, chash): old_tip = darcs_tip(darcs_repo) res = cmd("darcs pull \"%s\" --all --match=\"hash %s\"" % (darcs_repo, chash), hg_repo) + if re.search('^We have conflicts in the following files:$', res, re.MULTILINE): + print "Trying to revert files to work around conflict..." + rev_res = cmd ("darcs revert --all", hg_repo) + print rev_res print res new_tip = darcs_tip(darcs_repo) if not new_tip != old_tip + 1: error("Darcs pull did not work as expected: " + res) +def darcs_changes_summary(darcs_repo, chash): + """Gets the changes from the darcs summary. This returns the chronological + list of changes as (change_type, args). Eg. ('add_file', 'foo.txt') or + ('move', ['foo.txt','bar.txt']).""" + change = cmd("darcs changes --summary --xml-output --match=\"hash %s\"" % (chash), darcs_repo) + doc = xml_dom.parseString(change) + for patch_node in doc.childNodes[0].childNodes: + summary_nodes = filter(lambda n: n.nodeName == "summary" and n.nodeType == n.ELEMENT_NODE, patch_node.childNodes) + for summary_node in summary_nodes: + change_nodes = filter(lambda n: n.nodeType == n.ELEMENT_NODE, summary_node.childNodes) + if len(change_nodes) == 0: + name = filter(lambda n: n.nodeName == "name", patch_node.childNodes) + if not name: + error("Darcs patch has an empty summary node and no name: " + patch_node.toxml()) + name = name[0].childNodes[0].data.strip() + (tag, sub_count) = re.subn('^TAG ', '', name, 1) + if sub_count != 1: + error("Darcs patch has an empty summary node but doesn't look like a tag: " + patch_node.toxml()); + for change_node in change_nodes: + change = change_node.nodeName + if change == 'modify_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'add_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'remove_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'add_directory': + yield change, change_node.childNodes[0].data.strip() + elif change == 'remove_directory': + yield change, change_node.childNodes[0].data.strip() + elif change == 'move': + yield change, (change_node.getAttribute('from'), change_node.getAttribute('to')) + else: + error('Problem parsing summary xml: Unexpected element: ' + change_node.toxml()) + # ------------------------------------------------------------------------------ # # Mercurial interface @@ -127,6 +170,36 @@ tip = tip.split("\n")[0].split(":")[1].strip() return int(tip) +def hg_rename( hg_repo, from_file, to_file ): + cmd("hg rename --after \"%s\" \"%s\"" % (from_file, to_file), hg_repo); + +def hg_tag ( hg_repo, text, author, date ): + old_tip = hg_tip(hg_repo) + res = cmd("hg tag -u \"%s\" -d \"%s 0\" \"%s\"" % (author, date, text), hg_repo) + new_tip = hg_tip(hg_repo) + if not new_tip == old_tip + 1: + error("Mercurial tag did not work as expected: " + res) + +def hg_handle_change( hg_repo, author, date, change, arg ): + """Processes a change event as output by darcs_changes_summary. These + consist of file move/rename/add/delete commands.""" + if change == 'modify_file': + pass + elif change == 'add_file': + pass + elif change =='remove_file': + pass + elif change == 'add_directory': + pass + elif change == 'remove_directory': + pass + elif change == 'move': + hg_rename(hg_repo, arg[0], arg[1]) + elif change == 'tag': + hg_tag(hg_repo, arg, author, date) + else: + error('Unknown change type ' + change + ': ' + arg) + # ------------------------------------------------------------------------------ # # Main @@ -147,6 +220,7 @@ else: print USAGE sys.exit(-1) + print 'This command is deprecated. Use the convert extension instead.' # Initializes the target repo if not os.path.isdir(darcs_repo + "/_darcs"): print "No darcs directory found at: " + darcs_repo @@ -167,11 +241,13 @@ print "(skipping)" else: text = summary + "\n" + description - darcs_pull(hg_repo, darcs_repo, chash) # The commit hash has a date like 20021020201112 # --------------------------------YYYYMMDDHHMMSS date = chash.split("-")[0] epoch = int(mktime(strptime(date, '%Y%m%d%H%M%S'))) + darcs_pull(hg_repo, darcs_repo, chash) + for change, arg in darcs_changes_summary(darcs_repo, chash): + hg_handle_change(hg_repo, author, epoch, change, arg) hg_commit(hg_repo, text, author, epoch) change_number += 1 print "Darcs repository (_darcs) was not deleted. You can keep or remove it." diff -r dd714452c26e -r 2da5b19a6460 contrib/hg-ssh --- a/contrib/hg-ssh Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/hg-ssh Wed Feb 06 19:57:52 2008 -0800 @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2005, 2006 by Intevation GmbH +# Copyright 2005-2007 by Intevation GmbH # Author(s): # Thomas Arendsen Hein # @@ -25,7 +25,10 @@ command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}" """ -from mercurial import commands +# enable importing on demand to reduce startup time +from mercurial import demandimport; demandimport.enable() + +from mercurial import dispatch import sys, os @@ -38,7 +41,7 @@ path = orig_cmd[6:-14] repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) if repo in allowed_paths: - commands.dispatch(['-R', repo, 'serve', '--stdio']) + dispatch.dispatch(['-R', repo, 'serve', '--stdio']) else: sys.stderr.write("Illegal repository %r\n" % repo) sys.exit(-1) diff -r dd714452c26e -r 2da5b19a6460 contrib/hgdiff --- a/contrib/hgdiff Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/hgdiff Wed Feb 06 19:57:52 2008 -0800 @@ -15,7 +15,7 @@ parser.add_option('-x', '--count', default=1) parser.add_option('-c', '--context', type="int", default=3) parser.add_option('-p', '--show-c-function', action="store_true", default=False) -parser.add_option('-w', '--ignore-all-space', action="store_true", +parser.add_option('-w', '--ignore-all-space', action="store_true", default=False) (options, args) = parser.parse_args() diff -r dd714452c26e -r 2da5b19a6460 contrib/hgk --- a/contrib/hgk Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/hgk Wed Feb 06 19:57:52 2008 -0800 @@ -4,6 +4,8 @@ # This program is free software; it may be used, copied, modified # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. +# +# See hgk.py for extension usage and configuration. # Modified version of Tip 171: @@ -32,7 +34,7 @@ # if we are outside the app, try and scroll the focus widget if {![winfo exists $w]} { catch {set w [focus]} } if {[winfo exists $w]} { - + if {[bind $w $evt] ne ""} { # Awkward ... this widget has a MouseWheel binding, but to # trigger successfully in it, we must give it focus. @@ -70,8 +72,17 @@ bind all [list ::tk::MouseWheel %W %X %Y %D 0] # end of win32 section -} - +} + + +# Unify right mouse button handling. +# See "mouse buttons on macintosh" thread on comp.lang.tcl +if {[tk windowingsystem] eq "aqua"} { + event add <> + event add <> +} else { + event add <> +} proc gitdir {} { global env @@ -263,6 +274,7 @@ set comname {} set comdate {} set rev {} + set branch {} if {![info exists nchildren($id)]} { set children($id) {} set nchildren($id) 0 @@ -299,6 +311,8 @@ set comname [join [lrange $line 1 [expr {$x - 1}]]] } elseif {$tag == "revision"} { set rev [lindex $line 1] + } elseif {$tag == "branch"} { + set branch [join [lrange $line 1 end]] } } } else { @@ -323,11 +337,14 @@ set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] } set commitinfo($id) [list $headline $auname $audate \ - $comname $comdate $comment $rev] + $comname $comdate $comment $rev $branch] } proc readrefs {} { - global tagids idtags headids idheads tagcontents env + global tagids idtags headids idheads tagcontents env curid + + set curid [exec $env(HG) --config ui.report_untrusted=false id] + regexp -- {[[:xdigit:]]+} $curid curid set tags [exec $env(HG) --config ui.report_untrusted=false tags] regsub -all "\r\n" $tags "\n" tags @@ -390,6 +407,7 @@ global entries sha1entry sha1string sha1but global maincursor textcursor curtextcursor global rowctxmenu gaudydiff mergemax + global hgvdiff menu .bar .bar add cascade -label "File" -menu .bar.file @@ -593,6 +611,12 @@ $rowctxmenu add command -label "Make patch" -command mkpatch $rowctxmenu add command -label "Create tag" -command mktag $rowctxmenu add command -label "Write commit to file" -command writecommit + if { $hgvdiff ne "" } { + $rowctxmenu add command -label "Visual diff with parent" \ + -command {vdiff 1} + $rowctxmenu add command -label "Visual diff with selected" \ + -command {vdiff 0} + } } # when we make a key binding for the toplevel, make sure @@ -623,13 +647,14 @@ proc savestuff {w} { global canv canv2 canv3 ctext cflist mainfont textfont global stuffsaved findmergefiles gaudydiff maxgraphpct - global maxwidth + global maxwidth authorcolors curidfont if {$stuffsaved} return if {![winfo viewable .]} return catch { - set f [open "~/.gitk-new" w] + set f [open "~/.hgk-new" w] puts $f [list set mainfont $mainfont] + puts $f [list set curidfont $curidfont] puts $f [list set textfont $textfont] puts $f [list set findmergefiles $findmergefiles] puts $f [list set gaudydiff $gaudydiff] @@ -647,8 +672,25 @@ set wid [expr {([winfo width $cflist] - 11) \ / [font measure [$cflist cget -font] "0"]}] puts $f "set geometry(cflistw) $wid" + puts $f "#" + puts $f "# authorcolors format:" + puts $f "#" + puts $f "# zero or more sublists of" + puts $f "#" + puts $f "# { regex color }" + puts $f "#" + puts $f "# followed by a list of colors" + puts $f "#" + puts $f "# If the commit author matches a regex in a sublist," + puts $f "# the commit will be colored by that color" + puts $f "# otherwise the next unused entry from the list of colors" + puts $f "# will be assigned to this commit and also all other commits" + puts $f "# of the same author. When the list of colors is exhausted," + puts $f "# the last entry will be reused." + puts $f "#" + puts $f "set authorcolors {$authorcolors}" close $f - file rename -force "~/.gitk-new" "~/.gitk" + file rename -force "~/.hgk-new" "~/.hgk" } set stuffsaved 1 } @@ -739,6 +781,35 @@ pack $w.ok -side bottom } +set aunextcolor 0 +proc assignauthorcolor {name} { + global authorcolors aucolormap aunextcolor + if [info exists aucolormap($name)] return + + set randomcolors {black} + for {set i 0} {$i < [llength $authorcolors]} {incr i} { + set col [lindex $authorcolors $i] + if {[llength $col] > 1} { + set re [lindex $col 0] + set c [lindex $col 1] + if {[regexp -- $re $name]} { + set aucolormap($name) $c + return + } + } else { + set randomcolors [lrange $authorcolors $i end] + break + } + } + + set ncolors [llength $randomcolors] + set c [lindex $randomcolors $aunextcolor] + if {[incr aunextcolor] >= $ncolors} { + incr aunextcolor -1 + } + set aucolormap($name) $c +} + proc assigncolor {id} { global commitinfo colormap commcolors colors nextcolor global parents nparents children nchildren @@ -876,6 +947,7 @@ global lineno lthickness mainline mainlinearrow sidelines global commitlisted rowtextx idpos lastuse displist global oldnlines olddlevel olddisplist + global aucolormap curid curidfont incr numcommits incr lineno @@ -934,14 +1006,25 @@ } set headline [lindex $commitinfo($id) 0] set name [lindex $commitinfo($id) 1] + assignauthorcolor $name + set fg $aucolormap($name) + if {$id == $curid} { + set fn $curidfont + } else { + set fn $mainfont + } + set date [lindex $commitinfo($id) 2] set linehtag($lineno) [$canv create text $xt $y1 -anchor w \ - -text $headline -font $mainfont ] - $canv bind $linehtag($lineno) "rowmenu %X %Y $id" + -text $headline -font $fn \ + -fill $fg] + $canv bind $linehtag($lineno) <> "rowmenu %X %Y $id" set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \ - -text $name -font $namefont] + -text $name -font $namefont \ + -fill $fg] set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \ - -text $date -font $mainfont] + -text $date -font $mainfont \ + -fill $fg] set olddlevel $level set olddisplist $displist @@ -2206,6 +2289,9 @@ $ctext mark gravity fmark.0 left set info $commitinfo($id) $ctext insert end "Revision: [lindex $info 6]\n" + if {[llength [lindex $info 7]] > 0} { + $ctext insert end "Branch: [lindex $info 7]\n" + } $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" if {[info exists idtags($id)]} { @@ -3071,9 +3157,10 @@ proc incrfont {inc} { global mainfont namefont textfont ctext canv phase - global stopped entries + global stopped entries curidfont unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] + set curidfont [lreplace $curidfont 1 1 [expr {[lindex $curidfont 1] + $inc}]] set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]] set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] setcoords @@ -3364,7 +3451,7 @@ } proc rowmenu {x y id} { - global rowctxmenu idline selectedline rowmenuid + global rowctxmenu idline selectedline rowmenuid hgvdiff if {![info exists selectedline] || $idline($id) eq $selectedline} { set state disabled @@ -3374,6 +3461,9 @@ $rowctxmenu entryconfigure 0 -state $state $rowctxmenu entryconfigure 1 -state $state $rowctxmenu entryconfigure 2 -state $state + if { $hgvdiff ne "" } { + $rowctxmenu entryconfigure 6 -state $state + } set rowmenuid $id tk_popup $rowctxmenu $x $y } @@ -3686,6 +3776,26 @@ } } +proc vdiff {withparent} { + global env rowmenuid selectedline lineid hgvdiff + + if {![info exists rowmenuid]} return + set curid $rowmenuid + + if {$withparent} { + set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"] + set firstparent [lindex [split $parents "\n"] 0] + set otherid $firstparent + } else { + if {![info exists selectedline]} return + set otherid $lineid($selectedline) + } + set range "$otherid:$curid" + if {[catch {exec $env(HG) --config ui.report_untrusted=false $hgvdiff -r $range} err]} { + # Ignore errors, this is just visualization + } +} + proc showtag {tag isnew} { global ctext cflist tagcontents tagids linknum @@ -3711,6 +3821,19 @@ destroy . } +proc getconfig {} { + global env + + set lines [exec $env(HG) debug-config] + regsub -all "\r\n" $lines "\n" config + set config {} + foreach line [split $lines "\n"] { + regsub "^(k|v)=" $line "" line + lappend config $line + } + return $config +} + # defaults... set datemode 0 set boldnames 0 @@ -3718,6 +3841,7 @@ set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty" set mainfont {Helvetica 9} +set curidfont {} set textfont {Courier 9} set findmergefiles 0 set gaudydiff 0 @@ -3725,8 +3849,15 @@ set maxwidth 16 set colors {green red blue magenta darkgrey brown orange} - -catch {source ~/.gitk} +set authorcolors { + black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey +} + +catch {source ~/.hgk} + +if {$curidfont == ""} { # initialize late based on current mainfont + set curidfont "$mainfont bold italic underline" +} set namefont $mainfont if {$boldnames} { @@ -3752,7 +3883,12 @@ set redisplaying 0 set stuffsaved 0 set patchnum 0 + +array set config [getconfig] +set hgvdiff $config(vdiff) setcoords makewindow readrefs +set hgroot [exec $env(HG) root] +wm title . "hgk $hgroot" getcommits $revtreeargs diff -r dd714452c26e -r 2da5b19a6460 contrib/hgsh/hgsh.c --- a/contrib/hgsh/hgsh.c Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/hgsh/hgsh.c Wed Feb 06 19:57:52 2008 -0800 @@ -249,7 +249,7 @@ hg_serve, }; - + /* * attempt to verify that a directory is really a hg repo, by testing * for the existence of a subdirectory. @@ -342,13 +342,13 @@ if (cmd != hg_init) { int valid; - + valid = validate_repo(repo_root, "data"); if (valid == -1) { goto badargs; } - + if (valid == 0) { valid = validate_repo(repo_root, "store"); @@ -356,7 +356,7 @@ goto badargs; } } - + if (valid == 0) { perror(repo); exit(EX_DATAERR); @@ -385,7 +385,7 @@ nargv[i++] = repo; break; } - + nargv[i] = NULL; if (debug) { diff -r dd714452c26e -r 2da5b19a6460 contrib/hgwebdir.fcgi --- a/contrib/hgwebdir.fcgi Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/hgwebdir.fcgi Wed Feb 06 19:57:52 2008 -0800 @@ -2,14 +2,17 @@ # # An example CGI script to export multiple hgweb repos, edit as necessary +# adjust python path if not a system-wide install: +#import sys +#sys.path.insert(0, "/path/to/python/lib") + +# enable demandloading to reduce startup time +from mercurial import demandimport; demandimport.enable() + # send python tracebacks to the browser if an error occurs: import cgitb cgitb.enable() -# adjust python path if not a system-wide install: -#import sys -#sys.path.insert(0, "/path/to/python/lib") - # If you'd like to serve pages with UTF-8 instead of your default # locale charset, you can do so by uncommenting the following lines. # Note that this will cause your .hgrc files to be interpreted in @@ -20,6 +23,7 @@ from mercurial.hgweb.hgwebdir_mod import hgwebdir from mercurial.hgweb.request import wsgiapplication +from mercurial import dispatch, ui from flup.server.fcgi import WSGIServer # The config file looks like this. You can have paths to individual @@ -41,7 +45,8 @@ # Alternatively you can pass a list of ('virtual/path', '/real/path') tuples # or use a dictionary with entries like 'virtual/path': '/real/path' -def make_web_app(): - return hgwebdir("hgweb.config") +def web_app(ui): + return lambda: hgwebdir("hgweb.config", ui) -WSGIServer(wsgiapplication(make_web_app)).run() +u = ui.ui(report_untrusted=False, interactive=False) +dispatch.profiled(u, lambda: WSGIServer(wsgiapplication(web_app(u))).run()) diff -r dd714452c26e -r 2da5b19a6460 contrib/macosx/Readme.html --- a/contrib/macosx/Readme.html Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/macosx/Readme.html Wed Feb 06 19:57:52 2008 -0800 @@ -17,20 +17,11 @@

Before you install


-

This is not a stand-alone version of Mercurial.

-


-

To use it, you must have the appropriate version of Universal MacPython from www.python.org installed.

-


-

You can find more information and download MacPython from here:

-

http://www.python.org/download

-


-

Or direct links to the latest version are:

-

Python 2.5.1 for Macintosh OS X

-

Python 2.4.4 for Macintosh OS X

+

This is an OS X 10.5 version of Mercurial that depends on the default Python 2.5 installation.


After you install


-

This package installs the hg executable in /Library/Frameworks/Python.framework/Versions/Current/bin. This directory may not be in your shell's search path. The MacPython installer will have created an entry in .profile for it but if your shell doesn't use .profile you'll need configure it yourself or create a symlink from a directory already in your path.

+

This package installs the hg executable in /usr/local/bin and the Mercurial files in /Library/Python/2.5/site-packages/mercurial.


Documentation


diff -r dd714452c26e -r 2da5b19a6460 contrib/mercurial.el --- a/contrib/mercurial.el Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/mercurial.el Wed Feb 06 19:57:52 2008 -0800 @@ -426,7 +426,7 @@ (if (or (not default) current-prefix-arg) (string-to-number (eval (list* 'read-string - (or prompt "") + (or prompt "") (if default (cons (format "%d" default) nil) nil)))) default))) @@ -521,7 +521,7 @@ (completing-read (format "Revision%s (%s): " (or prompt "") (or default "tip")) - (map 'list 'cons revs revs) + (mapcar (lambda (x) (cons x x)) revs) nil nil nil @@ -565,7 +565,7 @@ (when buf (set-buffer buf) (hg-mode-line-internal status parents))))))) - + ;;; View mode bits. @@ -588,7 +588,7 @@ (setq hg-view-mode t) (setq truncate-lines t) (when file-name - (setq hg-view-file-name + (setq hg-view-file-name (hg-abbrev-file-name file-name)))) (defun hg-file-status (file) @@ -666,7 +666,11 @@ to have moved a little, but not really changed." (let ((point-context (hg-position-context (point))) (mark-context (let ((mark (mark-marker))) - (and mark (hg-position-context mark))))) + (and mark + ;; make sure active mark + (marker-buffer mark) + (marker-position mark) + (hg-position-context mark))))) (list point-context mark-context))) (defun hg-find-context (ctx) @@ -703,7 +707,7 @@ (added . "a") (deleted . "!") (modified . "m")))))))) - + (defun hg-mode-line (&optional force) "Update the modeline with the current status of a file. An update occurs if optional argument FORCE is non-nil, @@ -1000,7 +1004,7 @@ ;; none revision is specified explicitly (none (and (not rev1) (not rev2))) ;; only one revision is specified explicitly - (one (or (and (or (equal rev1 rev2) (not rev2)) rev1) + (one (or (and (or (equal rev1 rev2) (not rev2)) rev1) (and (not rev1) rev2))) diff) (hg-view-output ((cond @@ -1012,7 +1016,7 @@ (format "Mercurial: Diff from rev %s to %s of %s" rev1 rev2 a-path)))) (cond - (none + (none (call-process (hg-binary) nil t nil "diff" path)) (one (call-process (hg-binary) nil t nil "diff" "-r" one path)) @@ -1100,7 +1104,7 @@ (limit (format "%d" (or log-limit hg-log-limit)))) (hg-view-output ((if (equal r1 r2) (format "Mercurial: Log of rev %s of %s" rev1 a-path) - (format + (format "Mercurial: at most %s log(s) from rev %s to %s of %s" limit r1 r2 a-path))) (eval (list* 'call-process (hg-binary) nil t nil @@ -1123,7 +1127,7 @@ (interactive (list (hg-read-file-name " to log") (hg-read-rev " to start with" "tip") - (hg-read-rev " to end with" + (hg-read-rev " to end with" "0") (hg-read-number "Output limited to: " hg-log-limit))) diff -r dd714452c26e -r 2da5b19a6460 contrib/mergetools.hgrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/mergetools.hgrc Wed Feb 06 19:57:52 2008 -0800 @@ -0,0 +1,49 @@ +# Some default global settings for common merge tools + +[merge-tools] +kdiff3.args=--auto -L1 base --L2 local --L3 other $base $local $other -o $output +kdiff3.regkey=Software\KDiff3 +kdiff3.regappend=\kdiff3.exe +kdiff3.fixeol=True +kdiff3.gui=True + +gvimdiff.args=--nofork -d -g -O $local $other $base +gvimdiff.regkey=Software\Vim\GVim +gvimdiff.regname=path +gvimdiff.priority=-9 + +merge.checkconflicts=True +merge.priority=-10 + +gpyfm.gui=True + +meld.gui=True + +tkdiff.args=$local $other -a $base -o $output +tkdiff.gui=True +tkdiff.priority=-8 + +xxdiff.args=--show-merged-pane --exit-with-merge-status --title1 local --title2 base --title3 other --merged-filename $output --merge $local $base $other +xxdiff.gui=True +xxdiff.priority=-8 + +diffmerge.args=--nosplash --merge --title1=base --title2=local --title3=other $base $local $other +diffmerge.gui=True + +p4merge.args=$base $local $other $output +p4merge.regkey=Software\Perforce\Environment +p4merge.regname=P4INSTROOT +p4merge.regappend=\p4merge.exe +p4merge.gui=True +p4merge.priority=-8 + +tortoisemerge.args=/base: $output /mine:$local /theirs:$other /merged:$output +tortoisemerge.regkey=Software\TortoiseSVN +tortoisemerge.gui=True + +ecmerge.args=$base $local $other --mode=merge3 --title0=base --title1=local --title2=other --to=$output +ecmerge.regkey=Software\Elli\xc3\xa9 Computing\Merge +ecmerge.gui=True + +filemerge.args=-left $other -right $local -ancestor $base -merge $output +filemerge.gui=True diff -r dd714452c26e -r 2da5b19a6460 contrib/mq.el --- a/contrib/mq.el Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/mq.el Wed Feb 06 19:57:52 2008 -0800 @@ -18,6 +18,7 @@ ;; C-l'). If not, write to the Free Software Foundation, Inc., 59 ;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. +(eval-when-compile (require 'cl)) (require 'mercurial) @@ -62,35 +63,42 @@ (make-variable-buffer-local 'mq-prev-buffer) (put 'mq-prev-buffer 'permanent-local t) +(defvar mq-top nil) +(make-variable-buffer-local 'mq-top) +(put 'mq-top 'permanent-local t) ;;; Global keymap. -(defvar mq-global-map (make-sparse-keymap)) -(fset 'mq-global-map mq-global-map) -(global-set-key mq-global-prefix 'mq-global-map) -(define-key mq-global-map "." 'mq-push) -(define-key mq-global-map ">" 'mq-push-all) -(define-key mq-global-map "," 'mq-pop) -(define-key mq-global-map "<" 'mq-pop-all) -(define-key mq-global-map "=" 'mq-diff) -(define-key mq-global-map "r" 'mq-refresh) -(define-key mq-global-map "e" 'mq-refresh-edit) -(define-key mq-global-map "i" 'mq-new) -(define-key mq-global-map "n" 'mq-next) -(define-key mq-global-map "o" 'mq-signoff) -(define-key mq-global-map "p" 'mq-previous) -(define-key mq-global-map "s" 'mq-edit-series) -(define-key mq-global-map "t" 'mq-top) +(defvar mq-global-map + (let ((map (make-sparse-keymap))) + (define-key map "." 'mq-push) + (define-key map ">" 'mq-push-all) + (define-key map "," 'mq-pop) + (define-key map "<" 'mq-pop-all) + (define-key map "=" 'mq-diff) + (define-key map "r" 'mq-refresh) + (define-key map "e" 'mq-refresh-edit) + (define-key map "i" 'mq-new) + (define-key map "n" 'mq-next) + (define-key map "o" 'mq-signoff) + (define-key map "p" 'mq-previous) + (define-key map "s" 'mq-edit-series) + (define-key map "t" 'mq-top) + map)) + +(global-set-key mq-global-prefix mq-global-map) (add-minor-mode 'mq-mode 'mq-mode) ;;; Refresh edit mode keymap. -(defvar mq-edit-mode-map (make-sparse-keymap)) -(define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish) -(define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill) -(define-key mq-edit-mode-map "\C-c\C-s" 'mq-signoff) +(defvar mq-edit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-c" 'mq-edit-finish) + (define-key map "\C-c\C-k" 'mq-edit-kill) + (define-key map "\C-c\C-s" 'mq-signoff) + map)) ;;; Helper functions. @@ -102,7 +110,7 @@ (hg-chomp (hg-run0 (or source "qseries"))) "\n"))) (when force (completing-read (format "Patch%s: " (or prompt "")) - (map 'list 'cons patches patches) + (mapcar (lambda (x) (cons x x)) patches) nil nil nil @@ -131,7 +139,7 @@ (let ((line (buffer-substring bol (point)))) (when (> (length line) 0) line)))) - + (defun mq-push (&optional patch) "Push patches until PATCH is reached. If PATCH is nil, push at most one patch." @@ -166,7 +174,7 @@ (if ok (message "Pushing... %s" last-line) (error "Pushing... %s" last-line))))) - + (defun mq-push-all () "Push patches until all are applied." (interactive) @@ -195,7 +203,7 @@ (if ok (message "Popping... %s" last-line) (error "Popping... %s" last-line))))) - + (defun mq-pop-all () "Push patches until none are applied." (interactive) @@ -255,7 +263,7 @@ (let ((buf mq-prev-buffer)) (kill-buffer nil) (switch-to-buffer buf))) - + (defun mq-edit-kill () "Kill the edit currently being prepared." (interactive) @@ -316,7 +324,7 @@ (set-buffer-modified-p nil) (setq buffer-undo-list nil) (run-hooks 'text-mode-hook 'mq-edit-mode-hook)) - + (defun mq-refresh-edit () "Refresh the topmost applied patch, editing the patch description." (interactive) diff -r dd714452c26e -r 2da5b19a6460 contrib/simplemerge --- a/contrib/simplemerge Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/simplemerge Wed Feb 06 19:57:52 2008 -0800 @@ -1,503 +1,11 @@ #!/usr/bin/env python -# Copyright (C) 2004, 2005 Canonical Ltd -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -# mbp: "you know that thing where cvs gives you conflict markers?" -# s: "i hate that." from mercurial import demandimport demandimport.enable() -from mercurial import util, mdiff, fancyopts +import os, sys from mercurial.i18n import _ - - -class CantReprocessAndShowBase(Exception): - pass - - -def warn(message): - sys.stdout.flush() - sys.stderr.write(message) - sys.stderr.flush() - - -def intersect(ra, rb): - """Given two ranges return the range where they intersect or None. - - >>> intersect((0, 10), (0, 6)) - (0, 6) - >>> intersect((0, 10), (5, 15)) - (5, 10) - >>> intersect((0, 10), (10, 15)) - >>> intersect((0, 9), (10, 15)) - >>> intersect((0, 9), (7, 15)) - (7, 9) - """ - assert ra[0] <= ra[1] - assert rb[0] <= rb[1] - - sa = max(ra[0], rb[0]) - sb = min(ra[1], rb[1]) - if sa < sb: - return sa, sb - else: - return None - - -def compare_range(a, astart, aend, b, bstart, bend): - """Compare a[astart:aend] == b[bstart:bend], without slicing. - """ - if (aend-astart) != (bend-bstart): - return False - for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)): - if a[ia] != b[ib]: - return False - else: - return True - - - - -class Merge3Text(object): - """3-way merge of texts. - - Given strings BASE, OTHER, THIS, tries to produce a combined text - incorporating the changes from both BASE->OTHER and BASE->THIS.""" - def __init__(self, basetext, atext, btext, base=None, a=None, b=None): - self.basetext = basetext - self.atext = atext - self.btext = btext - if base is None: - base = mdiff.splitnewlines(basetext) - if a is None: - a = mdiff.splitnewlines(atext) - if b is None: - b = mdiff.splitnewlines(btext) - self.base = base - self.a = a - self.b = b - - - - def merge_lines(self, - name_a=None, - name_b=None, - name_base=None, - start_marker='<<<<<<<', - mid_marker='=======', - end_marker='>>>>>>>', - base_marker=None, - reprocess=False): - """Return merge in cvs-like form. - """ - self.conflicts = False - newline = '\n' - if len(self.a) > 0: - if self.a[0].endswith('\r\n'): - newline = '\r\n' - elif self.a[0].endswith('\r'): - newline = '\r' - if base_marker and reprocess: - raise CantReprocessAndShowBase() - if name_a: - start_marker = start_marker + ' ' + name_a - if name_b: - end_marker = end_marker + ' ' + name_b - if name_base and base_marker: - base_marker = base_marker + ' ' + name_base - merge_regions = self.merge_regions() - if reprocess is True: - merge_regions = self.reprocess_merge_regions(merge_regions) - for t in merge_regions: - what = t[0] - if what == 'unchanged': - for i in range(t[1], t[2]): - yield self.base[i] - elif what == 'a' or what == 'same': - for i in range(t[1], t[2]): - yield self.a[i] - elif what == 'b': - for i in range(t[1], t[2]): - yield self.b[i] - elif what == 'conflict': - self.conflicts = True - yield start_marker + newline - for i in range(t[3], t[4]): - yield self.a[i] - if base_marker is not None: - yield base_marker + newline - for i in range(t[1], t[2]): - yield self.base[i] - yield mid_marker + newline - for i in range(t[5], t[6]): - yield self.b[i] - yield end_marker + newline - else: - raise ValueError(what) - - - - - - def merge_annotated(self): - """Return merge with conflicts, showing origin of lines. - - Most useful for debugging merge. - """ - for t in self.merge_regions(): - what = t[0] - if what == 'unchanged': - for i in range(t[1], t[2]): - yield 'u | ' + self.base[i] - elif what == 'a' or what == 'same': - for i in range(t[1], t[2]): - yield what[0] + ' | ' + self.a[i] - elif what == 'b': - for i in range(t[1], t[2]): - yield 'b | ' + self.b[i] - elif what == 'conflict': - yield '<<<<\n' - for i in range(t[3], t[4]): - yield 'A | ' + self.a[i] - yield '----\n' - for i in range(t[5], t[6]): - yield 'B | ' + self.b[i] - yield '>>>>\n' - else: - raise ValueError(what) - - - - - - def merge_groups(self): - """Yield sequence of line groups. Each one is a tuple: - - 'unchanged', lines - Lines unchanged from base - - 'a', lines - Lines taken from a - - 'same', lines - Lines taken from a (and equal to b) - - 'b', lines - Lines taken from b - - 'conflict', base_lines, a_lines, b_lines - Lines from base were changed to either a or b and conflict. - """ - for t in self.merge_regions(): - what = t[0] - if what == 'unchanged': - yield what, self.base[t[1]:t[2]] - elif what == 'a' or what == 'same': - yield what, self.a[t[1]:t[2]] - elif what == 'b': - yield what, self.b[t[1]:t[2]] - elif what == 'conflict': - yield (what, - self.base[t[1]:t[2]], - self.a[t[3]:t[4]], - self.b[t[5]:t[6]]) - else: - raise ValueError(what) - - - def merge_regions(self): - """Return sequences of matching and conflicting regions. - - This returns tuples, where the first value says what kind we - have: - - 'unchanged', start, end - Take a region of base[start:end] - - 'same', astart, aend - b and a are different from base but give the same result - - 'a', start, end - Non-clashing insertion from a[start:end] - - Method is as follows: - - The two sequences align only on regions which match the base - and both descendents. These are found by doing a two-way diff - of each one against the base, and then finding the - intersections between those regions. These "sync regions" - are by definition unchanged in both and easily dealt with. - - The regions in between can be in any of three cases: - conflicted, or changed on only one side. - """ - - # section a[0:ia] has been disposed of, etc - iz = ia = ib = 0 - - for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions(): - #print 'match base [%d:%d]' % (zmatch, zend) - - matchlen = zend - zmatch - assert matchlen >= 0 - assert matchlen == (aend - amatch) - assert matchlen == (bend - bmatch) - - len_a = amatch - ia - len_b = bmatch - ib - len_base = zmatch - iz - assert len_a >= 0 - assert len_b >= 0 - assert len_base >= 0 - - #print 'unmatched a=%d, b=%d' % (len_a, len_b) - - if len_a or len_b: - # try to avoid actually slicing the lists - equal_a = compare_range(self.a, ia, amatch, - self.base, iz, zmatch) - equal_b = compare_range(self.b, ib, bmatch, - self.base, iz, zmatch) - same = compare_range(self.a, ia, amatch, - self.b, ib, bmatch) - - if same: - yield 'same', ia, amatch - elif equal_a and not equal_b: - yield 'b', ib, bmatch - elif equal_b and not equal_a: - yield 'a', ia, amatch - elif not equal_a and not equal_b: - yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch - else: - raise AssertionError("can't handle a=b=base but unmatched") - - ia = amatch - ib = bmatch - iz = zmatch - - # if the same part of the base was deleted on both sides - # that's OK, we can just skip it. - - - if matchlen > 0: - assert ia == amatch - assert ib == bmatch - assert iz == zmatch - - yield 'unchanged', zmatch, zend - iz = zend - ia = aend - ib = bend - - - def reprocess_merge_regions(self, merge_regions): - """Where there are conflict regions, remove the agreed lines. - - Lines where both A and B have made the same changes are - eliminated. - """ - for region in merge_regions: - if region[0] != "conflict": - yield region - continue - type, iz, zmatch, ia, amatch, ib, bmatch = region - a_region = self.a[ia:amatch] - b_region = self.b[ib:bmatch] - matches = mdiff.get_matching_blocks(''.join(a_region), - ''.join(b_region)) - next_a = ia - next_b = ib - for region_ia, region_ib, region_len in matches[:-1]: - region_ia += ia - region_ib += ib - reg = self.mismatch_region(next_a, region_ia, next_b, - region_ib) - if reg is not None: - yield reg - yield 'same', region_ia, region_len+region_ia - next_a = region_ia + region_len - next_b = region_ib + region_len - reg = self.mismatch_region(next_a, amatch, next_b, bmatch) - if reg is not None: - yield reg - - - def mismatch_region(next_a, region_ia, next_b, region_ib): - if next_a < region_ia or next_b < region_ib: - return 'conflict', None, None, next_a, region_ia, next_b, region_ib - mismatch_region = staticmethod(mismatch_region) - - - def find_sync_regions(self): - """Return a list of sync regions, where both descendents match the base. - - Generates a list of (base1, base2, a1, a2, b1, b2). There is - always a zero-length sync region at the end of all the files. - """ - - ia = ib = 0 - amatches = mdiff.get_matching_blocks(self.basetext, self.atext) - bmatches = mdiff.get_matching_blocks(self.basetext, self.btext) - len_a = len(amatches) - len_b = len(bmatches) - - sl = [] - - while ia < len_a and ib < len_b: - abase, amatch, alen = amatches[ia] - bbase, bmatch, blen = bmatches[ib] - - # there is an unconflicted block at i; how long does it - # extend? until whichever one ends earlier. - i = intersect((abase, abase+alen), (bbase, bbase+blen)) - if i: - intbase = i[0] - intend = i[1] - intlen = intend - intbase - - # found a match of base[i[0], i[1]]; this may be less than - # the region that matches in either one - assert intlen <= alen - assert intlen <= blen - assert abase <= intbase - assert bbase <= intbase - - asub = amatch + (intbase - abase) - bsub = bmatch + (intbase - bbase) - aend = asub + intlen - bend = bsub + intlen - - assert self.base[intbase:intend] == self.a[asub:aend], \ - (self.base[intbase:intend], self.a[asub:aend]) - - assert self.base[intbase:intend] == self.b[bsub:bend] - - sl.append((intbase, intend, - asub, aend, - bsub, bend)) - - # advance whichever one ends first in the base text - if (abase + alen) < (bbase + blen): - ia += 1 - else: - ib += 1 - - intbase = len(self.base) - abase = len(self.a) - bbase = len(self.b) - sl.append((intbase, intbase, abase, abase, bbase, bbase)) - - return sl - - - - def find_unconflicted(self): - """Return a list of ranges in base that are not conflicted.""" - am = mdiff.get_matching_blocks(self.basetext, self.atext) - bm = mdiff.get_matching_blocks(self.basetext, self.btext) - - unc = [] - - while am and bm: - # there is an unconflicted block at i; how long does it - # extend? until whichever one ends earlier. - a1 = am[0][0] - a2 = a1 + am[0][2] - b1 = bm[0][0] - b2 = b1 + bm[0][2] - i = intersect((a1, a2), (b1, b2)) - if i: - unc.append(i) - - if a2 < b2: - del am[0] - else: - del bm[0] - - return unc - - -# bzr compatible interface, for the tests -class Merge3(Merge3Text): - """3-way merge of texts. - - Given BASE, OTHER, THIS, tries to produce a combined text - incorporating the changes from both BASE->OTHER and BASE->THIS. - All three will typically be sequences of lines.""" - def __init__(self, base, a, b): - basetext = '\n'.join([i.strip('\n') for i in base] + ['']) - atext = '\n'.join([i.strip('\n') for i in a] + ['']) - btext = '\n'.join([i.strip('\n') for i in b] + ['']) - if util.binary(basetext) or util.binary(atext) or util.binary(btext): - raise util.Abort(_("don't know how to merge binary files")) - Merge3Text.__init__(self, basetext, atext, btext, base, a, b) - - -def simplemerge(local, base, other, **opts): - def readfile(filename): - f = open(filename, "rb") - text = f.read() - f.close() - if util.binary(text): - msg = _("%s looks like a binary file.") % filename - if not opts.get('text'): - raise util.Abort(msg) - elif not opts.get('quiet'): - warn(_('warning: %s\n') % msg) - return text - - name_a = local - name_b = other - labels = opts.get('label', []) - if labels: - name_a = labels.pop(0) - if labels: - name_b = labels.pop(0) - if labels: - raise util.Abort(_("can only specify two labels.")) - - localtext = readfile(local) - basetext = readfile(base) - othertext = readfile(other) - - orig = local - local = os.path.realpath(local) - if not opts.get('print'): - opener = util.opener(os.path.dirname(local)) - out = opener(os.path.basename(local), "w", atomictemp=True) - else: - out = sys.stdout - - reprocess = not opts.get('no_minimal') - - m3 = Merge3Text(basetext, localtext, othertext) - for line in m3.merge_lines(name_a=name_a, name_b=name_b, - reprocess=reprocess): - out.write(line) - - if not opts.get('print'): - out.rename() - - if m3.conflicts: - if not opts.get('quiet'): - warn(_("warning: conflicts during merge.\n")) - return 1 +from mercurial import simplemerge, fancyopts, util options = [('L', 'label', [], _('labels to use on conflict markers')), ('a', 'text', None, _('treat all files as text')), @@ -511,12 +19,15 @@ usage = _('''simplemerge [OPTS] LOCAL BASE OTHER Simple three-way file merge utility with a minimal feature set. - + Apply to LOCAL the changes necessary to go from BASE to OTHER. - + By default, LOCAL is overwritten with the results of this operation. ''') +class ParseError(Exception): + """Exception raised on errors in parsing the command line.""" + def showhelp(): sys.stdout.write(usage) sys.stdout.write('\noptions:\n') @@ -530,33 +41,24 @@ for first, second in out_opts: sys.stdout.write(' %-*s %s\n' % (opts_len, first, second)) -class ParseError(Exception): - """Exception raised on errors in parsing the command line.""" - -def main(argv): +try: + opts = {} try: - opts = {} - try: - args = fancyopts.fancyopts(argv[1:], options, opts) - except fancyopts.getopt.GetoptError, e: - raise ParseError(e) - if opts['help']: - showhelp() - return 0 - if len(args) != 3: - raise ParseError(_('wrong number of arguments')) - return simplemerge(*args, **opts) - except ParseError, e: - sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + args = fancyopts.fancyopts(sys.argv[1:], options, opts) + except fancyopts.getopt.GetoptError, e: + raise ParseError(e) + if opts['help']: showhelp() - return 1 - except util.Abort, e: - sys.stderr.write("abort: %s\n" % e) - return 255 - except KeyboardInterrupt: - return 255 - -if __name__ == '__main__': - import sys - import os - sys.exit(main(sys.argv)) + sys.exit(0) + if len(args) != 3: + raise ParseError(_('wrong number of arguments')) + sys.exit(simplemerge.simplemerge(*args, **opts)) +except ParseError, e: + sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + showhelp() + sys.exit(1) +except util.Abort, e: + sys.stderr.write("abort: %s\n" % e) + sys.exit(255) +except KeyboardInterrupt: + sys.exit(255) diff -r dd714452c26e -r 2da5b19a6460 contrib/vim/hg-menu.vim --- a/contrib/vim/hg-menu.vim Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/vim/hg-menu.vim Wed Feb 06 19:57:52 2008 -0800 @@ -9,7 +9,7 @@ " Usage: These command and gui menu displays useful hg functions " Configuration: Your hg executable must be in your path. " ============================================================================= - + " Section: Init {{{1 if exists("loaded_hg_menu") finish diff -r dd714452c26e -r 2da5b19a6460 contrib/win32/ReadMe.html --- a/contrib/win32/ReadMe.html Thu Jul 26 07:56:27 2007 -0400 +++ b/contrib/win32/ReadMe.html Wed Feb 06 19:57:52 2008 -0800 @@ -2,7 +2,7 @@ Mercurial for Windows - +