# HG changeset patch # User Dongsheng Song # Date 1237379557 -28800 # Node ID d0160b0b1a9eb31c2eec993cbffb812b1f01c83e # Parent c2cefd9f98935e6be338f36b4654d28ef856218f# Parent 5bfa0df6aaed357edebe49fcaa448e0600cafca4 Merge with http://hg.serpentine.com/mercurial/book diff -r c2cefd9f9893 -r d0160b0b1a9e en/Makefile --- a/en/Makefile Wed Mar 18 19:50:36 2009 +0800 +++ b/en/Makefile Wed Mar 18 20:32:37 2009 +0800 @@ -35,7 +35,7 @@ image-html := $(image-dot:%.dot=%.png) $(image-svg:%.svg=%.png) $(image-png) -example-sources := \ +example-sources-by-name := \ backout \ bisect \ branching \ @@ -67,6 +67,10 @@ tour \ tour-merge-conflict +example-sources := \ + $(example-sources-by-name:%=examples/%) \ + $(wildcard examples/ch*/*) + obj-web := html obj-websup := html/support @@ -162,11 +166,10 @@ examples: $(example-prereqs) examples/.run -examples/.run: $(example-sources:%=examples/%.run) - touch examples/.run +examples/.run: $(example-sources) + cd examples && ./run-example examples/%.run: examples/% examples/run-example - cd examples && ./run-example $(notdir $<) clean: -rm -rf dist html $(image-dot:%.dot=%.pdf) $(image-dot:%.dot=%.png) \ diff -r c2cefd9f9893 -r d0160b0b1a9e en/appB-mq-ref.xml --- a/en/appB-mq-ref.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/appB-mq-ref.xml Wed Mar 18 20:32:37 2009 +0800 @@ -38,11 +38,12 @@ This command is shorthand for hg commit --cwd .hg/patches. - - \subsection{ + + <command role="hg-ext-mq">qdelete</command>&emdash;delete a patch from the <filename role="special">series</filename> - file}</para> + file} The qdelete command removes the entry for a patch from the This book is licensed under the Open Publication License, and is produced entirely using Free Software tools. It is - typeset with \LaTeX{}; illustrations are drawn and rendered with + typeset with DocBook XML. Illustrations are drawn and rendered with Inkscape. The complete source code for this book is published as a diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch02-tour-basic.xml --- a/en/ch02-tour-basic.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch02-tour-basic.xml Wed Mar 18 20:32:37 2009 +0800 @@ -551,7 +551,8 @@ .hgrc should look like this. # This is a Mercurial configuration file. -[ui] username = Firstname Lastname +[ui] +username = Firstname Lastname <email.address@domain.net> The [ui] line begins a @@ -623,8 +624,8 @@ changeset: 73:584af0e231be -user: Censored Person <censored.person@example.org> -date: Tue Sep 26 21:37:07 2006 -0700 +user: Censored Person <censored.person@example.org> +date: Tue Sep 26 21:37:07 2006 -0700 summary: include buildmeister/commondefs. Add exports. As far as the remainder of the contents of the diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch03-tour-merge.xml --- a/en/ch03-tour-merge.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch03-tour-merge.xml Wed Mar 18 20:32:37 2009 +0800 @@ -344,9 +344,9 @@ The process of merging changes as outlined above is straightforward, but requires running three commands in sequence. - - hg pull hg merge hg commit -m 'Merged remote changes' - + hg pull +hg merge +hg commit -m 'Merged remote changes' In the case of the final commit, you also need to enter a commit message, which is almost always going to be a piece of uninteresting boilerplate text. @@ -383,9 +383,8 @@ extensions section. Then add a line that simply reads fetch . - - [extensions] fetch = - + [extensions] +fetch = (Normally, on the right-hand side of the = would appear the location of the extension, but since the The :22 identifies the port number to connect to the server on. The default port is - 22, so you only need to specify this part if you're - not using port 22. + 22, so you only need to specify a colon and port number if + you're not using port 22. The remainder of the URL is the local path to the repository on the server. @@ -595,19 +595,20 @@ If you have a high tolerance for pain, you can use the Cygwin port of OpenSSH. - In either case, you'll need to edit your \hgini\ file to + In either case, you'll need to edit your hg.ini file to tell Mercurial where to find the actual client command. For example, if you're using PuTTY, you'll need to use the plink command as a command-line ssh client. - [ui] ssh = C:/path/to/plink.exe -ssh -i - "C:/path/to/my/private/key" + [ui] +ssh = C:/path/to/plink.exe -ssh -i "C:/path/to/my/private/key" The path to plink shouldn't contain any whitespace characters, or Mercurial may not be able to run it correctly (so putting it in C:\\Program Files is probably + class="directory">C:\Program Files is probably not a good idea). @@ -784,7 +785,9 @@ your server, the next step is to ensure that Mercurial runs on the server. The following command should run successfully: + ssh myserver hg version + If you see an error message instead of normal hg version output, this is usually because you haven't installed Mercurial to Both ssh and plink accept a option which turns on compression. You can easily edit your /.hgrc\ to enable compression for + role="special">~/.hgrc to enable compression for all of Mercurial's uses of the ssh protocol. - [ui] ssh = ssh -C + [ui] +ssh = ssh -C If you use ssh, you can configure it to always use compression when talking to your server. To do this, edit your .ssh/config file (which may not yet exist), as follows. - Host hg Compression yes HostName - hg.example.com + Host hg + Compression yes + HostName hg.example.com This defines an alias, hg. When you use it on the ssh command line or in a Mercurial ssh-protocol URL, it will cause @@ -926,8 +931,7 @@ directory, from which they can serve up web pages. A file named foo in this directory will be accessible at a URL of the form - http://www.example.com/\ - {username/foo}. + http://www.example.com/username/foo. To get started, find the hgweb.cgi script that should be @@ -939,8 +943,8 @@ You'll need to copy this script into your public_html directory, and ensure that it's executable. - cp .../hgweb.cgi ~/public_html chmod 755 - ~/public_html/hgweb.cgi + cp .../hgweb.cgi ~/public_html +chmod 755 ~/public_html/hgweb.cgi The 755 argument to chmod is a little more general than just making the script executable: it ensures that the script is @@ -989,9 +993,9 @@ class="directory">public_html directory, and read files under the latter too. Here's a quick recipe to help you to make your permissions more appropriate. - chmod 755 ~ find ~/public_html -type d -print0 - | xargs -0r chmod 755 find ~/public_html -type f -print0 | - xargs -0r chmod 644 + chmod 755 ~ +find ~/public_html -type d -print0 | xargs -0r chmod 755 +find ~/public_html -type f -print0 | xargs -0r chmod 644 The other possibility with permissions is that you might get a completely empty window when you try to load the @@ -1004,13 +1008,9 @@ of CGI programs in your per-user web directory. Here's Apache's default per-user configuration from my Fedora system. - <Directory /home/*/public_html> - AllowOverride FileInfo AuthConfig Limit Options MultiViews - Indexes SymLinksIfOwnerMatch IncludesNoExec <Limit GET - POST OPTIONS> Order allow,deny Allow from all - </Limit> <LimitExcept GET POST OPTIONS> Order - deny,allow Deny from all </LimitExcept> - </Directory> + + &ch06-apache-config.lst; + If you find a similar-looking Directory group in your Apache configuration, the directive to look at inside it is @@ -1076,8 +1076,8 @@ mod_userdir, both of which were disabled by default on my system. I then added a few lines to the end of the config file, to configure these modules. - userdir.path = "public_html" cgi.assign = ( - ".cgi" => "" ) + userdir.path = "public_html" +cgi.assign = (".cgi" => "" ) With this done, lighttpd ran immediately for me. If I had configured lighttpd before Apache, I'd almost @@ -1112,8 +1112,8 @@ You'll need to copy this script into your public_html directory, and ensure that it's executable. - cp .../hgwebdir.cgi ~/public_html chmod 755 - ~/public_html ~/public_html/hgwebdir.cgi + cp .../hgwebdir.cgi ~/public_html +chmod 755 ~/public_html ~/public_html/hgwebdir.cgi With basic configuration out of the way, try to visit http://myhostname/ @@ -1139,8 +1139,8 @@ publish every repository under the directories you name. The section should look like this: - [collections] /my/root = - /my/root + [collections] +/my/root = /my/root Mercurial interprets this by looking at the directory name on the right hand side of the = sign; finding repositories @@ -1199,8 +1199,9 @@ to publish a specific list of repositories. To do so, create a paths section, with contents of the following form. - [paths] repo1 = /my/path/to/some/repo repo2 = - /some/path/to/another + [paths] +repo1 = /my/path/to/some/repo +repo2 = /some/path/to/another In this case, the virtual path (the component that will appear in a URL) is on the left hand side of each definition, while the path to the repository is on the @@ -1234,7 +1235,7 @@ you'll need to add an allow_archive item to the web section of your /.hgrc. + role="special">~/.hgrc. @@ -1277,8 +1278,8 @@ allow_archive entry at all, this feature will be disabled. Here is an example of how to enable all three supported formats. - [web] allow_archive = bz2 gz - zip + [web] +allow_archive = bz2 gz zip allowpull: Boolean. Determines whether the web interface allows @@ -1296,9 +1297,9 @@ address of a person or mailing list. It often makes sense to place this entry in a repository's own .hg/hgrc file, but it can make - sense to use in a global - /.hgrc\ if every repository has a single - maintainer. + sense to use in a global ~/.hgrc if every repository + has a single maintainer. maxchanges: Integer. The default maximum number of changesets to @@ -1323,7 +1324,8 @@ for details. Here, you can see how to enable the gitweb style. - [web] style = gitweb + [web] +style = gitweb templates: Path. The directory in which to search for template @@ -1335,7 +1337,7 @@ configuration items in a web section of the hgweb.config file instead of a - /.hgrc\ file, for + ~/.hgrc file, for convenience. These items are motd and style. @@ -1346,8 +1348,7 @@ A few web configuration items ought to be placed in a repository's local .hg/hgrc, rather than a user's - or global - /.hgrc. + or global ~/.hgrc. description: String. A @@ -1367,7 +1368,7 @@ Some of the items in the web section of a /.hgrc\ file are only for use + role="special">~/.hgrc file are only for use with the hg serve command. @@ -1401,8 +1402,8 @@ - Choosing the right <filename role="special"> - /.hgrc</filename>\ file to add <literal + <title>Choosing the right <filename + role="special">~/.hgrc</filename> file to add <literal role="rc-web">web</literal> items to It is important to remember that a web server like @@ -1413,16 +1414,15 @@ under that user ID. If you add web items to - your own personal - /.hgrc\ file, CGI scripts won't read that - /.hgrc\ file. Those + your own personal ~/.hgrc file, CGI scripts won't read that + ~/.hgrc file. Those settings will thus only affect the behaviour of the hg serve command when you run it. To cause CGI scripts to see your settings, either create a - /.hgrc\ file in the + ~/.hgrc file in the home directory of the user ID that runs your web server, or add those settings to a system-wide /.hgrc\ file. + role="special">~/.hgrc file. diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch08-branch.xml --- a/en/ch08-branch.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch08-branch.xml Wed Mar 18 20:32:37 2009 +0800 @@ -520,8 +520,8 @@ stable branch. Such a hook might look like this inside the shared repo's /.hgrc. - [hooks] pretxnchangegroup.branch = hg heads - --template '{branches} ' | grep mybranch + [hooks] +pretxnchangegroup.branch = hg heads --template '{branches} ' | grep mybranch diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch10-hook.xml --- a/en/ch10-hook.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch10-hook.xml Wed Mar 18 20:32:37 2009 +0800 @@ -115,7 +115,7 @@ In some cases, you may be exposed to hooks that you did not install yourself. If you work with Mercurial on an unfamiliar system, Mercurial will run hooks defined in that - system's global /.hgrc\ + system's global ~/.hgrc file. @@ -175,8 +175,7 @@ In a corporate intranet, this is somewhat easier to control, as you can for example provide a standard installation of Mercurial on an NFS - filesystem, and use a site-wide - /.hgrc\ file to define hooks that all users will + filesystem, and use a site-wide ~/.hgrc file to define hooks that all users will see. However, this too has its limits; see below. @@ -190,7 +189,7 @@ If you deploy a system- or site-wide /.hgrc\ file that defines some + role="special">~/.hgrc file that defines some hooks, you should thus understand that your users can disable or override those hooks. @@ -203,7 +202,7 @@ want others to be able to work around. For example, you may have a requirement that every changeset must pass a rigorous set of tests. Defining this requirement via a hook in a - site-wide /.hgrc\ won't + site-wide ~/.hgrc won't work for remote users on laptops, and of course local users can subvert it at will by overriding the hook. @@ -359,7 +358,7 @@ You add an entry to the hooks section of your /.hgrc. On the left is the name of + role="special">~/.hgrc. On the left is the name of the event to trigger on; on the right is the action to take. As you can see, you can run an arbitrary shell command in a hook. Mercurial passes extra information to the hook using environment @@ -533,7 +532,7 @@ Writing an external hook When you define an external hook in your /.hgrc\ and the hook is run, its + role="special">~/.hgrc and the hook is run, its value is passed to your shell, which interprets it. This means that you can use normal shell constructs in the body of the hook. @@ -561,7 +560,7 @@ Telling Mercurial to use an in-process hook - The /.hgrc\ syntax + The ~/.hgrc syntax for defining an in-process hook is slightly different than for an executable hook. The value of the hook must start with the text python:, and continue @@ -575,12 +574,12 @@ work. - The following /.hgrc\ + The following ~/.hgrc example snippet illustrates the syntax and meaning of the notions we just described. - [hooks] commit.example = - python:mymodule.submodule.myhook + [hooks] +commit.example = python:mymodule.submodule.myhook When Mercurial runs the commit.example hook, it imports mymodule.submodule, looks for the callable object named myhook, and @@ -595,7 +594,7 @@ the basic shape of the hook API: def myhook(ui, repo, **kwargs): - pass + pass The first argument to a Python hook is always a ui object. The second is a repository object; at the moment, it is always an @@ -745,8 +744,8 @@ changeset, and roll back a group of changesets if they modify forbidden files. Example: - [hooks] pretxnchangegroup.acl = - python:hgext.acl.hook + [hooks] +pretxnchangegroup.acl = python:hgext.acl.hook The acl extension is configured using three sections. @@ -813,8 +812,10 @@ to any file or directory except source/sensitive. - [acl.allow] docs/** = docwriter [acl.deny] - source/sensitive/** = intern + [acl.allow] +docs/** = docwriter +[acl.deny] +source/sensitive/** = intern @@ -827,9 +828,10 @@ possible) to pass in the option, don't forget that you can enable debugging output in your /.hgrc: + role="special">~/.hgrc: - [ui] debug = true + [ui] +debug = true With this enabled, the acl hook will print enough information to let you figure out why it is allowing or @@ -893,12 +895,12 @@ hook You should configure this hook in your server's - /.hgrc\ as an ~/.hgrc as an incoming hook, for example as follows: - [hooks] incoming.bugzilla = - python:hgext.bugzilla.hook + [hooks] +incoming.bugzilla = python:hgext.bugzilla.hook Because of the specialised nature of this hook, and because Bugzilla was not written with this kind of @@ -915,7 +917,7 @@ Configuration information for this hook lives in the bugzilla section of - your /.hgrc. + your ~/.hgrc. /.hgrc\ file where you + role="special">~/.hgrc file where you store this information. @@ -1005,8 +1007,8 @@ email address on the left, and a Bugzilla user name on the right. - [usermap] jane.user@example.com = - jane + [usermap] +jane.user@example.com = jane You can either keep the usermap data in a normal ~/.hgrc, or tell the @@ -1017,18 +1019,17 @@ a user-modifiable repository. This makes it possible to let your users maintain their own usermap entries. The main - /.hgrc\ file might look + ~/.hgrc file might look like this: - # regular hgrc file refers to external usermap - file [bugzilla] usermap = - /home/hg/repos/userdata/bugzilla-usermap.conf + # regular hgrc file refers to external usermap file +[bugzilla] +usermap = /home/hg/repos/userdata/bugzilla-usermap.conf While the usermap file that it refers to might look like this: - # bugzilla-usermap.conf - inside a hg - repository [usermap] stephanie@example.com = - steph + # bugzilla-usermap.conf - inside a hg repository +[usermap] stephanie@example.com = steph @@ -1036,7 +1037,7 @@ You can configure the text that this hook adds as a comment; you specify it in the form of a Mercurial template. - Several /.hgrc\ entries + Several ~/.hgrc entries (still in the bugzilla section) control this behaviour. @@ -1068,27 +1069,20 @@ In addition, you can add a baseurl item to the web section of your /.hgrc. The ~/.hgrc. The bugzilla hook will make this available when expanding a template, as the base string to use when constructing a URL that will let users browse from a Bugzilla comment to view a changeset. Example: - [web] baseurl = - http://hg.domain.com/ + [web] +baseurl = http://hg.domain.com/ Here is an example set of bugzilla hook config information. - [bugzilla] host = bugzilla.example.com - password = mypassword version = 2.16 # server-side repos - live in /home/hg/repos, so strip 4 leading # separators - strip = 4 hgweb = http://hg.example.com/ usermap = - /home/hg/repos/notify/bugzilla.conf template = Changeset - {node|short}, made by {author} in the {webroot} repo, refers - to this bug.\\nFor complete details, see - {hgweb}{webroot}?cmd=changeset;node={node|short}\\nChangeset - description:\\n\\t{desc|tabindent} + + &ch10-bugzilla-config.lst; @@ -1116,9 +1110,8 @@ sudo command. Here is an example entry for a sudoers file. - hg_user = (httpd_user) NOPASSWD: - /var/www/html/bugzilla/processmail-wrapper - %s + hg_user = (httpd_user) +NOPASSWD: /var/www/html/bugzilla/processmail-wrapper %s This allows the hg_user user to run a processmail-wrapper program under the identity of httpd_user. @@ -1131,8 +1124,8 @@ sudoers file. The contents of the wrapper script are simple: - #!/bin/sh cd `dirname $0` && - ./processmail "$1" nobody@example.com + #!/bin/sh +cd `dirname $0` && ./processmail "$1" nobody@example.com It doesn't seem to matter what email address you pass to processmail. @@ -1143,8 +1136,7 @@ push changes to the server. The error message will look like this: - cannot find bugzilla user id for - john.q.public@example.com + cannot find bugzilla user id for john.q.public@example.com What this means is that the committer's address, john.q.public@example.com, is not a valid Bugzilla user name, nor does it have an entry in your @@ -1189,14 +1181,15 @@ changesets (all those that arrived in a single pull or push). - [hooks] # send one email per group of changes - changegroup.notify = python:hgext.notify.hook # send one - email per change incoming.notify = - python:hgext.notify.hook + [hooks] +# send one email per group of changes +changegroup.notify = python:hgext.notify.hook +# send one email per change +incoming.notify = python:hgext.notify.hook Configuration information for this hook lives in the notify section of a - /.hgrc\ file. + ~/.hgrc file. test: @@ -1214,7 +1207,7 @@ config: The path to a configuration file that contains subscription information. This is kept separate from - the main /.hgrc\ so + the main ~/.hgrc so that you can maintain it in a repository of its own. People can then clone that repository, update their subscriptions, and push the changes back to your server. @@ -1273,35 +1266,14 @@ Here is an example set of notify configuration information. - - [notify] # really send email test = false # subscriber data - lives in the notify repo config = - /home/hg/repos/notify/notify.conf # repos live in - /home/hg/repos on server, so strip 4 "/" chars strip = 4 - template = X-Hg-Repo: {webroot} Subject: {webroot}: - {desc|firstline|strip} From: {author} changeset {node|short} - in {root} details: - {baseurl}{webroot}?cmd=changeset;node={node|short} - description: {desc|tabindent|strip} [web] baseurl = - http://hg.example.com/ - + + &ch10-notify-config.lst; This will produce a message that looks like the following: - - X-Hg-Repo: tests/slave Subject: tests/slave: Handle error - case when slave has no buffers Date: Wed, 2 Aug 2006 - 15:25:46 -0700 (PDT) changeset 3cba9bfe74b5 in - /home/hg/repos/tests/slave details: - http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5 - description: Handle error case when slave has no buffers - diffs (54 lines): diff -r 9d95df7cf2ad -r 3cba9bfe74b5 - include/tests.h --- a/include/tests.h Wed Aug 02 - 15:19:52 2006 -0700 +++ b/include/tests.h Wed Aug 02 - 15:25:26 2006 -0700 @@ -212,6 +212,15 @@ static __inline__ - void test_headers(void *h) [...snip...] - + + &ch10-notify-config-mail.lst; @@ -1327,9 +1299,7 @@ An in-process hook is called with arguments of the following form: - - def myhook(ui, repo, **kwargs): pass - + def myhook(ui, repo, **kwargs): pass The ui parameter is a ui object. The repo parameter is a Note that changeset IDs are passed into Python hooks as hexadecimal strings, not the binary hashes that Mercurial's APIs normally use. To convert a hash from hex to binary, use - the \pymodfunc{mercurial.node}{bin} function. + the bin function. @@ -1526,9 +1496,8 @@ node: A changeset ID. The changeset ID of the first changeset in the group that was added. All changesets between this and - \index{tags!tip}tip, - inclusive, were added by a single hg pull, tip, inclusive, were added by a single + hg pull, hg push or hg unbundle. @@ -1880,7 +1849,7 @@ node: A changeset ID. The changeset ID of the first changeset in the group that was added. All changesets between this and - \index{tags!tip}tip, + tip, inclusive, were added by a single hg pull, hg push or Setting a default style You can modify the output style that Mercurial will use - for every command by editing your - /.hgrc\ file, naming the style you would prefer - to use. + for every command by editing your ~/.hgrc file, naming the style + you would prefer to use. - [ui] style = compact + [ui] +style = compact If you write a style of your own, you can use it by either providing the path to your style file, or copying your style @@ -212,27 +213,27 @@ single replacement, as described below. - \textbackslash\textbackslash: + \: Backslash, \, ASCII 134. - \textbackslash n: Newline, + \n: Newline, ASCII 12. - \textbackslash r: Carriage + \r: Carriage return, ASCII 15. - \textbackslash t: Tab, ASCII + \t: Tab, ASCII 11. - \textbackslash v: Vertical + \v: Vertical tab, ASCII 13. - \textbackslash {: Open curly + {: Open curly brace, {, ASCII 173. - \textbackslash }: Close curly + }: Close curly brace, }, ASCII 175. @@ -548,24 +549,19 @@ The first component is simply Mercurial's way of saying I am giving up. - ___abort___: broken.style:1: parse - error + ___abort___: broken.style:1: parse error Next comes the name of the style file that contains the error. - - abort: ___broken.style___:1: parse error - + abort: ___broken.style___:1: parse error Following the file name is the line number where the error was encountered. - abort: broken.style:___1___: parse - error + abort: broken.style:___1___: parse error Finally, a description of what went wrong. - abort: broken.style:1: ___parse - error___ + abort: broken.style:1: ___parse error___ The description of the problem is not always clear (as in this case), but even when it is cryptic, it diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch12-mq.xml --- a/en/ch12-mq.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch12-mq.xml Wed Mar 18 20:32:37 2009 +0800 @@ -256,7 +256,8 @@ role="home">~/.hgrc file, and add the lines below. - [extensions] hgext.mq = + [extensions] +hgext.mq = Once the extension is enabled, it will make a number of new commands available. To verify that the extension is working, @@ -870,11 +871,9 @@ role="hg-opt-update">-C to override the patches you have pushed. - Merge all patches using - \hgcmdargs{qpush}{ }. The option to + Merge all patches using hg qpush -m + -a. The option to qpush tells MQ to perform a three-way merge if the patch fails to apply. @@ -931,10 +930,8 @@ changeset ID will also accept the name of an applied patch. MQ augments the tags normally in the repository with an eponymous one for each applied patch. In addition, the special tags - \index{tags!special tag - names!qbase}qbase and - \index{tags!special tag - names!qtip}qtip identify + qbase and + qtip identify the bottom-most and topmost applied patches, respectively. @@ -943,17 +940,14 @@ Want to patchbomb a mailing list with your latest series of changes? - hg email qbase:qtip - + hg email qbase:qtip (Don't know what patchbombing is? See section .) Need to see all of the patches since foo.patch that have touched files in a subdirectory of your tree? - - hg log -r foo.patch:qtip subdir - + hg log -r foo.patch:qtip subdir @@ -1081,8 +1075,7 @@ snippet in your ~/.bashrc. - alias mq=`hg -R $(hg - root)/.hg/patches' + alias mq=`hg -R $(hg root)/.hg/patches' You can then issue commands of the form mq pull from the main repository. diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch13-mq-collab.xml --- a/en/ch13-mq-collab.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch13-mq-collab.xml Wed Mar 18 20:32:37 2009 +0800 @@ -460,8 +460,9 @@ role="hg-ext">extdiff extension in the usual way, by adding a line to the extensions section of your - /.hgrc. - [extensions] extdiff = + ~/.hgrc. + [extensions] +extdiff = The interdiff command expects to be passed the names of two files, but the extdiff extension passes the program @@ -477,22 +478,20 @@ With the hg-interdiff program in your shell's search path, you can run it as follows, from inside an MQ patch directory: - hg extdiff -p hg-interdiff -r A:B - my-change.patch + hg extdiff -p hg-interdiff -r A:B my-change.patch Since you'll probably want to use this long-winded command a lot, you can get hgext to make it available as a normal Mercurial command, again by - editing your - /.hgrc. - [extdiff] cmd.interdiff = - hg-interdiff + editing your ~/.hgrc. + [extdiff] +cmd.interdiff = hg-interdiff This directs hgext to make an interdiff command available, so you can now shorten the previous invocation of extdiff to something a little more wieldy. - hg interdiff -r A:B - my-change.patch + hg interdiff -r A:B my-change.patch The interdiff command works well diff -r c2cefd9f9893 -r d0160b0b1a9e en/ch14-hgext.xml --- a/en/ch14-hgext.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/ch14-hgext.xml Wed Mar 18 20:32:37 2009 +0800 @@ -166,11 +166,10 @@ Clone the Python inotify binding repository. Build and install it. - - hg clone http://hg.kublai.com/python/inotify cd inotify - python setup.py build --force sudo python setup.py install - --skip-build - + hg clone http://hg.kublai.com/python/inotify +cd inotify +python setup.py build --force +sudo python setup.py install --skip-build Clone the crew Mercurial repository. @@ -178,12 +177,9 @@ repository so that Mercurial Queues will be able to apply patches to your cope of the crew repository. - - hg clone http://hg.intevation.org/mercurial/crew hg clone - crew inotify hg clone - http://hg.kublai.com/mercurial/patches/inotify - inotify/.hg/patches - + hg clone http://hg.intevation.org/mercurial/crew +hg clone crew inotify +hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches Make sure that you have the Mercurial Queues extension, mq, enabled. If @@ -197,9 +193,8 @@ using the option to the qpush command. - - cd inotify hg qpush -a - + cd inotify +hg qpush -a If you get an error message from qpush, you should not continue. @@ -207,16 +202,14 @@ Build and install the patched version of Mercurial. - - python setup.py build --force sudo python setup.py install - --skip-build - + python setup.py build --force +sudo python setup.py install --skip-build Once you've build a suitably patched version of Mercurial, all you need to do to enable the inotify extension is add an entry to - your /.hgrc. + your ~/.hgrc. [extensions] inotify = When the inotify extension is enabled, Mercurial will automatically and transparently start @@ -280,9 +273,10 @@ The extdiff extension is bundled with Mercurial, so it's easy to set up. In the extensions section of your - /.hgrc, simply add a + ~/.hgrc, simply add a one-line entry to enable the extension. - [extensions] extdiff = + [extensions] +extdiff = This introduces a command named extdiff, which by default uses your system's diff command to generate a @@ -372,15 +366,16 @@ new commands that will invoke your diff viewer with exactly the right options. - All you need to do is edit your - /.hgrc, and add a section named extdiff. Inside this section, - you can define multiple commands. Here's how to add a - kdiff3 command. Once you've defined this, - you can type hg kdiff3 and - the extdiff extension will - run kdiff3 for you. - [extdiff] cmd.kdiff3 = + All you need to do is edit your ~/.hgrc, and add a section named + extdiff. Inside this + section, you can define multiple commands. Here's how to add + a kdiff3 command. Once you've defined + this, you can type hg kdiff3 + and the extdiff extension + will run kdiff3 for you. + [extdiff] +cmd.kdiff3 = If you leave the right hand side of the definition empty, as above, the extdiff extension uses the name of the command you defined as the name @@ -388,7 +383,8 @@ be the same. Here, we define a command named hg wibble, which runs kdiff3. - [extdiff] cmd.wibble = kdiff3 + [extdiff] + cmd.wibble = kdiff3 You can also specify the default options that you want to invoke your diff viewing program with. The prefix to use is @@ -397,8 +393,9 @@ defines a hg vimdiff command that runs the vim editor's DirDiff extension. - [extdiff] cmd.vimdiff = vim opts.vimdiff = -f - '+next' '+execute "DirDiff" argv(0) argv(1)' + [extdiff] + cmd.vimdiff = vim +opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)' @@ -433,7 +430,8 @@ role="hg-ext">patchbomb extension takes just one or two lines in your /.hgrc. - [extensions] patchbomb = + [extensions] +patchbomb = Once you've enabled the extension, you will have a new command available, named email. diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/auto-snippets.xml --- a/en/examples/auto-snippets.xml Wed Mar 18 19:50:36 2009 +0800 +++ b/en/examples/auto-snippets.xml Wed Mar 18 20:32:37 2009 +0800 @@ -1,3 +1,7 @@ + + + + diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/ch06/apache-config.lst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/en/examples/ch06/apache-config.lst Wed Mar 18 20:32:37 2009 +0800 @@ -0,0 +1,11 @@ + + AllowOverride FileInfo AuthConfig Limit + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec + + Order allow,deny + Allow from all + + + Order deny,allow Deny from all + + diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/ch10/bugzilla-config.lst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/en/examples/ch10/bugzilla-config.lst Wed Mar 18 20:32:37 2009 +0800 @@ -0,0 +1,14 @@ +[bugzilla] +host = bugzilla.example.com +password = mypassword version = 2.16 +# server-side repos live in /home/hg/repos, so strip 4 leading +# separators +strip = 4 +hgweb = http://hg.example.com/ +usermap = /home/hg/repos/notify/bugzilla.conf +template = Changeset {node|short}, made by {author} in the {webroot} + repo, refers to this bug.\n + For complete details, see + {hgweb}{webroot}?cmd=changeset;node={node|short}\n + Changeset description:\n + \t{desc|tabindent} diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/ch10/notify-config-mail.lst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/en/examples/ch10/notify-config-mail.lst Wed Mar 18 20:32:37 2009 +0800 @@ -0,0 +1,18 @@ +X-Hg-Repo: tests/slave +Subject: tests/slave: Handle error case when slave has no buffers +Date: Wed, 2 Aug 2006 15:25:46 -0700 (PDT) + +changeset 3cba9bfe74b5 in /home/hg/repos/tests/slave + +details: +http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5 + +description: Handle error case when slave has no buffers + +diffs (54 lines): +diff -r 9d95df7cf2ad -r 3cba9bfe74b5 include/tests.h +--- a/include/tests.h Wed Aug 02 15:19:52 2006 -0700 ++++ b/include/tests.h Wed Aug 02 15:25:26 2006 -0700 +@@ -212,6 +212,15 @@ static __inline__ +void test_headers(void *h) +[...snip...] diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/ch10/notify-config.lst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/en/examples/ch10/notify-config.lst Wed Mar 18 20:32:37 2009 +0800 @@ -0,0 +1,19 @@ +[notify] +# really send email +test = false +# subscriber data lives in the notify repo +config = /home/hg/repos/notify/notify.conf +# repos live in /home/hg/repos on server, so strip 4 "/" chars +strip = 4 +template = X-Hg-Repo: {webroot}\n + Subject: {webroot}: {desc|firstline|strip}\n + From: {author} + \n\n + changeset {node|short} in {root} + \n\ndetails: + {baseurl}{webroot}?cmd=changeset;node={node|short} + description: {desc|tabindent|strip} + +[web] +baseurl = +http://hg.example.com/ diff -r c2cefd9f9893 -r d0160b0b1a9e en/examples/run-example --- a/en/examples/run-example Wed Mar 18 19:50:36 2009 +0800 +++ b/en/examples/run-example Wed Mar 18 20:32:37 2009 +0800 @@ -7,6 +7,7 @@ import cStringIO import errno import getopt +import glob import os import pty import re @@ -54,10 +55,89 @@ return None def result_name(name): - dirname, basename = os.path.split(name) - return os.path.join(dirname, 'results', basename) + return os.path.normpath(os.path.join('results', name.replace(os.sep, '-'))) + +def wopen(name): + path = os.path.dirname(name) + if path: + try: + os.makedirs(path) + except OSError, err: + if err.errno != errno.EEXIST: + raise + return open(name, 'w') class example: + entities = dict.fromkeys(l.rstrip() for l in open('auto-snippets.xml')) + + def __init__(self, name, verbose, keep_change): + self.name = os.path.normpath(name) + self.verbose = verbose + self.keep_change = keep_change + + def status(self, s): + sys.stdout.write(s) + if not s.endswith('\n'): + sys.stdout.flush() + + def rename_output(self, base, ignore=[]): + mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') + def mangle(s): + return mangle_re.sub('', s) + def matchfp(fp1, fp2): + while True: + s1 = mangle(fp1.readline()) + s2 = mangle(fp2.readline()) + if cmp(s1, s2): + break + if not s1: + return True + return False + + oldname = result_name(base + '.out') + tmpname = result_name(base + '.tmp') + errname = result_name(base + '.err') + errfp = open(errname, 'w+') + for line in open(tmpname): + errfp.write(mangle_re.sub('', line)) + os.rename(tmpname, result_name(base + '.lxo')) + errfp.seek(0) + try: + oldfp = open(oldname) + except IOError, err: + if err.errno != errno.ENOENT: + raise + os.rename(errname, oldname) + return False + if matchfp(oldfp, errfp): + os.unlink(errname) + return False + else: + print >> sys.stderr, '\nOutput of %s has changed!' % base + if self.keep_change: + os.rename(errname, oldname) + return False + else: + os.system('diff -u %s %s 1>&2' % (oldname, errname)) + return True + +class static_example(example): + def run(self): + self.status('running %s\n' % self.name) + s = open(self.name).read().rstrip() + s = s.replace('&', '&').replace('<', '<').replace('>', '>') + ofp = wopen(result_name(self.name + '.tmp')) + ofp.write('') + ofp.write(s) + ofp.write('\n') + ofp.close() + self.rename_output(self.name) + norm = self.name.replace(os.sep, '-') + example.entities[ + '' % (norm, norm)] = 1 + + +class shell_example(example): shell = '/usr/bin/env bash' ps1 = '__run_example_ps1__ ' ps2 = '__run_example_ps2__ ' @@ -65,12 +145,8 @@ timeout = 10 - entities = dict.fromkeys(l.rstrip() for l in open('auto-snippets.xml')) - def __init__(self, name, verbose, keep_change): - self.name = name - self.verbose = verbose - self.keep_change = keep_change + example.__init__(self, name, verbose, keep_change) self.poll = select.poll() def parse(self): @@ -83,11 +159,6 @@ yield cfp.getvalue() cfp.seek(0) cfp.truncate() - - def status(self, s): - sys.stdout.write(s) - if not s.endswith('\n'): - sys.stdout.flush() def send(self, s): if self.verbose: @@ -153,12 +224,12 @@ maybe_unlink(self.name + '.run') rcfile = os.path.join(tmpdir, '.hgrc') - rcfp = open(rcfile, 'w') + rcfp = wopen(rcfile) print >> rcfp, '[ui]' print >> rcfp, "username = Bryan O'Sullivan " rcfile = os.path.join(tmpdir, '.bashrc') - rcfp = open(rcfile, 'w') + rcfp = wopen(rcfile) print >> rcfp, 'PS1="%s"' % self.ps1 print >> rcfp, 'PS2="%s"' % self.ps2 print >> rcfp, 'unset HISTFILE' @@ -248,8 +319,7 @@ 'SYSTEM "results/%s.out">' % (norm, norm)] = 1 read_hint = ofp_basename + ' ' - ofp = open(result_name(ofp_basename + '.tmp'), - 'w') + ofp = wopen(result_name(ofp_basename + '.tmp')) ofp.write('') else: ofp = None @@ -297,52 +367,11 @@ elif os.WIFSIGNALED(rc): print >> sys.stderr, '(signal %s)' % os.WTERMSIG(rc) else: - open(result_name(self.name + '.run'), 'w') + wopen(result_name(self.name + '.run')) return err finally: shutil.rmtree(tmpdir) - def rename_output(self, base, ignore): - mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') - def mangle(s): - return mangle_re.sub('', s) - def matchfp(fp1, fp2): - while True: - s1 = mangle(fp1.readline()) - s2 = mangle(fp2.readline()) - if cmp(s1, s2): - break - if not s1: - return True - return False - - oldname = result_name(base + '.out') - tmpname = result_name(base + '.tmp') - errname = result_name(base + '.err') - errfp = open(errname, 'w+') - for line in open(tmpname): - errfp.write(mangle_re.sub('', line)) - os.rename(tmpname, result_name(base + '.lxo')) - errfp.seek(0) - try: - oldfp = open(oldname) - except IOError, err: - if err.errno != errno.ENOENT: - raise - os.rename(errname, oldname) - return False - if matchfp(oldfp, errfp): - os.unlink(errname) - return False - else: - print >> sys.stderr, '\nOutput of %s has changed!' % base - if self.keep_change: - os.rename(errname, oldname) - return False - else: - os.system('diff -u %s %s 1>&2' % (oldname, errname)) - return True - def print_help(exit, msg=None): if msg: print >> sys.stderr, 'Error:', msg @@ -383,18 +412,20 @@ print >> sys.stderr, '%s: %s' % (a, err.strerror) errs += 1 continue - if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: - if example(a, verbose, keep_change).run(): - errs += 1 + if stat.S_ISREG(st.st_mode): + if st.st_mode & 0111: + if shell_example(a, verbose, keep_change).run(): + errs += 1 + elif a.endswith('.lst'): + static_example(a, verbose, keep_change).run() else: print >> sys.stderr, '%s: not a file, or not executable' % a errs += 1 elif run_all: - names = os.listdir(path) + names = glob.glob("*") + glob.glob("app*/*") + glob.glob("ch*/*") names.sort() for name in names: - if name == 'run-example' or name.startswith('.'): continue - if name.endswith('~'): continue + if name == 'run-example' or name.endswith('~'): continue pathname = os.path.join(path, name) try: st = os.lstat(pathname) @@ -403,14 +434,17 @@ if err.errno != errno.ENOENT: raise continue - if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: - if example(pathname, verbose, keep_change).run(): - errs += 1 - print >> open(os.path.join(path, '.run'), 'w'), time.asctime() + if stat.S_ISREG(st.st_mode): + if st.st_mode & 0111: + if shell_example(pathname, verbose, keep_change).run(): + errs += 1 + elif pathname.endswith('.lst'): + static_example(pathname, verbose, keep_change).run() + print >> wopen(os.path.join(path, '.run')), time.asctime() else: print_help(1, msg='no test names given, and --all not provided') - fp = open('auto-snippets.xml', 'w') + fp = wopen('auto-snippets.xml') for key in sorted(example.entities.iterkeys()): print >> fp, key fp.close()