Table Of Contents
- General Comments
- Installation
- Config File Design
- [maps] Configuration Section
- [general] Configuration Section
- Group Configuration Sections
for_repos
for_paths
exclude_paths
ignore_if_other_matches
show_nonmatching_paths
commit_subject_template
,propchange_subject_template
,lock_subject_template
andunlock_subject_template
commit_subject_prefix
,propchange_subject_prefix
,lock_subject_prefix
andunlock_subject_prefix
max_subject_length
from_addr
,reply_to_addr
,to_addr
,to_fake
andbcc_addr
to_newsgroup
diff_command
generate_diffs
browser_base_url
viewcvs_base_url
long_mail_action
long_news_action
mail_transfer_encoding
news_transfer_encoding
mail_type
apply_charset_property
show_applied_charset
custom_header
extract_x509_author
cia_rpc_server
cia_project_name
cia_project_module
,cia_project_branch
andcia_project_submodule
cia_project_path
- Substitutions
- Configuring the Repository
- The svnmailer Command Line
General Comments
The svnmailer is an extensible subversion commit notification tool. Its purpose in the
first place is to create human readable commit mails and
correctly encoded other notifications. In order to accomplish this,
the content may be recoded to fit the requirements of the supported
standards like MIME or XML 1.0. Note that
this does not change the meaning of the actual content. It's
more like encoding a <
character as <
in an HTML or XML document.
That means that you always get valid and readable mails,
but you SHOULD NOT
expect to be able to simply copy the diffs from the generated mails and
apply them with the patch
program. Use svn diff
or ViewCVS diffs for
such tasks. The svnmailer is able to generate the proper ViewCVS urls
and place them quite handy near the diffs in the notification mails.
Nevertheless, there are always people doing weird things, so the svnmailer provides the possibility to generate multipart mails, which contain the opaque diff data. Note however, that the using the diffs directly from the multipart tracking mails has a number of disadvantages, including the following:
- The mails may be badly modified by gateways, because they are not protected by a proper transfer encoding
- The mails may not contain the whole change. There are options to omit diffs for special actions (often diffs for deletions are turned off). Further diffs of binary files are always omitted.
- Keyword and newline expansion in subversion happens
client side, so the mail diff may be another one than the stuff
svn diff
generates. - Last but not least email is an unreliable medium. The typical case to lose tracking mails is that the mailing list rejects mails that are greater than a certain limit. So how would you apply a diff, which you don't even have received? Sure, one could truncate the mails properly, but then issue 2 applies...
Installation
Before installing the svnmailer package make sure, that you meet the following requirements:
- Python 2.3 or later
- A POSIX compatible platform or Win32
- The subversion bindings for python
The svnmailer is a pure python package, which is packed using
distutils. So the installation on your system is fairly simple.
First download the package and make sure you've checked the
integrity of the downloaded file. There are a detached GPG signature
(*.asc
) and signed hash files (*.md5
and
*.sha1
), which you can use for this task.
After unpacking the archive file change into the
svnmailer-1.0.9
directory and follow the typical
python procedure:
$ bzip2 -cd svnmailer-1.0.9.tar.bz2 | tar -xf -
$ cd svnmailer-1.0.9
$ python setup.py install
Now there should be two things installed, the svn-mailer
command line script and svnmailer package itself. The package
is copied to the "proper" location, where python finds it by
default. The location of the script depends on the OS and the
python installation. For example, on linux it typically installs into
/usr/bin
or /usr/local/bin
. For
customizations please refer to the related python
documentation.
The next step is to create a configuration file. After you've done that, you can configure your repository to let the svnmailer do its work.
Config File Design
In short: the configuration file controls, who gets the notifications for which path in which repository. Further it defines the basic script parameters like how to send the notification mail, which diff program to use (if any) and so on. It is supposed to be compatible to the config of the original mailer.py script.
Syntactical Elements
The file is a plain text file in an INI like format as defined by the standard python ConfigParser module. Basically it consists of several sections, that are started with a line containing:
[section name]
and finished at the next [section]
or the end of the
file. Values are defined that way:
name = value
# or
name: value
As you might have guessed, comments are preceded by the hash character
(#
). Empty lines (or lines containing only whitespaces) are
ignored. Note that section headings, comments and value definitions have
to start at the first column, because the configuration parser treats
(non-empty) lines starting with spaces or tabs as continuations of the
previous line (like in mail headers).
Semantics
The sections in your config file are processed by the svnmailer as
follows: The [general]
section
contains the basic script parameters. The [defaults]
section contains default values for the group sections. All values
that are not defined in a selected notification group are taken from
the defaults. [defaults]
is optional. Further you can
have a [maps]
section, which
specifies value mapping tables (which may define further sections,
too). All sections not recognized otherwise
define notification groups. The names of these sections don't care
(except for debugging purposes). They just have to be unique within
the config and may not be named defaults
,
general
or maps
, of course. If there
is no separate group configuration, the defaults will be applied.
So a minimal config is:
[general]
If you call the svnmailer with this config, it will generate diffs
for every possible action at any path for any supplied repository and
write a notification message to stdout
.
Group Selection
When the svnmailer is called, it reads the config file and selects
all groups, which should be notified of that particular event (commit
or revprop change). Which groups are selected, is determined by the for_repos
, for_paths
, exclude_paths
and ignore_if_other_matches
options. Since the svnmailer tries to minimize the number of
notification mails, each of these selected groups gets one mail at
maximum per event (except they are configured for huge mail splitting).
Furthermore, if the notifications generated for
different selected groups are detected to be equal, these groups are
merged and just one mail is sent to all of those groups. Currently
this detection compares the list of modified paths (that were matched
by each group) and several configuration options, which are in
particular: show_nonmatching_paths
, commit_subject_template
, propchange_subject_template
, lock_subject_template
, unlock_subject_template
, commit_subject_prefix
, propchange_subject_prefix
, lock_subject_prefix
, unlock_subject_prefix
, max_subject_length
, reply_to_addr
, diff_command
, generate_diffs
, browser_base_url
, viewcvs_base_url
, extract_x509_author
, long_mail_action
, long_news_action
, mail_transfer_encoding
, news_transfer_encoding
, mail_type
, apply_charset_property
, show_applied_charset
.
Note that there's a subtle difference to the original mailer
script. If there are group configurations defined, the svnmailer will
never consider the [defaults]
section as an additional
group to be notified.
[maps] Configuration Section
The [maps]
section allows you to specify
mapping tables for values that you can't create directly by substitutions or just want to abbreviate via a
nick name. For example, a typical configuration of from_addr
is:
[defaults]
from_addr = %(author)s@example.org
This is fine as long all authors really do have a mail address at example.org, which local part matches the authentication user. However, a more complex mapping from author to mail address is not possible with this method. In this case, maps can provide a solution. Different map types are planned; for now, the svnmailer only supports plain config maps, which are described in the next section.
Note that not all options are mappable. The exceptions are all
options that specify boolean or integer options in addition to the
following list: generate_diffs
, mail_transfer_encoding
, news_transfer_encoding
, config_charset
, include_config
.
Plain Config Maps
All you need is a translation table, which maps the authenticated author to his real address. Something like this:
[author table]
john = doe@example.org
foo = bar@otherserver.example.com
Further you need to associate the [author table]
with
the revision author and the from_addr
option:
[maps]
from_addr = [author table]
[defaults]
from_addr = %(author)s
In the above config the [maps]
section defines, that
the resulting values of from_addr
should be mapped using
the [author table]
section. Now the svnmailer takes the
specified from_addr
(%(author)s
),
substitutes the author with, say, john
and maps
john
to doe@example.org
. If it doesn't
find the value (john
) in the mapping table, it is passed
through unchanged.
On list options like to_addr
, every item is mapped
separately. For example:
[maps]
from_addr = [author table]
to_addr = [author table]
[defaults]
from_addr = %(author)s
to_addr = %(author)s archive@svn.example.org
This excerpt sends all commits to the author itself and an archive account.
[general] Configuration Section
Option Name | Type | Description |
---|---|---|
config_charset |
string | The character encoding of the config file |
include_config |
List | A list of config files to include |
diff_command (deprecated) |
command line | The external diff program to use. |
sendmail_command |
command line | The sendmail compatible command line template |
smtp_host |
string | The SMTP host[:port] to
use |
smtp_user |
quoted literal | The user used for SMTP authentication |
smtp_pass |
quoted literal | The password used for SMTP authentication |
nntp_host |
string | The NNTP host[:port] to
use |
nntp_user |
quoted literal | The user used for NNTP authentication |
nntp_pass |
quoted literal | The password used for NNTP authentication |
debug_all_mails_to |
mail addresses | Mails should go only to these fixed addresses |
cia_rpc_server (deprecated) |
string | CIA XML-RPC tracking server |
tempdir |
string | The directory to use for temporary files |
Though the [general]
section defines such basic
parameters, it may be finally empty, because there are more or less
useful defaults given for each option. In order to make sure, that
you didn't forget it, the svnmailer requires at least the section
heading to be present in the config.
The different options play together as follows:
- If the
diff_command
option is given and not empty, it is used to generate the diff output. Otherwise an internal differ is used. The internal differ always generates the unified diff format. - If the
sendmail_command
option is given, it is used to send the mail. - If the
smtp_host
option is given andsendmail_command
is not given or empty, the former is used to open an smtp session to the specified host and deliver the mail via SMTP. If the server requires authentication, you have to supply bothsmtp_user
andsmtp_pass
. If the server doesn't support authentication, you may not supply thesmtp_user
option (alternatively just leave it empty). - If neither
sendmail_command
norsmtp_host
is specified, the notification message is written to stdout (with a small header, which configuration groups were selected). This can be used for debugging purposes.
config_charset
The config_charset
option defines, how
the svnmailer should interpret the (bytes read as) option values in
your config files. It defaults to us-ascii
, which means,
normally you can leave it just out. But note that there are
exceptions. The options of type "quoted literal" are not
charset decoded, but taken literally (though possibly unquoted).
Furthermore the first item of command line option values (the command
itself) may be interpreted literally, too. This depends on
the OS and the --path-encoding
option. See
there for details.
There's a subtle limitation: config_charset
should be an US-ASCII
based encoding (for example,
UTF-16
is a bad choice).
# Example
# =======
[general]
config_charset = iso-8859-1
include_config
The include_config
option specifies further
config files to append to the current one. The config files can be
defined using either relative or absolute paths in the filesystem.
Relative paths are taken relative to the config file which includes
them. The option value is parsed like a command line -- it is split
on whitespaces, except when they are quoted. Have a look at the
description of diff_command
for a
detailed explanation of the rules.
One typical use of include_config
is to exclude
mappings from the main config for maintenance and/or security
reasons.
Note that it is not possible (yet?) to override a section by including another file. Each and every section still can only be defined once.
# Example
# =======
[general]
include_config = passwords.txt
smtp_user = smtpuser
smtp_pass = smtppass
[maps]
smtp_user = [smtp]
smtp_pass = [smtp]
And the following could be the passwords.txt
file:
# Example
# =======
[smtp]
smtpuser = "someuser"
smtppass = "secret password"
diff_command
The diff_command
option in
[general]
is deprecated. diff_command
options defined
in group sections are taken in preference of the one defined in
[general]
.
sendmail_command
The sendmail_command
option defines the
command line template of the program that should be called for sending
a mail. The program should expect the mail body on stdin
.
The stdout
channel of the program is closed by the
svnmailer, but stderr
is passed through the caller of
the svnmailer.
In contrast to
diff_command
there are no substitutions made on the
arguments. Instead the final command line is constructed as follows:
- The command template is split into its arguments following the
rules described at
diff_command
. - To specifiy the mail sender the arguments
-f
and the sender address is attached to the argument list - The argument list is further extended with all recipient addresses.
This calling convention is compatible to, for example, sendmail or qmail's sendmail wrapper, hence the name sendmail_command.
As with diff_command
no shell metacharacters are
interpreted.
For compatibility reasons the sendmail_command
option
can also be written as mail_command
.
# Example
# =======
[general]
sendmail_command = /usr/sbin/sendmail
smtp_host
The smtp_host
option defines the SMTP
server to connect in order to send a mail. This option is ignored if
sendmail_command
is defined and not empty. The option value is a hostname, optionally
followed by a colon and a port. If the server supports
authentication, you can supply the required credentials via the smtp_user
and
smtp_pass
options.
# Example
# =======
[general]
smtp_host = mail.example.org
# or with port
smtp_host = mail.example.org:25
smtp_user and smtp_pass
These two options are only used if the smtp_host
is used by the
svnmailer. They define the credentials to be used in the SMTP
session when attemting to send mail. If you supply
smtp_user
, you have to define smtp_pass
as
well. However, svnmailer just checks for the presence of
smtp_user
to know, if any credentials should be used.
The utilized smtp library
supports the CRAM-MD5
, PLAIN
and
LOGIN
authentication mechanisms.
Because of the nature of those two options, the values are not
considered to be charset encoded. They are sent literally to the
SMTP server. In order to make sure, that spaces and other possibly
weird characters are taken literally, you can enclose the actual
string in double quotes ("
). For double quotes and
backslashes inside the quoted string apply the same
rules as for command line arguments. Have a look at the description
of diff_command
for
details. Of course, the surrounding quotes and backslash escape
characters are stripped before submitting the string to the SMTP
server.
# Example
# =======
[general]
smtp_host = mail.example.org
smtp_user = mysmtpuser
smtp_pass = mysmtppass
nntp_host
The nntp_host
option defines the NNTP
server to connect in order to post the notification as a news article.
The option value is a hostname, optionally followed by a colon and a
port. If the server requires authentication, you can supply the
credentials via the nntp_user
and
nntp_pass
options.
# Example
# =======
[general]
nntp_host = news.example.org
# or with port
nntp_host = news.example.org:119
nntp_user and nntp_pass
These two options are used if a news notification is submitted via
an nntp_host
.
They define the credentials to be used in the NNTP
session when attemting to post the article. If you supply
nntp_user
, you have to define nntp_pass
as
well.
Similar to smtp_user
and smtp_pass
the values are not considered to be
charset encoded. They are sent literally to the NNTP server. See there
for a further explanation of the argument format.
# Example
# =======
[general]
nntp_host = news.example.org
nntp_user = mynntpuser
nntp_pass = mynntppass
debug_all_mails_to
This one is a real debugging option. It specifies a fixed list of
mail addresses, where all notification mails should be sent to --
regardless of the to_addr
or
bcc_addr
templates of the selected groups. The addresses of the overridden
recipients are sent along with the mail using the
X-Supposed-Recipients
header.
# Example
# =======
[general]
debug_all_mails_to = svnadmin@example.org
cia_rpc_server
The cia_rpc_server
in [general]
if deprecated. cia_rpc_server
options defined in group sections are
preferred to the ones defined in [general]
.
tempdir
The tempdir
option defines a directory to
use for temporary files. By default or if the specified directory is
empty this temp directory is chosen by python's
tempfile module.
# Example
# =======
[general]
tempdir = /space/svnmailer-tmp
Group Configuration Sections
Option Name | Type | Description |
---|---|---|
for_repos |
regex | Matches the repository file path |
for_paths |
regex | Matches the virtual path inside a/the repository |
exclude_paths |
regex | Excludes paths that might be matched with
for_paths |
ignore_if_other_matches |
boolean | Determines, whether the group should be ignored, if any other group matches this path |
show_nonmatching_paths |
token | Defines how to deal with changed paths that don't belong to the group |
commit_subject_template |
template | The mail subject template for normal commits |
propchange_subject_template |
template | The mail subject template for revprop change notifications |
lock_subject_template |
template | The mail subject template for lock notifications |
unlock_subject_template |
template | The mail subject template for unlock notifications |
commit_subject_prefix |
string | The mail subject prefix for normal commits |
propchange_subject_prefix |
string | The mail subject prefix for revision property notifications |
lock_subject_prefix |
string | The mail subject prefix for lock notifications |
unlock_subject_prefix |
string | The mail subject prefix for unlock notifications |
max_subject_length |
number | The maximum subject length |
from_addr |
template | The sender addresses |
to_addr |
template | The receiver addresses |
reply_to_addr |
template | The reply-to address |
to_newsgroup |
template | The newsgroups to post to |
diff_command |
command line | The diff command to use |
generate_diffs |
token list | The list of actions, which generate diffs |
browser_base_url |
string | Base URL and type of the repository browser installation |
viewcvs_base_url |
string | (DEPRECATED) Base URL of the ViewCVS installation |
long_mail_action |
tuple | Action to take on overlong notification mails |
long_news_action |
tuple | Action to take on overlong notification news postings |
mail_transfer_encoding |
token | The content transfer encoding used for mails |
news_transfer_encoding |
token | The content transfer encoding used for news postings |
mail_type |
token | How to construct the mail (multipart/single) |
apply_charset_property |
boolean | Resolves the content charsets from
svnmailer:content-charset properties. |
show_applied_charset |
token | Specifies whether the content charset (configured or default) of the should be written into the diff header. |
custom_header |
tuple | Name and Value format string for a custom header, which is included in the mail |
extract_x509_author |
boolean | Treats the author as x509 subject string and tries to extract the author's real name and email address |
cia_rpc_server |
string | CIA XML-RPC tracking server |
cia_project_name |
template | The project name submitted to the CIA tracker |
cia_project_module |
template | The project module submitted to the CIA tracker |
cia_project_branch |
template | The project branch submitted to the CIA tracker |
cia_project_submodule |
template | The project submodule submitted to the CIA tracker |
cia_project_path |
template | The project path stripped from the absolute file paths before submitting to the CIA tracker |
The options described here are all valid both in group configurations
and in the [defaults]
section. If a option in a normal group
configuration is missing, its value is taken from [defaults]
.
If there is nothing defined, a hardcoded default is applied.
for_repos
The for_repos
option defines a regular expression,
which is used to match against the file path of repository, for
example /var/svn/my-repository
. The file-path, which is
matched against is guaranteed to not have a directory
separator at the end (slash or backslash). Note that the regular
expression always matches from the beginning of the path, so your regex
typically will begin with .*
. This is, because the
svnmailer uses the re.match
function - see the python
docs for further information.
If the for_repos
option is not defined or empty, the
particular group matches for any repository (which is the default).
Named matches of this group are stored for later substitutions.
In the following example the group "sample group" will be selected
only if the script is called for the "public" repository (e.g.
/var/svn/repositories/public
):
# Example
# =======
[sample group]
for_repos = .*/public$
for_paths
The for_paths
option defines a regular expression,
which is used to match against one of the modified paths stored in the
repository, but only if the group was preselected by repository (see for_repos
). If the
path matched against is a directory, it is guaranteed to end with a
slash, so that matching by directory paths results in more simple
regular expressions. As with for_repos
, the match always
starts at the beginning of the path, but without a leading slash.
If the for_paths
option is not defined or empty, the
particular group matches for any path inside the repository (which
is the default). Named matches of this group are stored for later substitutions.
In the following example the group "sample group" will be selected
only if the script is called for the "public" repository (e.g.
/var/svn/repositories/public
) and everything under the
/site/
directory (e.g. /site/images/foo.gif
,
but not for /site-tools/buildsite.sh
):
# Example
# =======
[sample group]
for_repos = .*/public$
for_paths = site/
exclude_paths
Since regular expressions usually match positive, it's from time to
time helpful (and better readable) to exclude substrings with a
separate match. The exclude_paths
option
exists for that purpose. It matches exactly like
for_paths
, but the group is selected only if the supplied
regex does not match (and has been preselected by for_repos
and
for_paths
).
If the exclude_paths
option is not defined or empty,
nothing will be excluded (which is the default). Of course, named
groups of the match will not be stored for substitution, because
the group is not selected, if there is a match of
exclude_paths
.
In the following example the group "sample group 1" will be selected
only if the script is called for the "public" repository (e.g.
/var/svn/repositories/public
) and everything under the
/site/
directory (e.g. /site/images/foo.gif
),
but not for stuff under /site/tools/
. For every
change under the site/tools/
directory the group
"sample group 2" will be notified:
# Example
# =======
[defaults]
for_repos = .*/public$
[sample group 1]
for_paths = site/
exclude_paths = site/tools/
[sample group 2]
for_paths = site/tools/
Note that if the exclude_paths
option was not given,
every change under site/tools/
would generate a
notification for both groups.
ignore_if_other_matches
Consider a main project, which consists of several subprojects. Every subproject has its own notification group:
# Example
# =======
[defaults]
for_repos = .*/public$
[main project]
# consists of main1/ .. mainn/ and sub1/ ... subn/
# sub1 ... n get their own notification, the main project should
# be notified only for stuff other than sub?/
for_paths = project/
exclude_paths = project/(sub1|sub2|...|subn)/
[sub 1]
for_paths = project/sub1/
# :
[sub 10]
for_paths = project/sub10/
The exclude_paths
option could be matched easier, if the
sub projects really would be named
subdigit
. But usually this is not the case. As
you see, maintaining the exclude_paths
regex grows to a
nightmare the more projects are added. The
ignore_if_other_matches
option is supposed to
help out of this ugly situation. If set to a positive value (e.g.
yes
), the group will not be selected for the matched path
if there are any other groups that match the same path / repository.
The above config could be rewritten as:
# Example
# =======
[defaults]
for_repos = .*/public$
[main project]
for_paths = project/
ignore_if_other_matches = yes
[sub 1]
for_paths = project/sub1/
# :
[sub 10]
for_paths = project/sub10/
Note that there is a border case. If you use this feature for more than one group, it can happen, that finally the list of selected groups per path consists only of more than one ignorable groups. Theoretically these would unselect each other. Practically all those groups are selected, so that the notification is not lost.
The "boolean" values accepted by this option are yes
,
on
, true
and 1
for the "true"
case and no
, off
, false
,
0
, none
and the empty string for the
"false" case. The default is false.
For compatibility reasons, convenience and better readability
this option can also be written as suppress_if_match
or fallback
.
show_nonmatching_paths
The show_nonmatching_paths
option specifies
how the svnmailer should deal with situations where the paths matched by
for_paths
are only a subset
of all paths affected by the commit. For instance, consider the following
changeset:
foo/
foo/bar
spam/eggs
Further consider a notification group that matches for all paths
beginning with foo/
:
[some group]
for_paths = foo/
The show_nonmatching_paths
option provides for three
values, which solve the conflict differently:
yes
- The additional changes are included in the notification (but after the ones belonging to the group). CIA notices for this group also include all changed paths then. If you have different customers that may not see each other's projects, be careful with this solution.
no
- It will be stated in the notification, that there are additional changes (after the path list), but neither the paths nor their diffs are included
ignore
- The additional paths will be just ignored. In the notification there will be no sign of changes not belonging to the group.
If show_nonmatching_paths
is unset or empty, it defaults
to no
. Note that this default differs from the less safe
yes
default used in the subversion 1.2
mailer.py
script.
For convenience reasons and better readability this option can also
be written as nonmatching_paths
,
nongroup_paths
and show_nongroup_paths
.
# Example
# =======
[some group]
show_nonmatching_paths = yes
commit_subject_template, propchange_subject_template, lock_subject_template and unlock_subject_template
These options define the subject templates to be used for the particular notification type (commit, revprop change, lock, unlock). In addition to the normal substitution record the following substitutions are available:
Name | Value Description |
---|---|
prefix |
This is the subject prefix as configured. |
part |
If mails are split, this contains the description of the
current part ([x/y] ) |
files * |
This contains the paths affected by the event. Despite the name
files this also contains affected directories
(consider them as special files). |
dirs * |
Well, this only contains the directories affected by the
event (in contrast to file ). |
files/dirs * |
The content of files/dirs is determined
dynamically. It chooses the value of files by
default. If the subject gets too long then, it takes
dirs . The length parameter is max_subject_length
or 255 if max_subject_length is
unset. |
* All items are space separated. Further if the path items have a
common prefix, it is extracted and the paths shortened respectively. It
looks about "in /prefix: foo bar/baz
" then.
After the template was filled in, all whitespaces are normalized,
that is, leading and trailing spaces are stripped and multiple
adjacent whitespaces of any favor are compressed to one space. So you
don't have to worry about strange-looking subjects, because one of the
substitutions is empty (part
is a good candidate).
The svnmailer defines the following default templates in case of unset or empty options:
commit | %(prefix)s r%(revision)s %(part)s -
%(files/dirs)s |
---|---|
revprop change | %(prefix)s r%(revision)s - %(property)s |
lock | %(prefix)s %(files/dirs)s |
unlock | %(prefix)s %(files/dirs)s |
A typical use case of a customized subject template is a mailing list, where the svn authors are not allowed to post, but just one mail address, which represents the notification mailer itself. Or you don't want to expose the mail addresses of the committers. However, it would be still desirable to get the author of the commit in the mail client overview. Just put into the subject:
# Example
# =======
[defaults]
commit_subject_template = %(author)s: %(revision)s - %(files)s
commit_subject_prefix, propchange_subject_prefix, lock_subject_prefix and unlock_subject_prefix
These options define the subject prefix of the generated mails
depending on the described event. If a string is supplied, it's
provided as prefix
substitution in the subject template.
commit_subject_prefix
defines the prefix
for normal subversion commits (files, directories and versioned
properties). propchange_subject_prefix
defines the subject prefix for unversioned property change notifications.
lock_subject_prefix
defines the subject prefix
for lock notifications (SVN 1.2 and later) and
unlock_subject_prefix
for unlock
notifications (you knew that, huh?).
The default prefixes are empty.
# Example
# =======
[defaults]
commit_subject_prefix = svn commit:
propchange_subject_prefix = svn revpropchange:
lock_subject_prefix = svn lock:
unlock_subject_prefix = svn unlock:
max_subject_length
The max_subject_length
option specifies the
maximum length of the generated mail or news subject line. If the
generated subject is longer than the defined limit, it is cut and three
dots are appended (hence the minimum subject length is
3
). If the max_subject_length
option is not
specified, empty or defines 0
, no limit is applied.
For compatibility reasons and convenience the
max_subject_length
option can also be written as
truncate_subject
or subject_length
.
# Example
# =======
[defaults]
max_subject_length = 127
from_addr, reply_to_addr, to_addr, to_fake and bcc_addr
from_addr
,
reply_to_addr
, to_addr
and bcc_addr
define address templates for
the mails to be sent. from_addr
, to_addr
and
bcc_addr
accept space or tab separated lists of address
templates, while reply_to_addr
takes just one address. The
basic semantics should be quite clear: from_addr
defines
the sender addresses (but usually just one), to_addr
the
recipient addresses which should show up in the To
header,
bcc_addr
the undisclosed recipients and
reply_to_addr
the address, where answers to
the commit mail should be sent to. If groups are merged during the
selection process, there can be any number of senders, receivers and
even reply-to addresses in the mail (which conforms to RFC 2822,
if you care about such things). Duplicates in the address lists are
filtered away. In the case of more than one final sender address, the
svnmailer generates an additional Sender:
header with the
first item of the sender address list (which is more or less random,
but they should be all valid, right?).
The to_fake
option comes into play if you
have bcc_addr
defined but no to_addr
. By
default, the svnmailer would just omit the To
header
and send the mail to the bcc recipients without this header. You
might want to fill the header with a dummy address in this case.
to_fake
will be just written into the header but
not treated as valid recipient address.
If there are no sender addresses given, it uses the string
no_author
(as the original script does). That may lead to
an error while mail sending, so the best is to supply a valid
from_addr
in the [defaults]
section.
If there are no recipients, the svnmailer simply doesn't send the
mail (this is useful, if there are more notifier types like news or
XML-RPC active). If this is not, what you want, you have to
supply functioning to_addr
options.
All those options may contain substitution patterns in the form
%(name)s
. The list of values to substitute is
determined for each notification group dynamically using the
for_repos
and for_paths
regular expressions.
The substitution names author
and group
are
always defined. If not overridden by one of the regular expressions,
author
contains the author of the change (or the string
no_author
if
no author could be determined) and group
the name of
the notification group (the section heading without the braces).
All address templates described here are empty by default. For
compatibility reasons the reply_to_addr
option can also
be written as reply_to
.
bcc_addr
and to_fake
are available in
version 1.0.8 and later.
# Example
# =======
[defaults]
for_repos = .*/public$
from_addr = %(author)s@example.org
[projects]
for_paths = projects/(?P<PROJECT>[^/]+)/
to_addr = commits@%(PROJECT)s.example.org
reply_to_addr = dev@%(PROJECT)s.example.org
[home repositories]
for_paths = home/(?P<OWNER>[^/]+)/
to_addr = %(OWNER)s@example.org
[everything else]
for_paths =
fallback = yes
to_addr = svnadmin@example.org
to_newsgroup
The to_newsgroup
option specifies a space
or tab separated list of newsgroups where the notification should be
posted to. This parameter is a substitution
template, so you can extract information from the commit
information.
Note that you need to define the nntp_host
option (in
[general]
) in order to submit news postings.
# Example
# =======
[general]
nntp_host = news.example.org
[defaults]
to_newsgroup = org.example.commits
diff_command
The diff_command
option defines, that
you want to use an external diff program (instead of python's difflib
module), where to find and how to call it. The option value is
a template for the command line to call. The program has to write
the diff information to stdout
. Stdout
and
stderr
are caught by the svnmailer and dumped into
the mail.
As said, the value describes a template. There is a fixed number of
substitutions defined for the diff_command
option, in
particular: label_from
, label_to
,
from
and to
. from
and
to
define the actual files to process (typically some
scrambled temporary file names). label_from
and
label_to
define, how the files should be labeled by
the diff program. These substitutions are written as
%(name)s
and replaced by the svnmailer script.
If you want a literal percent character somewhere in the command line,
you have to duplicate it (i.e., write %%
instead).
The command line template is split on spaces or tabs to separate the
different arguments. If you want to have an argument contain such space
characters, you have to enclose it in double quotes ("
).
Further if you want such a quoted argument to contain a double quote
character, you have to escape it with a backslash (i.e., write
\"
instead). To complete the escaping mechanism, you have
to duplicate backslashes inside a quoted argument. The
surrounding quotes and the backslash escape characters are stripped
by the svnmailer to get the final argument string.
Note that on POSIX systems no shell is called to execute the
program, so shell metacharacters are not interpreted. However, on
Win32 the shell (cmd.exe
& Co.) is called,
but the arguments are properly escaped.
For compatibility and convenience the diff_command
option can also be written as diff
.
# Example for GNU diff
# ====================
[defaults]
# (note that the following is all on one line)
diff_command = /usr/bin/diff -u -L %(label_from)s -L %(label_to)s %(from)s %(to)s
generate_diffs
The generate_diffs
option defines which
actions diffs are generated for. It takes a space or tab separated list
of one or more of the following tokens: add
, modify
,
copy
, delete
, propchange
and
none
.
If the add
token is given and a new file is added to
the repository, the svnmailer generates a diff between an empty file and
the newly added one. If the modify
token is given and the
content of an already existing file is changed, a diff between the old
revision and the new revision of that file is generated. The
copy
token only worries about files, that are copied
and modified during one commit. The delete
token
generates a diff between the previous revision of the file and an
empty file, if a file was deleted.
If the propchange
token is given, the svnmailer also
takes care of changes in versioned properties. Whether it should
actually generate diffs for the property change action depends on the
other tokens of the generate_diffs
list. The same rules as
for files apply, except that the svnmailer never generates property
diffs for deleted files. For example:
# Example
# =======
[defaults]
generate_diffs = add copy modify propchange
Now svnmailer generates diffs, if:
- A file is added, modified or copied (and modified)
- A property is added or modified (properties cannot be copied)
If a file or property is deleted, it's written as action information
into the mail, but no content diff is generated. The default value for
generate_diffs
contains all possible actions. Mistyped
tokens are ignored. If the resulting token list is empty, svnmailer
falls back to the default. If you really don't want diffs to be
generated, configure explicitly an empty generate_diff
option or use:
[some group]
generate_diffs = none
browser_base_url
If the browser_base_url
option is defined and
not empty, the svnmailer generates URLs for the specified repository
browser. One URL for the whole revision is placed on top and for every
generated file diff a conrete URL is written before the actual diff
output. The default value is empty and no urls are generated.
The option takes two parameters. The first one specifies the browser type. The second parameter determines the base url of the browser installation. The base url is interpreted by the semantics specified by the type, which can be one of:
viewcvs
- The base url specifies the root URL of the ViewCVS installation.
The svnmailer tries to keep most query parameters you provide (such
as
root
). The following query parameters are always overridden:view
,rev
,p1
,p2
,r1
andr2
. websvn
- The base url specifies the repository's WebSVN root listing URL.
Depending on the WebSVN configuration this looks different (see the
examples below) and produces different resulting URLs. The svnmailer
tries to autodetect the installation type on the basis of the
supplied URL. If it contains a query parameter called
repname
, a non-PATH_INFO
installation is assumed. In this case the svnmailer may choke if the last path element ends with a slash (i.e. does not represent a file). This is just a sanity check, because the file will be replaced by the svnmailer, when constructing the final URLs.As you might have guessed, if the URL doesn't contain this
repname
query parameter, aPATH_INFO
installation is assumed. However, the best way to get the proper base URL is to open the repository root directory in your browser and just copy the URL and paste it into the svnmailer config.
# Example
# =======
[defaults]
# simple base url:
browser_base_url = viewcvs http://example.org/browse/repos
# base url with parameters:
browser_base_url = viewcvs http://example.org/browse?root=repos
[some group using websvn]
browser_base_url = websvn http://example.org/svn/listing.php?repname=repos
# or websvn is configured using PATH_INFO
# (it's called multiviews in their docs)
browser_base_url = websvn http://example.org/svn/repos/
And here is an output of a change in a sample repository (revision 5):
Author: nd
Date: Thu Jan 6 00:10:04 2005
New Revision: 5
URL: http://svn.example.org/browse?view=rev&rev=5
Log:
copied a file
Added:
foo/eggs (contents, props changed)
- copied, changed from r4, foo/spam
Copied: foo/eggs (from r4, foo/spam)
URL: http://svn.example.org/browse/foo/eggs?view=diff&rev=5&p1=foo/spam&r1=4&p2=foo/eggs&r2=5
==============================================================================
--- foo/spam (original)
+++ foo/eggs Thu Jan 6 00:10:04 2005
@@ -1,1 +1,1 @@
-This is spam.
+These are eggs.
Propchange: foo/eggs
------------------------------------------------------------------------------
color = white
viewcvs_base_url
The viewcvs_base_url
option is deprecated. Use the browser_base_url
option
instead.
long_mail_action
From time to time it happens, that commits are huge
and so are the accompanying notification mails. They may hit
limits of mailing lists or mailboxes they are sent to or simply
crash some mail client. The long_mail_action
option specifies, what "huge" means (in number of bytes) and what
action the svnmailer should take to prevent such mails.
long_mail_action
takes at least two space or tab
separated parameters. The first one defines the number of bytes,
one notification mail body should contain at maximum. Note that
this number is applied, before the content is MIME
encoded, so the actual mail may be slightly greater than the
number of bytes specified here. The second parameter defines the
action to take. It can be one of the following tokens:
truncate
- This advises the svnmailer to truncate the notification mail starting with the first line reaching the limit. It will add a note about the number of lines truncated.
showurls
- If you have a
browser_base_url
configured and you hit the limit, the svnmailer will just leave out all the diffs and supply the browser URLs only. If you have nobrowser_base_url
configured, you will get neither diffs nor the URLs. If the final mail still gets too long, theshowurls
action doesn't care about, butshowurls/truncate
does. showurls/truncate
- This action token behaves mostly like
showurls
, except that if the single mail still gets too long, it is truncated after reaching the limit. A note about the number of truncated lines is appended then. split[/number]
- This action splits the notification mails into several ones.
The mail subject will contain an enumeration string
(
[1/3]
,[2/3]
etc) so you can read the mails in the proper order later and know if one is missing. In order to keep the mails readable the svnmailer never splits in the middle of a particular diff, but between whole diff blocks (including their meta information). That means, certain mails of the generated sequence may be still too long (containing one single huge diff). Thesplit
action doesn't care about this. If you want to truncate such huge single mails, use thesplit/truncate
token instead.Experience shows, that if the number of mails grows (huge imports easily lead to 30, 40 or more mails), less people actually read those mails. In order to not waste bandwidth and people's good humor, you may want to limit the number of mails per commit. This is done by extending the token by a slash and the maximum number of mails. If this limit is exceeded then, only one mail will be sent, containg just a short summary and an explanation.
split/truncate[/number]
- This action token behaves mostly like
split
, except that overlong single mails (containing one huge diff) are truncated after reaching the limit. A note about the number of truncated lines is appended then.
The optional final parameters determine, whether the configured
behaviour should be applied to revision property changes and/or locks,
too. The possible tokens are revprop-changes
and
locks
. Now if the second parameter specifies a
truncating action, the speecified notifications are
truncated if they would execeed the limit, otherwise they are not
touched (They are never split). However, overlong
revision property change or lock notifications should happen
very rarely.
By default no special action is taken to prevent huge mails. But it is highly recommended to configure one.
# Example
# =======
[defaults]
long_mail_action = 100000 split/truncate
[some group]
# truncate revprop changes as well
long_mail_action = 100000 split/truncate revprop-changes
[second group]
# truncate revprop changes and locks as well
long_mail_action = 100000 split/truncate revprop-changes locks
[other group]
# limit to 3 mails per commit at max
long_mail_action = 100000 split/truncate/3
long_news_action
The long_news_action
option defines, how
the svnmailer should deal with huge commit notification news articles.
It takes exactly the same parameters like the long_mail_action
option. Please have a look there for detailed information.
# Example
# =======
[defaults]
long_news_action = 100000 showurls/truncate
mail_transfer_encoding
The mail_transfer_encoding
option specifies,
which transfer encoding should be used when sending mails. It takes one
of the following tokens:
quoted-printable
- The mail will be encoded using quoted-printable. This has the
advantage, that no physical line will be longer than 76 bytes
(some mail servers cut or reject lines with more than 1000
byte). Disadvantage: The final size depends on the content.
There is currently a known bug with this encoding: The underlying
email module (from stdlib) changed its API between minor versions and
suddenly encoded the already encoded content again. Therefore
svnmailer no longer defaults to
quoted-printable
but to8bit
for now. base64
- The mail will be encoded using base64. Lines are also broken after 76 bytes and the final size is always 4/3 of the original size. Disadvantage: The encoded content is not human readable.
8bit
(default)- The mail won't be transfer encoded. This means, that huge lines
may be cut or mails containing weird bytes (e.g.
\0
) may be misinterpreted or rejected.
Note that the mail_transfer_encoding
is not applied to
multipart mails.
# Example
# =======
[defaults]
mail_transfer_encoding = base64
news_transfer_encoding
The news_transfer_encoding
option defines the
transfer encoding to use for news postings. It takes the value as mail_transfer_encoding
.
# Example
# =======
[defaults]
news_transfer_encoding = base64
mail_type
The mail_type
option defines how the
notification mail should be constructed. If you set it to
multipart
, the mail will be of type
multipart/mixed
, otherwise it's a single text mail.
The generation of multipart mails is discouraged, because is has
unclear semantics (the diffs are more or less opaque data) and the
client support is not as well as it could be. Further the mail_transfer_encoding
option
is not applied to multipart mails. The diff parts are designated as
Content-Transfer-Encoding: binary
. Further note, that
regardless of the charset, paths are always encoded as
UTF-8.
With svnmailer 1.0.4 and later you can also refine the
multimail
type with options. These options have the
form name=value
and just have
to be appended to the mail_type
command. The following
options are possible:
type=content/type
- The
type
option allows to specify the content type of the diff parts. A reasonable value could be, for instance,text/x-diff
. Several mail clients are known to provide syntax highlighting for the diff then. If the option is not specified it defaults totext/plain
. disposition=content-disposition
- The
disposition
option determines how the diff parts appear in the mail. Possible values areinline
andattachment
. If the option is not specified it defaults toinline
.
# Example
# =======
[defaults]
mail_type = single
[some group requested multipart mails]
mail_type = multipart
[multipart mails with options]
mail_type = multipart type=text/x-diff
apply_charset_property
The apply_charset_property
option determines,
whether the svnmailer should retrieve the content charset of the
modified files from svn:mime-type
and
svnmailer:content-charset
properties.
This charset is used to recode the files, when generating the diff,
so you get readable notifications, even if you change files with
different charsets during one commit.
At first the svn:mime-type
property of the particular
file (in the particular revision) is evaluated. If it's set and contains
a charset
attribute (like text/plain;
charset=iso-8859-2
), the attribute value
(iso-8859-2
) is chosen as file encoding. Otherwise the
svnmailer continues the encoding lookup by evaluating
svnmailer:content-charset
properties.
The svnmailer:content-charset
property can be set
either for the file itself or for one or more of its parent
directories (while more specific definitions override less specific
ones). If set for a particular file, the property just contains the
charset name:
# Example: setting a specific file charset
$ svn pset svnmailer:content-charset koi8-r file.html.ru
If the svnmailer doesn't find the property set for the changed file,
it looks for the svnmailer:content-charset
property in the
parent directories up to /
. These directory properties are
the way to specify file charsets in a more general manner. If specified,
they are expected to contain shell-style glob/charset definitions, one
per line. Such a line looks like:
glob = charset
Leading and trailing spaces, empty lines, lines starting with
#
and lines without a =
character are
ignored. Those directory properties can be easily set using the
svn propedit
command:
# (note the trailing dot)
$ svn pedit svnmailer:content-charset .
Now an editor should be opened and you can add the desired definitions. A sample property could look like:
# German files
*.xml.de = iso-8859-1
*.html.de = iso-8859-1
# Russian files
*.xml.ru = koi8-r
*.html.ru.koi8-r = koi8-r
Note that the globs apply to the whole file path including the leading slash. They are interpreted case sensitive by python's fnmatch module. The content of the property is expected to be UTF-8 encoded.
If apply_charset_property
is false or there's no
svnmailer:content-charset
property defined or the
charset cannot be found in python's codec collection, the svnmailer
falls back to iso-8859-1
, which translates
literally to unicode and so just represents the byte stream in
character form. If the file content is miscoded (according to the
chosen charset), uninterpretable byte sequences are represented by the
replace character (U+FFFD
). Note that asian encodings are
not present in python 2.3. If you want to use such encodings, you
need to install the CJKCodecs
(which are included in python 2.4 and later).
The "boolean" values accepted by this option are yes
,
on
, true
and 1
for the "true"
case and no
, off
, false
,
0
, none
and the empty string for the
"false" case. The default is false.
For convenience the apply_charset_property
option can
also be written as charset_property
.
# Example
# =======
[defaults]
apply_charset_property = yes
show_applied_charset
The apply_charset_property
option specifies
whether the svnmailer should write the (either assumed or configured)
charset of a file into the diff header. This looks like this:
Modified: foo/somefile.html.ru
=============================================
--- foo/somefile.html.ru [koi8-r] (original)
+++ foo/somefile.html.ru [koi8-r] Sat May 21 18:16:10 2005
@@ -1,4 +1,5 @@
...
The value in the square brackets represents the content charset before it is recoded to UTF-8. That way you have all information to recode it back if you need to. The following configurations are possible:
yes
- Always show the applied charset
no
- Never show the applied charset
nondefault
- Show the applied charset only if it was explicitly configured
If the option is unset or empty the svnmailer picks
nondefault
as default ;-).
# Example
# =======
[defaults]
show_applied_charset = yes
custom_header
The custom_header
option defines a custom
header line that is attached to each mail sent for the particular group
(or all groups, if you make it default). This allows for better
filtering of the mails than just by subject. If the mails are sent to a
mailing list, you probably don't need a custom header, because most
mailing list software defines its own (and probably better) headers.
The supplied option value consists of two space or tab separated
parts -- the header name and the header value template. The header name
is always prepended with X-
and invalid characters
(according to RFC 2822) are stripped. The header value is a substitution template. Note that if the final
header value contains characters, that are not contained by the
us-ascii
character set, it is encoded according to RFC 2047. If
you supply the header name only, the header will be attached empty.
If groups are merged during the
selection process and multiple custom headers are found, they are
all attached to the mail. If multiple values for the same header name
are found, they are merged with a comma and a space between. By
default custom_header
is empty.
# Example
# =======
[defaults]
for_repos = .*/(?P<REPOS>[^/]+)$
custom_header = SVN-Repository %(REPOS)s
[some group]
for_repos = .*/public$
# ...
[group without custom header]
custom_header =
In the above example the svnmailer sends all mails for the group
some group
with an additional header named
X-SVN-Repository
containing the value
public
.
extract_x509_author
The extract_x509_author
option is useful, if
you're using SSL client certificates in conjunction with SSL
Options +FakeBasicAuth
for repository authentication. If
set to a positive value (e.g. yes
), the svnmailer tries to
extract the author's real name and email address from the supplied
x509 Subject Distinguished Name (DN). In case of successful extraction
it adds the following values to the substitution parameters:
x509_CN
- The contents of the Common Name field (which is assumed to be UTF-8 encoded). This value also will be taken by the message generator for the meta data on top of the message.
x509_emailAddress
- The contents of the email address field
x509_address
- A string consisting of CN and email address usable as full email
address. It has the form
Common Name <email address>
, where the Common Name is encoded according to RFC 2047.
The "boolean" values accepted by this option are yes
,
on
, true
and 1
for the "true"
case and no
, off
, false
,
0
, none
and the empty string for the
"false" case. The default is false.
For convenience the extract_x509_author
option can also
be written as x509_author
.
# Example
# =======
[defaults]
extract_x509_author = yes
from_addr = %(x509_address)s
cia_rpc_server
The cia_rpc_server
option defines a CIA XML-RPC handler, where your commits
or some of them) should be tracked in real time. If this option is
defined and not empty, the cia_xmlrpc
notifier is
considered to be run, but it will be activated only if the selected notification group defines a cia_project_name
option. Note that it's possible for every group to run more than one
notifier (e.g., mail
and cia_xmlrpc
) per
commit.
The cia_rpc_server
option takes a http
or
https
URL. Note that the trailing slash is
important. If there's no URL path given (i.e., just
http://server
), the svnmailer (or better, the utilized XML-RPC
library) assumes it to be /RPC2
.
The CIA notifier will not send any information if it runs in the post-revprop-change hook. By default there's no RPC server defined.
The cia_rpc_server
option is allowed in group
section in version 1.0.8 and later.
# Example
# =======
[defaults]
# (note the missing trailing slash!)
cia_rpc_server = http://cia.navi.cx
cia_project_name
The cia_project_name
specifies the project
name under which the changes are tracked in a CIA real time tracker. In order to track
your projects using CIA notifiations you need to define the cia_rpc_server
option
properly at least and a cia_project_name
for the
notification groups that should be tracked. However, you should
consider to set cia_project_path
to a
reasonable value.
The cia_project_name
option value is a substitution template, so it is possible to
extract the project name from the path or the like. By default there's
no project name defined.
# Example
# =======
[defaults]
cia_rpc_server = http://cia.example.org
[some group]
cia_project_name = Example Project
cia_project_module, cia_project_branch and cia_project_submodule
These options further refine the project description submitted to the CIA tracker. Note that you still need to specify a project name to submit the notification to the CIA server at all.
Like cia_project_name
the option values are substitution templates, so it is possible to
extract some information from the path. By default all of the
descriptions are empty.
# Example
# =======
[defaults]
for_paths = [^/]+/(?P<MOD>[^/]+)/(?:branches/(?P<BRA>[^/]+)/)?
cia_rpc_server = http://cia.example.org
cia_project_module = %(MOD)s
cia_project_branch = %(BRA)s
[some group]
cia_project_name = Example Project
cia_project_path
The cia_project_path
option defines the path
in the repository that should be stripped from the beginning of the
paths changed when submitting the file list to the CIA tracker. This
lets tracked projects look more self containing. A real life example is
the Apache HTTP Server. Its
position in the ASF repository is /httpd/httpd/{trunk,branches,tags}
.
A reasonable cia_project_path
value would be
httpd/httpd/
. Note that the specified path is normalized
before being stripped. That means, any leading slash is removed and a
trailing slash is appended if needed.
Like cia_project_name
the option value is a substitution template, so it is possible to
extract this information from the path. By default no path is
stripped.
# Example
# =======
[defaults]
for_paths = (?P<PATH>[^/]+)/(?P<MOD>[^/]+)/(?:branches/(?P<BRA>[^/]+)/)?
cia_rpc_server = http://cia.example.org
cia_project_module = %(MOD)s
cia_project_branch = %(BRA)s
cia_project_path = %(PATH)s
[Example Project]
cia_project_name = %(group)s
Substitutions
Substitutions are a powerful feature that can simplify some
configurations very much. They base on named python format
strings. The format strings are similar to the ones you may
already know from the printf()
function of C or perl,
except that the particular formats are not determined by order, but
by name. To give a particular format a name, you just
write %(name)s
instead of %s
(for a
string). The name can be any sequence of characters.
As usual, when dealing with such format strings, if you want to
express a literal %
, you need to duplicate it
(%%
). Note that you should limit your formats to
strings (i.e. the s
format), because that's what the
svnmailer always supplies. Here is a real life example:
[defaults]
from_addr = %(author)s@example.org
Well, where are the format names and values taken from? Depending on
the option they are either fixed or determined dynamically. The former
-- simpler -- variant is used by the diff_command
option. For
this option the svnmailer defines, which format names and
values are used (label_from
, label_to
,
from
and to
). For the actual meaning of these
format names have a look at the
diff_command
description.
The dynamic definition of format names and values is a bit more
complex. This is used by the address
templates, the the subject
templates, the CIA project
descriptions and the custom_header
option.
There the list of format names (and values) is taken from
previously matched regular expressions (default for_repos
, default
for_paths
, group for_repos
and group
for_paths
-- in that order, later definitions override
earlier ones). This relies on another python feature: named matching
groups. These are like normal storing parentheses, but you can give
them a name. Instead of (to-match)
, you write
(?P<name>to-match)
in your regular
expression. Such a name has to look like a valid python
identifier. After a matching regular expression is
executed, the svnmailer stores such named groups for later use
separatly for each notification group. A typical use case of
this feature is:
[some group]
for_paths = projects/(?P<PROJECT>[^/]+)/
to_addr = %(PROJECT)s-commits@example.org
Besides the regular expression matches the substitution value
record initially contains some fixed values: revision
,
property
, author
and
group
. revision
contains the revision number
if there is one available (e.g. locks are not tied to a particular
revision). In the case of revision property change notifications
property
contains the name of the propery modified.
author
contains the author of the particular event
(or no_author
if no author could be determined).
group
contains the name of the notification group
(that is the section heading without the braces). Further the
record may contain the values described at the extract_x509_author
option. All initial values can be overridden by one of the regular
expressions described above. Additionally the subject templates provide more
predefined values, but have a look there for details.
Configuring the Repository
Now, after you've created a config file, you can hook the svnmailer into the repository. Subversion uses so called hook scripts to perform customized actions at certain stages of a change event. (Note that the following descriptions don't apply directly to Windows.)
Configuring For Commit Messages
In order to run the svnmailer for normal commits you need to call
it at the post-commit stage. If your post-commit hook isn't customized
already, change into the repository/hooks
directory and copy the post-commit.tmpl
template to
post-commit
It's generally a good idea, to keep the template
file for later reference.
# change into the hooks directory
# (/var/svn/public is the repository in question)
$ cd /var/svn/public/hooks
# create the actual hook script from template
$ cp post-commit.tmpl post-commit
# edit the file
$ vi post-commit
# make it executable
$ chmod 755 post-commit
After you've copied the template open the newly created hook script with your favorite editor. You will see a lot of comments describing the purpose of the hook and giving some hints about file system permissions etc. After you've read these comments, there follows a small shell script. Typcially there are sample scripts activated, you may not want to run. If so, comment them out or delete the entries. Finally to activate the svnmailer, add the following:
# the location of svn-mailer may be customized,
# use the real location.
/usr/bin/svn-mailer --commit --config /path/to/your/config \
--repository "${REPOS}" --revision "${REV}" &
Of course, the REPOS
and REV
variables are
only available if you left the definitions below the comments. Anyway,
that's it. After you saved the file and closed your editor, you only have
to make it executable and subversion will execute it after every
commit. It is, however, a good idea to test the hook script as the user
who runs it, before doing the next commit (That is only possible, if there
are already revision stored in the repository):
# in this example wwwrun is the user the httpd runs as
$ sudo -u wwwrun ./post-commit /var/svn/public 1
Now you should receive a notification. If not, you should get a descriptive error message, what went wrong. By the way: a typical error is a non-readable configuration file.
Configuring For Revision Property Changes
Configuring for a revprop change message is mostly equal to commit
messages. If you do not allow to modify revision properties, you don't
need to care and can stop here. If you want to allow for revision
property changes, you should read the related subversion documentation regarding the
pre-revprop-change
and post-revprop-change
hooks first.
You need to hook the svnmailer into post-revprop-change
to get a notification containing the new property value.
# change into the hooks directory
# (/var/svn/public is the repository in question)
$ cd /var/svn/public/hooks
# create the actual hook script from template
$ cp post-revprop-change.tmpl post-revprop-change
# edit the file
$ vi post-revprop-change
# make it executable
$ chmod 755 post-revprop-change
After opening the hook script the same warnings as for post-commits
apply: remove all stuff, you don't want there. After that you can add
the svnmailer command to the script. Depending on the subversion release,
the command line may differ. Starting with subversion 1.2, the action
taken on the property and the old property value (via
STDIN
) are supplied to the hook script.
# the location of svn-mailer may be customized,
# use the real location.
# command line for SVN < 1.2
/usr/bin/svn-mailer --propchange --config /path/to/your/config \
--repository "${REPOS}" --revision "${REV}" \
--author "${USER}" --propname "${PROPNAME}" &
# command line for SVN >= 1.2
/usr/bin/svn-mailer --propchange --config /path/to/your/config \
--repository "${REPOS}" --revision "${REV}" \
--author "${USER}" --propname "${PROPNAME}" \
--action "${ACTION}" &
The REPOS
, REV
, USER
,
PROPNAME
and ACTION
variables should be still
defined, of course. Close the file, make it executable and test it:
# in this example wwwrun is the user the httpd runs as
# SVN < 1.2
$ sudo -u wwwrun ./post-revprop-change /var/svn/public 1 nd svn:log
# SVN >= 1.2
$ echo -n | sudo -u wwwrun \
./post-revprop-change /var/svn/public 1 nd svn:log A
Configuring For Lock Notifications
Locking notifications can be sent out when paths are either locked or
unlocked. Locking is a new feature of subversion 1.2. In order to
activate those notifications you need to hook the svnmailer into the
post-lock
hook and the post-unlock
hook
respectively. Similar to the other hooks there should be templates in
your hooks/
directory. However, if you've just upgraded
your subversion installation to 1.2, they may be not there, because the
templates are generated only when you're creating a new repository. So if
you don't find them, just create files in your hook directory named
post-lock
and post-unlock
.
Well, when you're editing the template copies, make sure there's nothing called you do not want. And that's what you have to put into the hook scripts to let the svnmailer do its work:
# the location of svn-mailer may be customized,
# use the real location.
# post-lock hook:
/usr/bin/svn-mailer --lock --config /path/to/your/config \
--repository "${REPOS}" --author "${USER}" &
# post-unlock hook:
/usr/bin/svn-mailer --unlock --config /path/to/your/config \
--repository "${REPOS}" --author "${USER}"
The REPOS
and USER
variables should be still
defined. If you've created the files from the scratch, the variable
definitions are as follows:
REPOS="$1"
USER="$2"
When you're done, close the file, make it exectuable and test it:
# in this example wwwrun is the user the httpd runs as
$ echo "/some/existing/file/in/your/repos" | \
sudo -u wwwrun ./post-lock /var/svn/public nd
$ echo "/some/existing/file/in/your/repos" | \
sudo -u wwwrun ./post-unlock /var/svn/public nd
Congratulations, you're done. Happy Hacking!
The svnmailer Command Line
Parameter Name | Type | Description |
---|---|---|
--version |
action | Shows the version and exits |
--help |
action | Shows a short help and exits |
--debug |
flag | Turns on debugging mode |
--path-encoding (-e ) |
string | The encoding used for file and path names |
--config (-f ) |
filepath | The location of the main config file |
--revision (-r ) |
int | The revision number to process |
--repository (-d ) |
filepath | The repository to process |
--commit (-c ) |
flag | Turns on the commit mode |
--propchange (-p ) |
flag | Turns on the revpropchange mode |
--lock (-p ) |
flag | Turns on the lock mode. SVN 1.2 and later |
--unlock (-p ) |
flag | Turns on the unlock mode. SVN 1.2 and later |
--author (-a ) |
string | The author of the change (usually for revprop changes only) |
--propname (-n ) |
string | The name of the modified property (for revprop changes only) |
--action (-o ) |
character | The revprop change action (A , D or
M ). SVN 1.2 and later |
The svnmailer is usually invoked via a small script called
svn-mailer
. It's located, whereever python installs it (have
a look at the installation procedure for
details). On my box it was installed to
/usr/bin/svn-mailer
. The script needs a number of command
line parameters, which control its behaviour.
svn-mailer
supports two command line styles: the
"old-style" command line, which is compatible to the original mailer.py
script and its own "new-style" command line, which takes named parameters
only. The latter is recommended, however.
The "old-style" variant is derived from svn itself. It starts with
a subcommand (either commit
or propchange
) and
continues with the necessary parameters. Further it is fixed. No
further options are allowed. Here are the old-style variants (optional
parameters are enclosed in square brackets):
svn-mailer commit repos revision [config]
svn-mailer propchange repos revision author propname
[config]
# (optionally) for SVN >= 1.2:
svn-mailer propchange2 repos revision author propname
action [config]
svn-mailer lock repos author [config]
svn-mailer unlock repos author [config]
These lines, translated into the new style, look about:
svn-mailer [--commit] [--config=config] \
--repository=repos
--revision=revision
svn-mailer --propchange [--config=config] \
--repository=repos
--revision=revision \
--author=author
--propname=propname
# (optionally) for SVN >= 1.2:
svn-mailer --propchange [--config=config] \
--repository=repos
--revision=revision \
--author=author
--propname=propname \
--action=action
svn-mailer --lock [--config=config] \
--repository=repos
--author=author
svn-mailer --unlock [--config=config] \
--repository=repos
--author=author
The following sections describe all available "new-style" command line parameters in detail.
--version
If you supply the --version
parameter, the
svnmailer writes its own name and version plus the version of the
subversion bindings it uses to stdout
and exits
immediately.
$ svn-mailer --version
svnmailer-1.0.9
with svn 1.1.3 (r12730)
--help
If you supply the --help
parameter, the
svnmailer writes a short usage information to stdout
and
exits immediately.
$ svn-mailer --help
usage: svn-mailer options
... description of the parameters ...
--debug
The --debug
option turns the svnmailer into
debug mode. This means, that no mails are sent, but written to
stdout
, so you can test your installation. Additionally a
header called X-Config-Groups
is attached, which
contains the selected notification groups.
$ svn-mailer --debug --repository=testrepos --revision=1
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
X-Mailer: svnmailer-1.0.9
Date: Sat, 15 Jan 2005 21:03:58 -0000
Subject: r1 - foo
To: foo@example.org
From: nd@example.org
X-Config-Groups: [defaults]
Author: nd
Date: Wed Jan 5 00:23:43 2005
New Revision: 1
Log:
added directory foo
Added:
foo/
--path-encoding (-e)
The --path-encoding
option can be used to
override the assumptions regarding the path name encodings the
svnmailer makes based on the locale environment. This affects
the paths given both via command line and config. If you're using
file and path names consisting of ASCII characters only, you can
(and probably should) safely skip the following paragraphs.
Normally this option should not be necessary.
However, the POSIX filesystem doesn't know anything about
encodings at all, so it can easily happen, that the bytes
that happen to represent the file name are not interpretable as
characters in the locale used. --path-encoding
provides
a workaround for this kind of problem (at least it tries to). You can
specify the encoding of filenames independet from the locale. It just
should be one of the codecs recognized by python.
Unfortunately there may be still a problem. The function
to open the repository of underlying subversion bindings expects an
unicode path and recodes it back to the locale representation (possibly
using a slightly different algortithm than python). That way, the
svnmailer has to recognize the encoding of the path given in the
command line. The conversion back to the locale (inside svn) is not
influencable by the --path-encoding
option. If
you get a crash caused by the subversion library, that describes
a recoding error, you can try setting the LC_CTYPE
environment variable to some ISO-8859-1
locale (like
en_US.iso-8859-1
), and just treat the octets of the
file names as characters (the reason for this is, that the
codepoints of ISO-8859-1
are compatible to unicode, so
it should be all recoded smoothly) -- or use
--path-encoding
to supply it in a readable form to the
svnmailer.
Anyway, the best solution is either to use just ASCII names or
to use consistent encodings for file names and locales.
UTF-8
is a good choice.
--config (-f)
The --config
option is used to pass the path
and name of a configuration file to the svnmailer.
If you omit this option, the svnmailer looks at some default locations for
a config, which are in order: repos/conf/mailer.conf
, a
file called mailer.conf
in the same directory the
svn-mailer
script is located in and
/etc/svn-mailer.conf
. The file found first wins. If you
didn't supply a --config
option and no file is found at
the default locations, the svnmailer exits with an error. It is
recommended, to supply always the full path to the config file, so
that no misunderstandings can happen.
If the supplied config file is a single dash (-
), the
config is read from STDIN
. Note that this interferes with the
property value supplied via stdin on revision property changes in
subversion 1.2 and later.
For convenience the --config
option can also be written as
-f
.
--revision (-r)
The --revision
parameter defines the revision
to process. It has to be a number and a valid revision of the supplied repository, otherwise the svnmailer will exit
with an error. Typically you don't need to worry about this, since the
proper revision number is passed to the hook script by subversion
itself.
For convenience the --revision
parameter can also be
written as -r
.
--repository (-d)
The --repository
parameter specifies the full
filesystem location of the repository. This is the path matched
against by the for_repos
configuration option. If it does not point to a subversion repository,
the svnmailer will exit with an error. Typically you don't need to
worry about this, since the proper repository path is passed to the
hook script by subversion itself.
For convenience the --repository
parameter can also be
written as -d
.
--commit (-c), --propchange (-p), --lock (-l) and --unlock (-u)
These options tell the svnmailer whether it is running in the
post-commit, the post-revprop-change, the
post-lock or the post-unlock hook. They
are mutually exclusive (in fact, if you supply more of one, the most
right option wins). The --commit
option is default and can
be omitted. The --lock
and --unlock
switches
are only available if you're using subversion 1.2 or later. Have a
look at the repository configuration section
for further information.
The options also can be abbreviated, of course. --commit
can be written as -c
, --propchange
as
-p
. --lock
as -l
and
--unlock
as -u
.
--author (-a)
The --author
option defines the author of the
change. This is typically used in the post-revprop-change hook, where the
author maybe different from the original revision author. The change
author is passed to the hook script by subversion.
It is also possible to pass the --author
option from
within the post-commit hook. In that case it overrides the revision
author noted in the repository. This is useful, if there is no
revision author stored.
For convenience the --author
parameter can also be written
as -a
.
--propname (-p)
The --propname
parameter is only used for
revprop-change notifications. It specifies the name of the property
being modified. The name is passed to the hook script by subversion.
For convenience the --propname
parameter can also be
written as -n
.
--action (-o)
The --action
parameter is only used for
revprop-change notifications. It specifies the action that was taken on
the specified property. It contains one of the letters A
(for
"added"), M
(for "modified") or D
(for
"deleted"). The proper value is passed to the hook script by subversion
1.2 and later. If the svnmailer is in propchange mode and this parameter
is specified and valid, the svnmailer reads the old property value from
STDIN
and generates a diff between the old and the new
value.
For convenience the --action
parameter can also be
written as -o
(shortcut for "operation" :-).