Commits

Bryan O'Sullivan committed 18210d4

More hook content.

Comments (0)

Files changed (6)

 % Python module.
 \newcommand{\pymod}[1]{\index{\texttt{#1} module}\texttt{#1}}
 
+% Bundled extension.
+\newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}}
+
 % Python class in a module.
 \newcommand{\pymodclass}[2]{\index{\texttt{#1} module!\texttt{#2}
     class}\texttt{#1.#2}}
 
 example-sources := \
 	examples/daily.files \
+	examples/hook.msglen \
 	examples/hook.simple \
 	examples/hook.ws \
 	examples/mq.qinit-help \

en/examples/data/check_whitespace.py

 #!/usr/bin/python
 
-import os, re, sys
+import re
 
-count = 0
+def trailing_whitespace(difflines):
+    added, linenum, header = [], 0, False
 
-for line in os.popen('hg export tip'):
-    # remember the name of the file that this diff affects
-    m = re.match(r'^--- [^/]/([^\t])', line)
-    if m: 
-	filename = m.group(1)
-	continue
-    # remember the line number
-    m = re.match(r'^@@ -(\d+),')
-    if m:
-        linenum = m.group(1)
-        continue
-    linenum += 1
-    # check for an added line with trailing whitespace
-    m = re.match(r'^\+.*\s$', line)
-    if m:
-	print >> sys.stderr, ('%s:%d: trailing whitespace introduced' %
-                              (filename, linenum))
-        count += 1
+    for line in difflines:
+        if header:
+            if line.startswith('+++ '):
+                header = False
+            else:
+                # remember the name of the file that this diff affects
+                m = re.match(r'--- [^/]/([^\t])', line)
+                if m: filename = m.group(1)
+            continue
+        if line.startswith('diff '):
+            header = True
+            continue
+        # hunk header - save the line number
+        m = re.match(r'@@ -(\d+),', line)
+        if m:
+            linenum = int(m.group(1))
+            continue
+        # hunk body - check for an added line with trailing whitespace
+        m = re.match(r'\+.*\s$', line)
+        if m:
+            added.append((filename, linenum))
+        if line and line[0] in ' +':
+            linenum += 1
+    return added
 
-if count:
-    # save the commit message so we don't need to retype it
-    os.system('hg tip --template "{desc}" > .hg/commit.save')
-    print >> sys.stderr, 'commit message saved to .hg/commit.save'
-
-sys.exit(count)
+if __name__ == '__main__':
+    import os, sys
+    
+    added = trailing_whitespace(os.popen('hg export tip'))
+    if added:
+        for filename, linenum in added:
+            print >> sys.stderr, ('%s, line %d: trailing whitespace added' %
+                                  (filename, linenum))
+        # save the commit message so we don't need to retype it
+        os.system('hg tip --template "{desc}" > .hg/commit.save')
+        print >> sys.stderr, 'commit message saved to .hg/commit.save'
+        sys.exit(1)

en/examples/hook.msglen

+#!/bin/sh
+
+hg init a
+cd a
+echo '[hooks]' > .hg/hgrc
+echo 'pretxncommit.msglen = test `hg tip --template {desc} | wc -c` -ge 10' >> .hg/hgrc
+
+#$ name: run
+
+cat .hg/hgrc
+echo a > a
+hg add a
+hg commit -A -m 'too short'
+hg commit -A -m 'long enough'

en/examples/hook.ws

 #!/bin/bash
 
-cp $EXAMPLE_DIR/data/check_whitespace.py .
-
 hg init a
 cd a
 echo '[hooks]' > .hg/hgrc
 cat .hg/hgrc
 echo 'a ' > a
 hg commit -A -m 'test with trailing whitespace'
+echo 'a' > a
+hg commit -A -m 'drop trailing whitespace and try again'
+
+#$ name:
+
+echo '[hooks]' > .hg/hgrc
+echo "pretxncommit.whitespace = check_whitespace.py" >> .hg/hgrc
+cp $EXAMPLE_DIR/data/check_whitespace.py .
+
+#$ name: better
+
+cat .hg/hgrc
+echo 'a ' >> a
+hg commit -A -m 'add new line with trailing whitespace'
+perl -pi -e 's,\s+$,,' a
+hg commit -A -m 'trimmed trailing whitespace'
 
 \section{Some hook examples}
 
-\subsection{Enforcing coding guidelines in your own repository}
+\subsection{Writing meaningful commit messages}
+
+It's hard to imagine a useful commit message being very short.  The
+simple \hook{pretxncommit} hook of figure~\ref{ex:hook:msglen.run}
+will prevent you from committing a changeset with a message that is
+less than ten bytes long.
+
+\begin{figure}[ht]
+  \interaction{hook.msglen.run}
+  \caption{A hook that forbids overly short commit messages}
+  \label{ex:hook:msglen.run}
+\end{figure}
+
+\subsection{Checking for trailing whitespace}
 
 An interesting use of a commit-related hook is to help you to write
 cleaner code.  A simple example of ``cleaner code'' is the dictum that
 whitespace''.  Trailing whitespace is a series of space and tab
 characters at the end of a line of text.  In most cases, trailing
 whitespace is unnecessary, invisible noise, but it is occasionally
-problematic, and people tend to prefer to get rid of it.
+problematic, and people often prefer to get rid of it.
 
 You can use either the \hook{precommit} or \hook{pretxncommit} hook to
 tell whether you have a trailing whitespace problem.  If you use the
 hook that checks for trailing whitespace.  This hook is short, but not
 very helpful.  It exits with an error status if a change adds a line
 with trailing whitespace to any file, but does not print any
-information that might help us to identify the offending file or line.
+information that might help us to identify the offending file or
+line.  It also has the nice property of not paying attention to
+unmodified lines; only lines that introduce new trailing whitespace
+cause problems.
+
+\begin{figure}[ht]
+  \interaction{hook.ws.better}
+  \caption{A better trailing whitespace hook}
+  \label{ex:hook:ws.better}
+\end{figure}
+
+The example of figure~\ref{ex:hook:ws.better} is much more complex,
+but also more useful.  It parses a unified diff to see if any lines
+add trailing whitespace, and prints the name of the file and the line
+number of each such occurrence.  Even better, if the change adds
+trailing whitespace, this hook saves the commit comment and prints the
+name of the save file before exiting and telling Mercurial to roll the
+transaction back, so you can use
+\hgcmdargs{commit}{\hgopt{commit}{-l}~\emph{filename}} to reuse the
+saved commit message once you've corrected the problem.
+
+As a final aside, note in figure~\ref{ex:hook:ws.better} the use of
+\command{perl}'s in-place editing feature to get rid of trailing
+whitespace from a file.  This is concise and useful enough that I will
+reproduce it here.
+\begin{codesample2}
+  perl -pi -e 's,\\s+$,,' filename
+\end{codesample2}
+
+\section{Bundled hooks}
+
+Mercurial ships with several bundled hooks.  You can find them in the
+\dirname{hgext} directory of a Mercurial source tree.  If you are
+using a Mercurial binary package, the hooks will be located in the
+\dirname{hgext} directory of wherever your package installer put
+Mercurial.
+
+\subsection{\hgext{acl}---access control for parts of a repository}
+
+The \hgext{acl} extension lets you control which remote users are
+allowed to push changesets to a networked server.  You can protect any
+portion of a repository (including the entire repo), so that a
+specific remote user can push changes that do not affect the protected
+portion.
+
+This extension implements access control based on the identity of the
+user performing a push, \emph{not} on who committed the changesets
+they're pushing.  (If access control based on committer was to work
+properly, it would require commits to be cryptographically signed,
+which is an onerous and hence unusual policy to enforce.)
+
+XXX More help.
 
 \section{Hook reference}
 \label{sec:hook:ref}