hgbook
changeset 579:80928ea6e7ae
Add the ability to include text files and have them XML-mangled.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Tue Mar 17 21:47:12 2009 -0700 (2009-03-17) |
parents | cd978765da64 |
children | 8366882f67f2 |
files | en/ch02-tour-basic.xml en/ch03-tour-merge.xml en/ch06-collab.xml en/examples/auto-snippets.xml en/examples/ch06/apache-config.lst en/examples/run-example |
line diff
1.1 --- a/en/ch02-tour-basic.xml Tue Mar 10 22:40:47 2009 -0700 1.2 +++ b/en/ch02-tour-basic.xml Tue Mar 17 21:47:12 2009 -0700 1.3 @@ -30,21 +30,17 @@ 1.4 1.5 <itemizedlist> 1.6 <listitem><para>Debian:</para> 1.7 - <programlisting>apt-get install 1.8 - mercurial</programlisting></listitem> 1.9 + <programlisting>apt-get install mercurial</programlisting></listitem> 1.10 <listitem><para>Fedora Core:</para> 1.11 - <programlisting>yum install 1.12 - mercurial</programlisting></listitem> 1.13 + <programlisting>yum install mercurial</programlisting></listitem> 1.14 <listitem><para>Gentoo:</para> 1.15 <programlisting>emerge mercurial</programlisting></listitem> 1.16 <listitem><para>OpenSUSE:</para> 1.17 - <programlisting>yum install 1.18 - mercurial</programlisting></listitem> 1.19 + <programlisting>yum install mercurial</programlisting></listitem> 1.20 <listitem><para>Ubuntu: Ubuntu's Mercurial package is based on 1.21 Debian's. To install it, run the following 1.22 command.</para> 1.23 - <programlisting>apt-get install 1.24 - mercurial</programlisting></listitem> 1.25 + <programlisting>apt-get install mercurial</programlisting></listitem> 1.26 </itemizedlist> 1.27 1.28 </sect2> 1.29 @@ -554,7 +550,8 @@ 1.30 <filename role="special">.hgrc</filename> should look like 1.31 this.</para> 1.32 <programlisting># This is a Mercurial configuration file. 1.33 -[ui] username = Firstname Lastname 1.34 +[ui] 1.35 +username = Firstname Lastname 1.36 <email.address@domain.net></programlisting> 1.37 1.38 <para>The <quote><literal>[ui]</literal></quote> line begins a 1.39 @@ -626,8 +623,8 @@ 1.40 1.41 <programlisting> 1.42 changeset: 73:584af0e231be 1.43 -user: Censored Person <censored.person@example.org> 1.44 -date: Tue Sep 26 21:37:07 2006 -0700 1.45 +user: Censored Person <censored.person@example.org> 1.46 +date: Tue Sep 26 21:37:07 2006 -0700 1.47 summary: include buildmeister/commondefs. Add exports.</programlisting> 1.48 1.49 <para>As far as the remainder of the contents of the
2.1 --- a/en/ch03-tour-merge.xml Tue Mar 10 22:40:47 2009 -0700 2.2 +++ b/en/ch03-tour-merge.xml Tue Mar 17 21:47:12 2009 -0700 2.3 @@ -337,9 +337,9 @@ 2.4 <para>The process of merging changes as outlined above is 2.5 straightforward, but requires running three commands in 2.6 sequence.</para> 2.7 - <programlisting> 2.8 - hg pull hg merge hg commit -m 'Merged remote changes' 2.9 - </programlisting> 2.10 + <programlisting>hg pull 2.11 +hg merge 2.12 +hg commit -m 'Merged remote changes'</programlisting> 2.13 <para>In the case of the final commit, you also need to enter a 2.14 commit message, which is almost always going to be a piece of 2.15 uninteresting <quote>boilerplate</quote> text.</para> 2.16 @@ -376,9 +376,8 @@ 2.17 <literal role="rc-extensions">extensions</literal> section. Then 2.18 add a line that simply reads <quote><literal>fetch 2.19 </literal></quote>.</para> 2.20 - <programlisting> 2.21 - [extensions] fetch = 2.22 - </programlisting> 2.23 + <programlisting>[extensions] 2.24 +fetch =</programlisting> 2.25 <para>(Normally, on the right-hand side of the 2.26 <quote><literal>=</literal></quote> would appear the location of 2.27 the extension, but since the <literal
3.1 --- a/en/ch06-collab.xml Tue Mar 10 22:40:47 2009 -0700 3.2 +++ b/en/ch06-collab.xml Tue Mar 17 21:47:12 2009 -0700 3.3 @@ -536,8 +536,8 @@ 3.4 </listitem> 3.5 <listitem><para>The <quote>:22</quote> identifies the port 3.6 number to connect to the server on. The default port is 3.7 - 22, so you only need to specify this part if you're 3.8 - <emphasis>not</emphasis> using port 22.</para> 3.9 + 22, so you only need to specify a colon and port number if 3.10 + you're <emphasis>not</emphasis> using port 22.</para> 3.11 </listitem> 3.12 <listitem><para>The remainder of the URL is the local path to 3.13 the repository on the server.</para> 3.14 @@ -597,8 +597,8 @@ 3.15 example, if you're using PuTTY, you'll need to use the 3.16 <command>plink</command> command as a command-line ssh 3.17 client.</para> 3.18 - <programlisting>[ui] ssh = C:/path/to/plink.exe -ssh -i 3.19 - "C:/path/to/my/private/key"</programlisting> 3.20 + <programlisting>[ui] 3.21 +ssh = C:/path/to/plink.exe -ssh -i "C:/path/to/my/private/key"</programlisting> 3.22 3.23 <note> 3.24 <para> The path to <command>plink</command> shouldn't contain 3.25 @@ -840,15 +840,17 @@ 3.26 turns on compression. You can easily edit your <filename 3.27 role="special"> /.hgrc</filename>\ to enable compression for 3.28 all of Mercurial's uses of the ssh protocol.</para> 3.29 - <programlisting>[ui] ssh = ssh -C</programlisting> 3.30 + <programlisting>[ui] 3.31 +ssh = ssh -C</programlisting> 3.32 3.33 <para>If you use <command>ssh</command>, you can configure it to 3.34 always use compression when talking to your server. To do 3.35 this, edit your <filename 3.36 role="special">.ssh/config</filename> file (which may not 3.37 yet exist), as follows.</para> 3.38 - <programlisting>Host hg Compression yes HostName 3.39 - hg.example.com</programlisting> 3.40 + <programlisting>Host hg 3.41 + Compression yes 3.42 + HostName hg.example.com</programlisting> 3.43 <para>This defines an alias, <literal>hg</literal>. When you 3.44 use it on the <command>ssh</command> command line or in a 3.45 Mercurial <literal>ssh</literal>-protocol URL, it will cause 3.46 @@ -936,8 +938,8 @@ 3.47 <para>You'll need to copy this script into your <filename 3.48 class="directory">public_html</filename> directory, and 3.49 ensure that it's executable.</para> 3.50 - <programlisting>cp .../hgweb.cgi ~/public_html chmod 755 3.51 - ~/public_html/hgweb.cgi</programlisting> 3.52 + <programlisting>cp .../hgweb.cgi ~/public_html 3.53 +chmod 755 ~/public_html/hgweb.cgi</programlisting> 3.54 <para>The <literal>755</literal> argument to 3.55 <command>chmod</command> is a little more general than just 3.56 making the script executable: it ensures that the script is 3.57 @@ -986,9 +988,9 @@ 3.58 class="directory">public_html</filename> directory, and 3.59 read files under the latter too. Here's a quick recipe to 3.60 help you to make your permissions more appropriate.</para> 3.61 - <programlisting>chmod 755 ~ find ~/public_html -type d -print0 3.62 - | xargs -0r chmod 755 find ~/public_html -type f -print0 | 3.63 - xargs -0r chmod 644</programlisting> 3.64 + <programlisting>chmod 755 ~ 3.65 +find ~/public_html -type d -print0 | xargs -0r chmod 755 3.66 +find ~/public_html -type f -print0 | xargs -0r chmod 644</programlisting> 3.67 3.68 <para>The other possibility with permissions is that you might 3.69 get a completely empty window when you try to load the 3.70 @@ -1001,6 +1003,9 @@ 3.71 of CGI programs in your per-user web directory. Here's 3.72 Apache's default per-user configuration from my Fedora 3.73 system.</para> 3.74 + 3.75 + &ch06-apache-config.lst; 3.76 + 3.77 <programlisting><Directory /home/*/public_html> 3.78 AllowOverride FileInfo AuthConfig Limit Options MultiViews 3.79 Indexes SymLinksIfOwnerMatch IncludesNoExec <Limit GET
4.1 --- a/en/examples/auto-snippets.xml Tue Mar 10 22:40:47 2009 -0700 4.2 +++ b/en/examples/auto-snippets.xml Tue Mar 17 21:47:12 2009 -0700 4.3 @@ -1,3 +1,4 @@ 4.4 +<!ENTITY ch06-apache-config.lst SYSTEM "results/ch06-apache-config.lst.out"> 4.5 <!ENTITY interaction.backout.init SYSTEM "results/backout.init.out"> 4.6 <!ENTITY interaction.backout.manual.backout SYSTEM "results/backout.manual.backout.out"> 4.7 <!ENTITY interaction.backout.manual.cat SYSTEM "results/backout.manual.cat.out">
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/en/examples/ch06/apache-config.lst Tue Mar 17 21:47:12 2009 -0700 5.3 @@ -0,0 +1,11 @@ 5.4 +<Directory /home/*/public_html> 5.5 + AllowOverride FileInfo AuthConfig Limit 5.6 + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec 5.7 + <Limit GET POST OPTIONS> 5.8 + Order allow,deny 5.9 + Allow from all 5.10 + </Limit> 5.11 + <LimitExcept GET POST OPTIONS> 5.12 + Order deny,allow Deny from all 5.13 + </LimitExcept> 5.14 +</Directory>
6.1 --- a/en/examples/run-example Tue Mar 10 22:40:47 2009 -0700 6.2 +++ b/en/examples/run-example Tue Mar 17 21:47:12 2009 -0700 6.3 @@ -54,10 +54,83 @@ 6.4 return None 6.5 6.6 def result_name(name): 6.7 - dirname, basename = os.path.split(name) 6.8 - return os.path.join(dirname, 'results', basename) 6.9 + return os.path.join('results', name.replace(os.sep, '-')) 6.10 6.11 class example: 6.12 + entities = dict.fromkeys(l.rstrip() for l in open('auto-snippets.xml')) 6.13 + 6.14 + def __init__(self, name, verbose, keep_change): 6.15 + self.name = name 6.16 + self.verbose = verbose 6.17 + self.keep_change = keep_change 6.18 + 6.19 + def rename_output(self, base, ignore=[]): 6.20 + mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') 6.21 + def mangle(s): 6.22 + return mangle_re.sub('', s) 6.23 + def matchfp(fp1, fp2): 6.24 + while True: 6.25 + s1 = mangle(fp1.readline()) 6.26 + s2 = mangle(fp2.readline()) 6.27 + if cmp(s1, s2): 6.28 + break 6.29 + if not s1: 6.30 + return True 6.31 + return False 6.32 + 6.33 + oldname = result_name(base + '.out') 6.34 + tmpname = result_name(base + '.tmp') 6.35 + errname = result_name(base + '.err') 6.36 + errfp = open(errname, 'w+') 6.37 + for line in open(tmpname): 6.38 + errfp.write(mangle_re.sub('', line)) 6.39 + os.rename(tmpname, result_name(base + '.lxo')) 6.40 + errfp.seek(0) 6.41 + try: 6.42 + oldfp = open(oldname) 6.43 + except IOError, err: 6.44 + if err.errno != errno.ENOENT: 6.45 + raise 6.46 + os.rename(errname, oldname) 6.47 + return False 6.48 + if matchfp(oldfp, errfp): 6.49 + os.unlink(errname) 6.50 + return False 6.51 + else: 6.52 + print >> sys.stderr, '\nOutput of %s has changed!' % baseq 6.53 + if self.keep_change: 6.54 + os.rename(errname, oldname) 6.55 + return False 6.56 + else: 6.57 + os.system('diff -u %s %s 1>&2' % (oldname, errname)) 6.58 + return True 6.59 + 6.60 +def wopen(name): 6.61 + path = os.path.dirname(name) 6.62 + if path: 6.63 + try: 6.64 + os.makedirs(path) 6.65 + except OSError, err: 6.66 + if err.errno != errno.EEXIST: 6.67 + raise 6.68 + return open(name, 'w') 6.69 + 6.70 +class static_example(example): 6.71 + def run(self): 6.72 + s = open(self.name).read().rstrip() 6.73 + s = s.replace('&', '&').replace('<', '<').replace('>', '>') 6.74 + ofp = wopen(result_name(self.name + '.tmp')) 6.75 + ofp.write('<programlisting>') 6.76 + ofp.write(s) 6.77 + ofp.write('</programlisting>\n') 6.78 + ofp.close() 6.79 + self.rename_output(self.name) 6.80 + norm = self.name.replace(os.sep, '-') 6.81 + example.entities[ 6.82 + '<!ENTITY %s SYSTEM "results/%s.out">' % (norm, norm)] = 1 6.83 + 6.84 + 6.85 +class shell_example(example): 6.86 shell = '/usr/bin/env bash' 6.87 ps1 = '__run_example_ps1__ ' 6.88 ps2 = '__run_example_ps2__ ' 6.89 @@ -65,12 +138,8 @@ 6.90 6.91 timeout = 10 6.92 6.93 - entities = dict.fromkeys(l.rstrip() for l in open('auto-snippets.xml')) 6.94 - 6.95 def __init__(self, name, verbose, keep_change): 6.96 - self.name = name 6.97 - self.verbose = verbose 6.98 - self.keep_change = keep_change 6.99 + example.__init__(self, name, verbose, keep_change) 6.100 self.poll = select.poll() 6.101 6.102 def parse(self): 6.103 @@ -153,12 +222,12 @@ 6.104 maybe_unlink(self.name + '.run') 6.105 6.106 rcfile = os.path.join(tmpdir, '.hgrc') 6.107 - rcfp = open(rcfile, 'w') 6.108 + rcfp = wopen(rcfile) 6.109 print >> rcfp, '[ui]' 6.110 print >> rcfp, "username = Bryan O'Sullivan <bos@serpentine.com>" 6.111 6.112 rcfile = os.path.join(tmpdir, '.bashrc') 6.113 - rcfp = open(rcfile, 'w') 6.114 + rcfp = wopen(rcfile) 6.115 print >> rcfp, 'PS1="%s"' % self.ps1 6.116 print >> rcfp, 'PS2="%s"' % self.ps2 6.117 print >> rcfp, 'unset HISTFILE' 6.118 @@ -248,8 +317,7 @@ 6.119 'SYSTEM "results/%s.out">' 6.120 % (norm, norm)] = 1 6.121 read_hint = ofp_basename + ' ' 6.122 - ofp = open(result_name(ofp_basename + '.tmp'), 6.123 - 'w') 6.124 + ofp = wopen(result_name(ofp_basename + '.tmp')) 6.125 ofp.write('<screen>') 6.126 else: 6.127 ofp = None 6.128 @@ -297,52 +365,11 @@ 6.129 elif os.WIFSIGNALED(rc): 6.130 print >> sys.stderr, '(signal %s)' % os.WTERMSIG(rc) 6.131 else: 6.132 - open(result_name(self.name + '.run'), 'w') 6.133 + wopen(result_name(self.name + '.run')) 6.134 return err 6.135 finally: 6.136 shutil.rmtree(tmpdir) 6.137 6.138 - def rename_output(self, base, ignore): 6.139 - mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') 6.140 - def mangle(s): 6.141 - return mangle_re.sub('', s) 6.142 - def matchfp(fp1, fp2): 6.143 - while True: 6.144 - s1 = mangle(fp1.readline()) 6.145 - s2 = mangle(fp2.readline()) 6.146 - if cmp(s1, s2): 6.147 - break 6.148 - if not s1: 6.149 - return True 6.150 - return False 6.151 - 6.152 - oldname = result_name(base + '.out') 6.153 - tmpname = result_name(base + '.tmp') 6.154 - errname = result_name(base + '.err') 6.155 - errfp = open(errname, 'w+') 6.156 - for line in open(tmpname): 6.157 - errfp.write(mangle_re.sub('', line)) 6.158 - os.rename(tmpname, result_name(base + '.lxo')) 6.159 - errfp.seek(0) 6.160 - try: 6.161 - oldfp = open(oldname) 6.162 - except IOError, err: 6.163 - if err.errno != errno.ENOENT: 6.164 - raise 6.165 - os.rename(errname, oldname) 6.166 - return False 6.167 - if matchfp(oldfp, errfp): 6.168 - os.unlink(errname) 6.169 - return False 6.170 - else: 6.171 - print >> sys.stderr, '\nOutput of %s has changed!' % base 6.172 - if self.keep_change: 6.173 - os.rename(errname, oldname) 6.174 - return False 6.175 - else: 6.176 - os.system('diff -u %s %s 1>&2' % (oldname, errname)) 6.177 - return True 6.178 - 6.179 def print_help(exit, msg=None): 6.180 if msg: 6.181 print >> sys.stderr, 'Error:', msg 6.182 @@ -383,18 +410,20 @@ 6.183 print >> sys.stderr, '%s: %s' % (a, err.strerror) 6.184 errs += 1 6.185 continue 6.186 - if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: 6.187 - if example(a, verbose, keep_change).run(): 6.188 - errs += 1 6.189 + if stat.S_ISREG(st.st_mode): 6.190 + if st.st_mode & 0111: 6.191 + if shell_example(a, verbose, keep_change).run(): 6.192 + errs += 1 6.193 + elif a.endswith('.lst'): 6.194 + static_example(a, verbose, keep_change).run() 6.195 else: 6.196 print >> sys.stderr, '%s: not a file, or not executable' % a 6.197 errs += 1 6.198 elif run_all: 6.199 - names = os.listdir(path) 6.200 + names = glob.glob("*") + glob.glob("app*/*") + glob.glob("ch*/*") 6.201 names.sort() 6.202 for name in names: 6.203 - if name == 'run-example' or name.startswith('.'): continue 6.204 - if name.endswith('~'): continue 6.205 + if name == 'run-example' or name.endswith('~'): continue 6.206 pathname = os.path.join(path, name) 6.207 try: 6.208 st = os.lstat(pathname) 6.209 @@ -403,14 +432,17 @@ 6.210 if err.errno != errno.ENOENT: 6.211 raise 6.212 continue 6.213 - if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: 6.214 - if example(pathname, verbose, keep_change).run(): 6.215 - errs += 1 6.216 - print >> open(os.path.join(path, '.run'), 'w'), time.asctime() 6.217 + if stat.S_ISREG(st.st_mode): 6.218 + if st.st_mode & 0111: 6.219 + if shell_example(pathname, verbose, keep_change).run(): 6.220 + errs += 1 6.221 + elif pathname.endswith('.lst'): 6.222 + static_example(pathname, verbose, keep_change).run() 6.223 + print >> wopen(os.path.join(path, '.run')), time.asctime() 6.224 else: 6.225 print_help(1, msg='no test names given, and --all not provided') 6.226 6.227 - fp = open('auto-snippets.xml', 'w') 6.228 + fp = wopen('auto-snippets.xml') 6.229 for key in sorted(example.entities.iterkeys()): 6.230 print >> fp, key 6.231 fp.close()