| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package SVN::Notify; |
|
2
|
|
|
|
|
|
|
|
|
3
|
293
|
|
|
293
|
|
409453
|
use strict; |
|
|
293
|
|
|
|
|
885
|
|
|
|
293
|
|
|
|
|
24713
|
|
|
4
|
|
|
|
|
|
|
require 5.006_000; |
|
5
|
293
|
|
|
293
|
|
42613
|
use constant WIN32 => $^O eq 'MSWin32'; |
|
|
293
|
|
|
|
|
683
|
|
|
|
293
|
|
|
|
|
50870
|
|
|
6
|
293
|
|
|
293
|
|
1915
|
use constant PERL58 => $] > 5.007_000; |
|
|
293
|
|
|
|
|
656
|
|
|
|
293
|
|
|
|
|
246646
|
|
|
7
|
|
|
|
|
|
|
require Encode if PERL58; |
|
8
|
|
|
|
|
|
|
$SVN::Notify::VERSION = '2.84'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Make sure any output (such as from _dbpnt()) triggers no Perl warnings. |
|
11
|
|
|
|
|
|
|
if (PERL58) { |
|
12
|
|
|
|
|
|
|
# Dupe them? |
|
13
|
|
|
|
|
|
|
binmode STDOUT, ':utf8'; |
|
14
|
|
|
|
|
|
|
binmode STDERR, ':utf8'; |
|
15
|
|
|
|
|
|
|
} |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 Name |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
SVN::Notify - Subversion activity notification |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 Synopsis |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Use F in F: |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
svnnotify --repos-path "$1" --revision "$2" \ |
|
26
|
|
|
|
|
|
|
--to developers@example.com [options] |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
svnnotify --repos-path "$1" --revision "$2" \ |
|
29
|
|
|
|
|
|
|
--to-cx-regex i10n@example.com=I10N [options] |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Use the class in a custom script: |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
use SVN::Notify; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my $notifier = SVN::Notify->new(%params); |
|
36
|
|
|
|
|
|
|
$notifier->prepare; |
|
37
|
|
|
|
|
|
|
$notifier->execute; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 Description |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
This class may be used for sending email messages for Subversion repository |
|
42
|
|
|
|
|
|
|
activity. There are a number of different modes supported, and SVN::Notify is |
|
43
|
|
|
|
|
|
|
fully subclassable, to add new functionality, and offers L
|
|
44
|
|
|
|
|
|
|
content filtering|SVN::Notify::Filter> to easily modify the format of its |
|
45
|
|
|
|
|
|
|
messages. By default, A list of all the files affected by the commit will be |
|
46
|
|
|
|
|
|
|
assembled and listed in a single message. An additional option allows diffs to |
|
47
|
|
|
|
|
|
|
be calculated for the changes and either appended to the message or added as |
|
48
|
|
|
|
|
|
|
an attachment. See the C and C options below. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 Usage |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
To use SVN::Notify, simply add a call to F to your Subversion |
|
53
|
|
|
|
|
|
|
repository's F script. This script lives in the F |
|
54
|
|
|
|
|
|
|
directory at the root of the repository directory; consult the documentation |
|
55
|
|
|
|
|
|
|
in F for details. Make sure that you specify the complete |
|
56
|
|
|
|
|
|
|
path to F, as well as to F and F in the options |
|
57
|
|
|
|
|
|
|
passed to F so that everything executes properly. And if you |
|
58
|
|
|
|
|
|
|
specify any string options, be sure that they are in the encoding specified by |
|
59
|
|
|
|
|
|
|
the C<--encoding> option, or UTF-8 if you have not specified C<--encoding>. |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head2 Windows Usage |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
To get SVN::Notify to work properly in a F script, you must set |
|
64
|
|
|
|
|
|
|
the following environment variables, as they will likely not be present inside |
|
65
|
|
|
|
|
|
|
Apache: |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=over |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=item PATH=C:\perl\bin |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item OS=Windows_NT |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=item SystemRoot=C:\WINDOWS |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=back |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
See L
|
|
78
|
|
|
|
|
|
|
HOWTO|http://svn.haxx.se/users/archive-2006-05/0593.shtml> for more detailed |
|
79
|
|
|
|
|
|
|
information on getting SVN::Notify running on Windows. If you have issues with |
|
80
|
|
|
|
|
|
|
asynchronous execution, try using |
|
81
|
|
|
|
|
|
|
L|http://www.koders.com/csharp/fidE2724F44EF2D47F1C0FE76C538006435FA20051D.aspx> |
|
82
|
|
|
|
|
|
|
to run F. |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=cut |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Map the svnlook changed codes to nice labels. |
|
87
|
|
|
|
|
|
|
my %map = ( |
|
88
|
|
|
|
|
|
|
U => 'Modified Paths', |
|
89
|
|
|
|
|
|
|
A => 'Added Paths', |
|
90
|
|
|
|
|
|
|
D => 'Removed Paths', |
|
91
|
|
|
|
|
|
|
_ => 'Property Changed', |
|
92
|
|
|
|
|
|
|
); |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my %filters; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
############################################################################## |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 Class Interface |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head2 Constructor |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head3 new |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $notifier = SVN::Notify->new(%params); |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Constructs and returns a new SVN::Notify object. This object is a handle on |
|
107
|
|
|
|
|
|
|
the whole process of collecting meta data and content for the commit email and |
|
108
|
|
|
|
|
|
|
then sending it. As such, it takes a number of parameters to affect that |
|
109
|
|
|
|
|
|
|
process. |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Each of these parameters has a corresponding command-line option that can be |
|
112
|
|
|
|
|
|
|
passed to F. The options have the same names as these parameters, |
|
113
|
|
|
|
|
|
|
but any underscores you see here should be replaced with dashes when passed to |
|
114
|
|
|
|
|
|
|
F. Most also have a corresponding single-character option. On Perl |
|
115
|
|
|
|
|
|
|
5.8 and higher, If you pass parameters to C, they B be L
|
|
116
|
|
|
|
|
|
|
into Perl's internal form|Encode/"PERL ENCODING API"> if they have any |
|
117
|
|
|
|
|
|
|
non-ASCII characters. |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Supported parameters: |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=over |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item repos_path |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
svnnotify --repos-path "$PATH" |
|
126
|
|
|
|
|
|
|
svnnotify -p "$PATH" |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
The path to the Subversion repository. The path is passed as the first |
|
129
|
|
|
|
|
|
|
argument when Subversion executes F. So you can simply pass C<$1> |
|
130
|
|
|
|
|
|
|
to this parameter if you like. See the documentation in F for |
|
131
|
|
|
|
|
|
|
details. Required. |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item revision |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
svnnotify --revision "$REV" |
|
136
|
|
|
|
|
|
|
svnnotify -r "$REV" |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
The revision number for the current commit. The revision number is passed as |
|
139
|
|
|
|
|
|
|
the second argument when Subversion executes F. So you can |
|
140
|
|
|
|
|
|
|
simply pass C<$2> to this parameter if you like. See the documentation in |
|
141
|
|
|
|
|
|
|
F for details. Required. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item to |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
svnnotify --to commiters@example.com |
|
146
|
|
|
|
|
|
|
svnnotify -t commiters@example.com --to managers@example.com |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
The address or addresses to which to send the notification email. Can be used |
|
149
|
|
|
|
|
|
|
multiple times to specify multiple addresses. This parameter is required |
|
150
|
|
|
|
|
|
|
unless either C or C is specified. |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item to_regex_map |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
svnnotify --to-regex-map translate@example.com=L18N \ |
|
155
|
|
|
|
|
|
|
-x legal@example.com=License |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
This parameter specifies a hash reference of email addresses to regular |
|
158
|
|
|
|
|
|
|
expression strings. SVN::Notify will compile the regular expression strings |
|
159
|
|
|
|
|
|
|
into regular expression objects, and then send notification messages if and |
|
160
|
|
|
|
|
|
|
only if the name of one or more of the paths affected by a commit matches the |
|
161
|
|
|
|
|
|
|
regular expression. This is a good way to have a notification email sent to a |
|
162
|
|
|
|
|
|
|
particular mail address (or comma-delimited list of addresses) only for |
|
163
|
|
|
|
|
|
|
certain parts of the subversion tree. This parameter is required unless C |
|
164
|
|
|
|
|
|
|
or C is specified. |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
The command-line options, C<--to-regex_map> and C<-x>, can be specified any |
|
167
|
|
|
|
|
|
|
number of times, once for each entry in the hash to be passed to C. The |
|
168
|
|
|
|
|
|
|
value passed to the option must be in the form of the key and the value |
|
169
|
|
|
|
|
|
|
separated by an equal sign. Consult the L documentation for more |
|
170
|
|
|
|
|
|
|
information. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Here's an example complements of Matt Doar of how to use C to do |
|
173
|
|
|
|
|
|
|
per-branch matching: |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
author=`svnlook author $REPOS -r $REV` |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# The mail regexes should match all the top-level directories |
|
178
|
|
|
|
|
|
|
/usr/bin/svnnotify --repos-path "$REPOS" --revision "$REV" \ |
|
179
|
|
|
|
|
|
|
-x eng-bar@example.com,${EXTRAS}="^Bar" \ |
|
180
|
|
|
|
|
|
|
-x eng-foo@example.com,${EXTRAS}="^trunk/Foo|^branches/Foo|^tags/Foo" \ |
|
181
|
|
|
|
|
|
|
-x $author@example.com="^users" --subject-cx |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item to_email_map |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
svnnotify --to-email-map L18N=translate@example.com \ |
|
186
|
|
|
|
|
|
|
--to-email-map License=legal@example.com |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
The inverse of C: The regular expression is the hash key |
|
189
|
|
|
|
|
|
|
and the email address or addresses are the value. |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item from |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
svnnotify --from somewhere@example.com |
|
194
|
|
|
|
|
|
|
svnnotify -f elsewhere@example.com |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
The email address to use in the "From" line of the email. If not specified, |
|
197
|
|
|
|
|
|
|
SVN::Notify will use the username from the commit, as returned by C
|
|
198
|
|
|
|
|
|
|
info>. |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item user_domain |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
svnnotify --user-domain example.com |
|
203
|
|
|
|
|
|
|
svnnotify -D example.net |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
A domain name to append to the username for the "From" header of the email. |
|
206
|
|
|
|
|
|
|
During a Subversion commit, the username returned by C is |
|
207
|
|
|
|
|
|
|
usually something like a Unix login name. SVN::Notify will use this username |
|
208
|
|
|
|
|
|
|
in the email "From" header unless the C parameter is specified. If you |
|
209
|
|
|
|
|
|
|
wish to have the username take the form of a real email address, specify a |
|
210
|
|
|
|
|
|
|
domain name and SVN::Notify will append C<\@$domain_name> to the username in |
|
211
|
|
|
|
|
|
|
order to create a real email address. This can be useful if all of your |
|
212
|
|
|
|
|
|
|
committers have an email address that corresponds to their username at the |
|
213
|
|
|
|
|
|
|
domain specified by the C parameter. |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=item svnlook |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
svnnotify --svnlook /path/to/svnlook |
|
218
|
|
|
|
|
|
|
svnnotify -l /path/to/svnlook |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
The location of the F executable. If not specified, SVN::Notify will |
|
221
|
|
|
|
|
|
|
search through the directories in the C<$PATH> environment variable, plus in |
|
222
|
|
|
|
|
|
|
F and F, for an F executable. Specify a |
|
223
|
|
|
|
|
|
|
full path to F via this option or by setting the C<$SVNLOOK> |
|
224
|
|
|
|
|
|
|
environment variable if F isn't in your path or to avoid loading |
|
225
|
|
|
|
|
|
|
L. |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
It's important to provide a complete path to F because the |
|
228
|
|
|
|
|
|
|
environment during the execution of F is anemic, with nary a |
|
229
|
|
|
|
|
|
|
C<$PATH> environment variable to be found. So if F appears not to |
|
230
|
|
|
|
|
|
|
be working at all (and Subversion seems loathe to log when it dies!), make |
|
231
|
|
|
|
|
|
|
sure that you have specified the complete path to a working F |
|
232
|
|
|
|
|
|
|
executable. |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item sendmail |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
svnnotify --sendmail /path/to/sendmail |
|
237
|
|
|
|
|
|
|
svnnotify -s /path/to/sendmail |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
The location of the F executable. If neither the C nor the |
|
240
|
|
|
|
|
|
|
C parameter is specified, SVN::Notify will search through the |
|
241
|
|
|
|
|
|
|
directories in the C<$PATH> environment variable, plus in F |
|
242
|
|
|
|
|
|
|
and F, for an F executable. Specify a full path to |
|
243
|
|
|
|
|
|
|
F via this option or by setting the C<$SENDMAIL> environment |
|
244
|
|
|
|
|
|
|
variable if F isn't in your path or to avoid loading |
|
245
|
|
|
|
|
|
|
L. The same caveats as applied to the location of the |
|
246
|
|
|
|
|
|
|
F executable apply here. |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item set_sender |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
svnnotify --set-sender |
|
251
|
|
|
|
|
|
|
svnnotify -E |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Uses the C<-f> option to C to set the envelope sender address of the |
|
254
|
|
|
|
|
|
|
email to the same address as is used for the "From" header. If you're also |
|
255
|
|
|
|
|
|
|
using the C option, be sure to make it B an email address. Don't |
|
256
|
|
|
|
|
|
|
include any other junk in it, like a sender's name. Ignored when using |
|
257
|
|
|
|
|
|
|
C. |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=item smtp |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
svnnotify --smtp smtp.example.com |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
The address for an SMTP server through which to send the notification email. |
|
264
|
|
|
|
|
|
|
If unspecified, SVN::Notify will use F to send the message. If |
|
265
|
|
|
|
|
|
|
F is not installed locally (such as on Windows boxes!), you I |
|
266
|
|
|
|
|
|
|
specify an SMTP server. |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=item smtp_tls |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
svnnotify --smtp-tls |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Use TLS authentication and encrypted channels for connecting with the server. |
|
273
|
|
|
|
|
|
|
Usually, TLS servers will require user/password authentication. |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item smtp_user |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
svnnotify --smtp-user myuser |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
The user name for SMTP authentication. If this option is specified, |
|
280
|
|
|
|
|
|
|
SVN::Notify will use L to send the notification |
|
281
|
|
|
|
|
|
|
message, and will of course authenticate to the SMTP server. |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=item smtp_pass |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
svnnotify --smtp-pass mypassword |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
The password for SMTP authentication. Use in parallel with C. |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item smtp_port |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
svnnotify --smtp-port 465 |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
The port for an SMTP server through which to send the notification email. The |
|
294
|
|
|
|
|
|
|
default port is 25. |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item smtp_authtype |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
svnnotify --smtp-authtype authtype |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Deprecated in SVN::Notify 2.83, where it has become a no-op. The auth type is |
|
301
|
|
|
|
|
|
|
determined by the contents returned by the SMTP server's response to the |
|
302
|
|
|
|
|
|
|
C command. See L for details. |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=item encoding |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
svnnotify --encoding UTF-8 |
|
307
|
|
|
|
|
|
|
svnnotify -c Big5 |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
The character set typically used on the repository for log messages, file |
|
310
|
|
|
|
|
|
|
names, and file contents. Used to specify the character set in the email |
|
311
|
|
|
|
|
|
|
Content-Type headers and, when the C parameter is specified, the |
|
312
|
|
|
|
|
|
|
C<$LANG> environment variable when launching C. See L"Character |
|
313
|
|
|
|
|
|
|
Encoding Support"> for more information. Defaults to "UTF-8". |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=item charset |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
svnnotify --charset UTF-8 |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
Deprecated. Use C instead. |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=item svn_encoding |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
svnnotify --svn-encoding euc-jp |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
The character set used in files and log messages managed in Subversion. It's |
|
326
|
|
|
|
|
|
|
useful to set this option if you store files in Subversion using one character |
|
327
|
|
|
|
|
|
|
set but want to send notification messages in a different character set. |
|
328
|
|
|
|
|
|
|
Therefore C would be used for the notification message, and |
|
329
|
|
|
|
|
|
|
C would be used to read in data from Subversion. See |
|
330
|
|
|
|
|
|
|
L"Character Encoding Support"> for more information. Defaults to the value |
|
331
|
|
|
|
|
|
|
stored in C. |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item diff_encoding |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
svnnotify --diff-encoding iso-2022-jp |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
The character set used by files in Subversion, and thus present in the the |
|
338
|
|
|
|
|
|
|
diff. It's useful to set this option if you store files in Subversion using |
|
339
|
|
|
|
|
|
|
one character write log messages in a different character set. Therefore |
|
340
|
|
|
|
|
|
|
C would be used to read the log message and C |
|
341
|
|
|
|
|
|
|
would be used to read the diff from Subversion. See L"Character Encoding |
|
342
|
|
|
|
|
|
|
Support"> for more information. Defaults to the value stored in |
|
343
|
|
|
|
|
|
|
C. |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=item language |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
svnnotify --language fr |
|
348
|
|
|
|
|
|
|
svnnotify -g i-klingon |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
The language typically used on the repository for log messages, file names, |
|
351
|
|
|
|
|
|
|
and file contents. Used to specify the email Content-Language header and to |
|
352
|
|
|
|
|
|
|
set the C<$LANG> environment variable to C<< $notify->language . '.' . |
|
353
|
|
|
|
|
|
|
$notify->encoding >> before executing C and C (but not for |
|
354
|
|
|
|
|
|
|
sending data to Net::SMTP). Undefined by default, meaning that no |
|
355
|
|
|
|
|
|
|
Content-Language header is output and the C<$LANG> environment variable will |
|
356
|
|
|
|
|
|
|
not be set. See L"Character Encoding Support"> for more information. |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=item with_diff |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
svnnotify --with-diff |
|
361
|
|
|
|
|
|
|
svnnotify -d |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
A boolean value specifying whether or not to include the output of C
|
|
364
|
|
|
|
|
|
|
diff> in the notification email. The diff will be inline at the end of the |
|
365
|
|
|
|
|
|
|
email unless the C parameter specifies a true value. |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=item attach_diff |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
svnnotify --attach-diff |
|
370
|
|
|
|
|
|
|
svnnotify -a |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
A boolean value specifying whether or not to attach the output of C
|
|
373
|
|
|
|
|
|
|
diff> to the notification email. Rather than being inline in the body of the |
|
374
|
|
|
|
|
|
|
email, this parameter causes SVN::Notify to attach the diff as a separate |
|
375
|
|
|
|
|
|
|
file, named for the user who triggered the commit and the date and time UTC at |
|
376
|
|
|
|
|
|
|
which the commit took place. Specifying this parameter to a true value |
|
377
|
|
|
|
|
|
|
implicitly sets the C parameter to a true value. |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=item diff_switches |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
svnnotify --diff-switches '--no-diff-added' |
|
382
|
|
|
|
|
|
|
svnnotify -w '--no-diff-deleted' |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Switches to pass to C, such as C<--no-diff-deleted> and |
|
385
|
|
|
|
|
|
|
C<--no-diff-added>. And who knows, maybe someday it will support the same |
|
386
|
|
|
|
|
|
|
options as C, such as C<--diff-cmd> and C<--extensions>. Only |
|
387
|
|
|
|
|
|
|
relevant when used with C or C. |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item diff_content_type |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
svnnotify --diff-content-type 'text/x-diff' |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Sets the Content-Type header for attached diffs. The default, if this parameter |
|
394
|
|
|
|
|
|
|
is not passed, is 'text/plain'. This parameter has no effect if '--attach-diff' |
|
395
|
|
|
|
|
|
|
is not specified. |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=item reply_to |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
svnnotify --reply-to devlist@example.com |
|
400
|
|
|
|
|
|
|
svnnotify -R developers@example.net |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
The email address to use in the "Reply-To" header of the notification email. |
|
403
|
|
|
|
|
|
|
No "Reply-To" header will be added to the email if no value is specified for |
|
404
|
|
|
|
|
|
|
the C parameter. |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=item add_headers |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
svnnotify --add-header X-Approve=letMeIn |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Add a header to the notification email message. The header name and its value |
|
411
|
|
|
|
|
|
|
must be separated by an equals sign. Specify the option multiple times in |
|
412
|
|
|
|
|
|
|
order to add multiple headers. Headers with the same names are allowed. Not to |
|
413
|
|
|
|
|
|
|
be confused with the C<--header> option, which adds introductory text to the |
|
414
|
|
|
|
|
|
|
beginning of the email body. |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=item subject_prefix |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
svnnotify --subject-prefix [Devlist] |
|
419
|
|
|
|
|
|
|
svnnotify -P [%d (Our-Developers)] |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
An optional string to prepend to the beginning of the subject line of the |
|
422
|
|
|
|
|
|
|
notification email. If it contains '%d', it will be used to place the revision |
|
423
|
|
|
|
|
|
|
number; otherwise it will simply be prepended to the subject, which will |
|
424
|
|
|
|
|
|
|
contain the revision number in brackets. |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=item subject_cx |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
svnnotify --subject-cx |
|
429
|
|
|
|
|
|
|
svnnotify -C |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
A boolean value indicating whether or not to include a the context of the |
|
432
|
|
|
|
|
|
|
commit in the subject line of the email. In a commit that affects multiple |
|
433
|
|
|
|
|
|
|
files, the context will be the name of the shortest directory affected by the |
|
434
|
|
|
|
|
|
|
commit. This should indicate up to how high up the Subversion repository tree |
|
435
|
|
|
|
|
|
|
the commit had an effect. If the commit affects a single file, then the |
|
436
|
|
|
|
|
|
|
context will simply be the name of that file. |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item strip_cx_regex |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
svnnotify --strip-cx-regex '^trunk/' |
|
441
|
|
|
|
|
|
|
svnnotify --strip-cx-regex '^trunk/' --strip-cx-regex '^branches/' |
|
442
|
|
|
|
|
|
|
svnnotify -X '^trunk' |
|
443
|
|
|
|
|
|
|
svnnotify -X '^trunk' -X '^branches' |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
One or more regular expressions to be used to strip out parts of the subject |
|
446
|
|
|
|
|
|
|
context. This can be useful for very deep Subversion trees, where the commits |
|
447
|
|
|
|
|
|
|
you're sending will always be sent from a particular subtree, so you'd like to |
|
448
|
|
|
|
|
|
|
remove part of the tree. Used only if C is set to a true value. |
|
449
|
|
|
|
|
|
|
Pass an array reference if calling C directly. |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=item no_first_line |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
svnnotify --no-first-line |
|
454
|
|
|
|
|
|
|
svnnotify -O |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Omits the first line of the log message from the subject. This is most useful |
|
457
|
|
|
|
|
|
|
when used in combination with the C parameter, so that just the |
|
458
|
|
|
|
|
|
|
commit context is displayed in the subject and no part of the log message. |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=item header |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
svnnotify --header 'SVN::Notify is brought to you by Kineticode. |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Adds a specified text to each message as a header at the beginning of the body |
|
465
|
|
|
|
|
|
|
of the message. Not to be confused with the C<--add-header> option, which adds |
|
466
|
|
|
|
|
|
|
a header to the headers section of the email. |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=item footer |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
svnnotify --footer 'Copyright (R) by Kineticode, Inc.' |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Adds a specified text to each message as a footer at the end of the body of |
|
473
|
|
|
|
|
|
|
the message. |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=item max_sub_length |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
svnnotify --max-sub-length 72 |
|
478
|
|
|
|
|
|
|
svnnotify -i 76 |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
The maximum length of the notification email subject line. SVN::Notify |
|
481
|
|
|
|
|
|
|
includes the first line of the commit log message, or the first sentence of |
|
482
|
|
|
|
|
|
|
the message (defined as any text up to the string ". "), whichever is |
|
483
|
|
|
|
|
|
|
shorter. This could potentially be quite long. To prevent the subject from |
|
484
|
|
|
|
|
|
|
being over a certain number of characters, specify a maximum length here, and |
|
485
|
|
|
|
|
|
|
SVN::Notify will truncate the subject to the last word under that length. |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=item max_diff_length |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
svnnotify --max-diff-length 1024 |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
The maximum length of the diff (attached or in the body). The diff output is |
|
492
|
|
|
|
|
|
|
truncated at the last line under the maximum character count specified and |
|
493
|
|
|
|
|
|
|
then outputs an additional line indicating that the maximum diff size was |
|
494
|
|
|
|
|
|
|
reached and output truncated. This is helpful when a large diff output could |
|
495
|
|
|
|
|
|
|
cause a message to bounce due to message size. |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=item handler |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
svnnotify --handler HTML |
|
500
|
|
|
|
|
|
|
svnnotify -H HTML |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
Specify the subclass of SVN::Notify to be constructed and returned, and |
|
503
|
|
|
|
|
|
|
therefore to handle the notification. Of course you can just use a subclass |
|
504
|
|
|
|
|
|
|
directly, but this parameter is designed to make it easy to just use |
|
505
|
|
|
|
|
|
|
C<< SVN::Notify->new >> without worrying about loading subclasses, such as in |
|
506
|
|
|
|
|
|
|
F. Be sure to read the documentation for your subclass of choice, |
|
507
|
|
|
|
|
|
|
as there may be additional parameters and existing parameters may behave |
|
508
|
|
|
|
|
|
|
differently. |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=item filters |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
svnnotify --filter Trac -F My::Filter |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
SVN::Notify->new( %params, filters => ['Markdown', 'My::Filter'] ); |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
Specify a more module to be loaded in the expectation that it defines output |
|
517
|
|
|
|
|
|
|
filters. For example, L |
|
518
|
|
|
|
|
|
|
loads a filter that converts log messages from Trac's markup format to HTML. |
|
519
|
|
|
|
|
|
|
L, available on |
|
520
|
|
|
|
|
|
|
CPAN, does the same for Markdown format. Check CPAN for other SVN::Notify |
|
521
|
|
|
|
|
|
|
filter modules. |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
This command-line option can be specified more than once to load multiple |
|
524
|
|
|
|
|
|
|
filters. The C parameter to C should be an array reference of |
|
525
|
|
|
|
|
|
|
modules names. If a value contains "::", it is assumed to be a complete module |
|
526
|
|
|
|
|
|
|
name. Otherwise, it is assumed to be in the SVN::Notify::Filter name space. |
|
527
|
|
|
|
|
|
|
See L for details on writing your own |
|
528
|
|
|
|
|
|
|
output filters (it's really easy, I promise!). |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=item author_url |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
svnnotify --author-url 'http://svn.example.com/changelog/~author=%s/repos' |
|
533
|
|
|
|
|
|
|
svnnotify --A 'mailto:%s@example.com' |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
If a URL is specified for this parameter, then it will be used to create a |
|
536
|
|
|
|
|
|
|
link for the current author. The URL can have the "%s" format where the |
|
537
|
|
|
|
|
|
|
author's username should be put into the URL. |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item revision_url |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
svnnotify --revision-url 'http://svn.example.com/changelog/?cs=%s' |
|
542
|
|
|
|
|
|
|
svnnotify -U 'http://svn.example.com/changelog/?cs=%s' |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
If a URL is specified for this parameter, then it will be used to create a |
|
545
|
|
|
|
|
|
|
link to the Subversion browser URL corresponding to the current revision |
|
546
|
|
|
|
|
|
|
number. It will also be used to create links to any other revision numbers |
|
547
|
|
|
|
|
|
|
mentioned in the commit message. The URL must have the "%s" format where the |
|
548
|
|
|
|
|
|
|
Subversion revision number should be put into the URL. |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=item svnweb_url |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
svnnotify --svnweb-url 'http://svn.example.com/index.cgi/revision/?rev=%s' |
|
553
|
|
|
|
|
|
|
svnnotify -S 'http://svn.example.net/index.cgi/revision/?rev=%s' |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Deprecated. Use C instead. |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=item viewcvs_url |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
svnnotify --viewcvs-url 'http://svn.example.com/viewcvs/?rev=%s&view=rev' |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
Deprecated. Use C instead. |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=item ticket_map |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
svnnotify --ticket-map '\[?#\s*(\d+)\s*\]?=http://example.com/ticket?id=%s' \ |
|
566
|
|
|
|
|
|
|
--ticket-map 'rt=http://rt.cpan.org/NoAuth/Bugs.html?id=%s' \ |
|
567
|
|
|
|
|
|
|
--ticket-map '\b([A-Z0-9]+-\d+)\b=http://jira/browse/%s' |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Specifies a mapping between a regular expression and a URL. The regular |
|
570
|
|
|
|
|
|
|
expression should return a single match to be interpolated into the URL, which |
|
571
|
|
|
|
|
|
|
should be a C format using "%s" to place the match (usually the |
|
572
|
|
|
|
|
|
|
ticket identifier) from the regex. The command-line option may be specified |
|
573
|
|
|
|
|
|
|
any number of times for different ticketing systems. To the API, it must be |
|
574
|
|
|
|
|
|
|
passed as a hash reference. |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
The first example matches "[#1234]" or "#1234" or "[# 1234]". This regex |
|
577
|
|
|
|
|
|
|
should be as specific as possible, preferably wrapped in "\b" to match word |
|
578
|
|
|
|
|
|
|
boundaries. If you're using L, be sure to |
|
579
|
|
|
|
|
|
|
read its documentation for a different regular expression requirement! |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Optionally, the key value can be a placeholder for a regular expression used |
|
582
|
|
|
|
|
|
|
internally by SVN::Notify to match strings typically used for well-known |
|
583
|
|
|
|
|
|
|
ticketing systems. Those keys are: |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=over |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=item rt |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Matches Request Tracker (RT) ticket references of the form "Ticket # 12", |
|
590
|
|
|
|
|
|
|
"ticket 6", "RT # 52", "rt 52", "RT-Ticket # 213" or even "Ticket#1066". |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=item bugzilla |
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Matches Bugzilla bug references of the form "Bug # 12" or "bug 6" or even |
|
595
|
|
|
|
|
|
|
"Bug#1066". |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=item jira |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
Matches JIRA references of the form "JRA-1234". |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=item gnats |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
Matches GnatsWeb references of the form "PR 1234". |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=back |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=item rt_url |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
svnnotify --rt-url 'http://rt.cpan.org/NoAuth/Bugs.html?id=%s' |
|
610
|
|
|
|
|
|
|
svnnotify -T 'http://rt.perl.org/NoAuth/Bugs.html?id=%s' |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
A shortcut for C<--ticket-map 'rt=$url'> provided for backwards compatibility. |
|
613
|
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
=item bugzilla_url |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
svnnotify --bugzilla-url 'http://bugzilla.mozilla.org/show_bug.cgi?id=%s' |
|
617
|
|
|
|
|
|
|
svnnotify -B 'http://bugs.bricolage.cc/show_bug.cgi?id=%s' |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
A shortcut for C<--ticket-map 'bugzilla=$url'> provided for backwards |
|
620
|
|
|
|
|
|
|
compatibility. |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=item jira_url |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
svnnotify --jira-url 'http://jira.atlassian.com/secure/ViewIssue.jspa?key=%s' |
|
625
|
|
|
|
|
|
|
svnnotify -J 'http://nagoya.apache.org/jira/secure/ViewIssue.jspa?key=%s' |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
A shortcut for C<--ticket-map 'jira=$url'> provided for backwards |
|
628
|
|
|
|
|
|
|
compatibility. |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=item gnats_url |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
svnnotify --gnats-url 'http://gnatsweb.example.com/cgi-bin/gnatsweb.pl?cmd=view&pr=%s' |
|
633
|
|
|
|
|
|
|
svnnotify -G 'http://gnatsweb.example.com/cgi-bin/gnatsweb.pl?cmd=view&pr=%s' |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
A shortcut for C<--ticket-map 'gnats=$url'> provided for backwards |
|
636
|
|
|
|
|
|
|
compatibility. |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=item ticket_url |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
svnnotify --ticket-url 'http://ticket.example.com/showticket.html?id=%s' |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
Deprecated. Use C, instead. |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=item ticket_regex |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
svnnotify --ticket-regex '\[?#\s*(\d+)\s*\]?' |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
Deprecated. Use C, instead. |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=item verbose |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
svnnotify --verbose -V |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
A value between 0 and 3 specifying how verbose SVN::Notify should be. The |
|
655
|
|
|
|
|
|
|
default is 0, meaning that SVN::Notify will be silent. A value of 1 causes |
|
656
|
|
|
|
|
|
|
SVN::Notify to output some information about what it's doing, while 2 and 3 |
|
657
|
|
|
|
|
|
|
each cause greater verbosity. To set the verbosity on the command line, simply |
|
658
|
|
|
|
|
|
|
pass the C<--verbose> or C<-V> option once for each level of verbosity, up to |
|
659
|
|
|
|
|
|
|
three times. Output from SVN::Notify is sent to C. |
|
660
|
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item boundary |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
The boundary to use between email body text and attachments. This is normally |
|
664
|
|
|
|
|
|
|
generated by SVN::Notify. |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=item subject |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
The subject of the email to be sent. This attribute is normally generated by |
|
669
|
|
|
|
|
|
|
C. |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=back |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=cut |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# XXX Sneakily used by SVN::Notify::HTML. Change to use class methods? |
|
676
|
|
|
|
|
|
|
our %_ticket_regexen = ( |
|
677
|
|
|
|
|
|
|
rt => '\b((?:rt|(?:rt-)?ticket:?)\s*#?\s*(\d+))\b', |
|
678
|
|
|
|
|
|
|
bugzilla => '\b(bug\s*#?\s*(\d+))\b', |
|
679
|
|
|
|
|
|
|
jira => '\b([A-Z0-9]+-\d+)\b', |
|
680
|
|
|
|
|
|
|
gnats => '\b(PR\s*(\d+))\b', |
|
681
|
|
|
|
|
|
|
); |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub new { |
|
684
|
3406
|
|
|
3406
|
1
|
55835994
|
my ($class, %params) = @_; |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
# Delegate to a subclass if requested. |
|
687
|
3406
|
100
|
|
|
|
29004
|
if (my $handler = delete $params{handler}) { |
|
688
|
346
|
|
|
|
|
1302
|
my $subclass = __PACKAGE__ . "::$handler"; |
|
689
|
346
|
50
|
|
|
|
1685
|
unless ($subclass eq $class) { |
|
690
|
346
|
50
|
|
|
|
35089
|
eval "require $subclass" or die $@; |
|
691
|
346
|
|
|
|
|
6913
|
return $subclass->new(%params); |
|
692
|
|
|
|
|
|
|
} |
|
693
|
|
|
|
|
|
|
} |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
# Load any filters. |
|
696
|
3060
|
|
100
|
|
|
57155
|
$params{filters} ||= {}; |
|
697
|
3060
|
100
|
|
|
|
31378
|
if (ref $params{filters} eq 'ARRAY') { |
|
698
|
716
|
|
|
|
|
1740
|
my $filts = {}; |
|
699
|
716
|
|
|
|
|
1182
|
for my $pkg ( @{ $params{filters} } ) { |
|
|
716
|
|
|
|
|
2213
|
|
|
700
|
778
|
100
|
|
|
|
5751
|
$pkg = "SVN::Notify::Filter::$pkg" if $pkg !~ /::/; |
|
701
|
778
|
100
|
|
|
|
4241
|
if ($filters{$pkg}) { |
|
702
|
308
|
|
|
|
|
645
|
while (my ($k, $v) = each %{ $filters{$pkg} }) { |
|
|
876
|
|
|
|
|
6088
|
|
|
703
|
568
|
|
50
|
|
|
4457
|
$filts->{$k} ||= []; |
|
704
|
568
|
|
|
|
|
989
|
push @{ $filts->{$k} }, $v; |
|
|
568
|
|
|
|
|
1813
|
|
|
705
|
|
|
|
|
|
|
} |
|
706
|
|
|
|
|
|
|
} else { |
|
707
|
470
|
50
|
|
|
|
50823
|
eval "require $pkg" or die $@; |
|
708
|
470
|
|
|
|
|
3425
|
$filters{$pkg} = {}; |
|
709
|
293
|
|
|
293
|
|
2007
|
no strict 'refs'; |
|
|
293
|
|
|
|
|
702
|
|
|
|
293
|
|
|
|
|
3292129
|
|
|
710
|
470
|
|
|
|
|
1163
|
while ( my ($k, $v) = each %{ "$pkg\::" } ) { |
|
|
1355
|
|
|
|
|
16128
|
|
|
711
|
885
|
100
|
|
|
|
1789
|
my $code = *{$v}{CODE} or next; |
|
|
885
|
|
|
|
|
6251
|
|
|
712
|
769
|
|
|
|
|
2604
|
$filters{$pkg}->{$k} = $code; |
|
713
|
769
|
|
100
|
|
|
14341
|
$filts->{$k} ||= []; |
|
714
|
769
|
|
|
|
|
2988
|
push @{ $filts->{$k} }, $code; |
|
|
769
|
|
|
|
|
2628
|
|
|
715
|
|
|
|
|
|
|
} |
|
716
|
|
|
|
|
|
|
} |
|
717
|
|
|
|
|
|
|
} |
|
718
|
716
|
|
|
|
|
2068
|
$params{filters} = $filts; |
|
719
|
|
|
|
|
|
|
} |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
# Make sure that the tos are an arrayref. |
|
722
|
3060
|
100
|
66
|
|
|
32942
|
$params{to} = [ $params{to} || () ] unless ref $params{to}; |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
# Check for required parameters. |
|
725
|
3060
|
100
|
|
|
|
18787
|
$class->_dbpnt( "Checking required parameters to new()") |
|
726
|
|
|
|
|
|
|
if $params{verbose}; |
|
727
|
3060
|
100
|
|
|
|
12014
|
_usage( qq{Missing required "repos_path" parameter} ) |
|
728
|
|
|
|
|
|
|
unless $params{repos_path}; |
|
729
|
3059
|
100
|
|
|
|
17689
|
_usage( qq{Missing required "revision" parameter} ) |
|
730
|
|
|
|
|
|
|
unless $params{revision}; |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# Set up default values. |
|
733
|
3058
|
|
0
|
|
|
20878
|
$params{svnlook} ||= $ENV{SVNLOOK} || $class->find_exe('svnlook'); |
|
|
|
|
33
|
|
|
|
|
|
734
|
3058
|
|
100
|
|
|
40671
|
$params{with_diff} ||= $params{attach_diff}; |
|
735
|
3058
|
|
100
|
|
|
37113
|
$params{verbose} ||= 0; |
|
736
|
3058
|
|
50
|
|
|
37711
|
$params{encoding} ||= $params{charset} || 'UTF-8'; |
|
|
|
|
66
|
|
|
|
|
|
737
|
3058
|
|
66
|
|
|
25409
|
$params{svn_encoding} ||= $params{encoding}; |
|
738
|
3058
|
|
66
|
|
|
29026
|
$params{diff_encoding} ||= $params{svn_encoding}; |
|
739
|
3058
|
|
50
|
|
|
111697
|
$params{diff_content_type} ||= $params{diff_content_type} || 'text/plain'; |
|
|
|
|
66
|
|
|
|
|
|
740
|
3058
|
100
|
0
|
|
|
16988
|
$params{sendmail} ||= $ENV{SENDMAIL} || $class->find_exe('sendmail') |
|
|
|
|
33
|
|
|
|
|
|
741
|
|
|
|
|
|
|
unless $params{smtp}; |
|
742
|
|
|
|
|
|
|
|
|
743
|
3058
|
50
|
66
|
|
|
11413
|
_usage( qq{Cannot find sendmail and no "smtp" parameter specified} ) |
|
744
|
|
|
|
|
|
|
unless $params{sendmail} || $params{smtp}; |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
# Set up the environment locale. |
|
747
|
3058
|
100
|
66
|
|
|
14663
|
if ( $params{language} && !$ENV{LANG} ) { |
|
748
|
210
|
|
|
|
|
1474
|
( my $lang_country = $params{language} ) =~ s/-/_/g; |
|
749
|
210
|
|
|
|
|
940
|
for my $p (qw(encoding svn_encoding)) { |
|
750
|
420
|
|
|
|
|
3880
|
my $encoding = $params{$p}; |
|
751
|
420
|
50
|
|
|
|
2138
|
$encoding =~ s/-//g if uc($encoding) ne 'UTF-8'; |
|
752
|
420
|
|
|
|
|
7236
|
(my $label = $p ) =~ s/(_?)encoding/$1/; |
|
753
|
420
|
|
|
|
|
2681
|
$params{"${label}env_lang"} = "$lang_country.$encoding"; |
|
754
|
|
|
|
|
|
|
} |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
# Set up the revision URL. |
|
758
|
3058
|
|
100
|
|
|
108427
|
$params{revision_url} ||= delete $params{svnweb_url} |
|
|
|
|
100
|
|
|
|
|
|
759
|
|
|
|
|
|
|
|| delete $params{viewcvs_url}; |
|
760
|
3058
|
50
|
66
|
|
|
18253
|
if ($params{revision_url} && $params{revision_url} !~ /%s/) { |
|
761
|
0
|
|
|
|
|
0
|
warn "--revision-url must have '%s' format\n"; |
|
762
|
0
|
|
|
|
|
0
|
$params{revision_url} .= '/revision/?rev=%s&view=rev' |
|
763
|
|
|
|
|
|
|
} |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# Set up the issue tracking links. |
|
766
|
3058
|
|
|
|
|
7970
|
my $track = $params{ticket_map}; |
|
767
|
3058
|
100
|
|
|
|
9123
|
if ($params{ticket_regex}) { |
|
768
|
77
|
|
|
|
|
555
|
$track->{ delete $params{ticket_regex} } = delete $params{ticket_url}; |
|
769
|
|
|
|
|
|
|
} |
|
770
|
|
|
|
|
|
|
|
|
771
|
3058
|
|
|
|
|
9357
|
for my $system (qw(rt bugzilla jira gnats)) { |
|
772
|
12232
|
|
|
|
|
25403
|
my $param = $system . '_url'; |
|
773
|
12232
|
100
|
|
|
|
60209
|
if ($params{ $param }) { |
|
774
|
283
|
|
|
|
|
1320
|
$track->{ $system } = delete $params{ $param }; |
|
775
|
283
|
50
|
|
|
|
2310
|
warn "--$system-url must have '%s' format\n" |
|
776
|
|
|
|
|
|
|
unless $track->{ $system } =~ /%s/; |
|
777
|
|
|
|
|
|
|
} |
|
778
|
|
|
|
|
|
|
} |
|
779
|
3058
|
100
|
|
|
|
9281
|
$params{ticket_map} = $track if $track; |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
# Make it so! |
|
782
|
3058
|
100
|
|
|
|
10973
|
$class->_dbpnt( "Instantiating $class object") if $params{verbose}; |
|
783
|
3058
|
|
|
|
|
39960
|
return bless \%params, $class; |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
############################################################################## |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=head2 Class Methods |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=head3 content_type |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
my $content_type = SVN::Notify->content_type; |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
Returns the content type of the notification message, "text/plain". Used to |
|
795
|
|
|
|
|
|
|
set the Content-Type header for the message. |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
=cut |
|
798
|
|
|
|
|
|
|
|
|
799
|
1617
|
|
|
1617
|
1
|
16076
|
sub content_type { 'text/plain' } |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
############################################################################## |
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=head3 register_attributes |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
SVN::Notify::Subclass->register_attributes( |
|
806
|
|
|
|
|
|
|
foo_attr => 'foo-attr=s', |
|
807
|
|
|
|
|
|
|
bar => 'bar', |
|
808
|
|
|
|
|
|
|
bat => undef, |
|
809
|
|
|
|
|
|
|
); |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
This class method is used by subclasses to register new attributes. Pass in a |
|
812
|
|
|
|
|
|
|
list of key/value pairs, where the keys are the attribute names and the values |
|
813
|
|
|
|
|
|
|
are option specifications in the format required by Getopt::Long. SVN::Notify |
|
814
|
|
|
|
|
|
|
will create accessors for each attribute, and if the corresponding value is |
|
815
|
|
|
|
|
|
|
defined, it will be used by the C class method to get a |
|
816
|
|
|
|
|
|
|
command-line option value. |
|
817
|
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
See for an example usage of |
|
819
|
|
|
|
|
|
|
C. |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=cut |
|
822
|
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
my %OPTS; |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
sub register_attributes { |
|
826
|
269
|
|
|
269
|
1
|
1033
|
my $class = shift; |
|
827
|
269
|
|
|
|
|
707
|
my @attrs; |
|
828
|
269
|
|
|
|
|
1732
|
while (@_) { |
|
829
|
665
|
|
|
|
|
4304
|
push @attrs, shift; |
|
830
|
665
|
50
|
|
|
|
4638
|
if (my $opt = shift) { |
|
831
|
665
|
|
|
|
|
3064
|
$OPTS{$attrs[-1]} = $opt; |
|
832
|
|
|
|
|
|
|
} |
|
833
|
|
|
|
|
|
|
} |
|
834
|
269
|
|
|
|
|
2847
|
$class->_accessors(@attrs); |
|
835
|
|
|
|
|
|
|
} |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
############################################################################## |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=head3 get_options |
|
840
|
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
my $options = SVN::Notify->get_options; |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
Parses the command-line options in C<@ARGV> to a hash reference suitable for |
|
844
|
|
|
|
|
|
|
passing as the parameters to C. See L<"new"> for a complete list of the |
|
845
|
|
|
|
|
|
|
supported parameters and their corresponding command-line options. |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
This method use Getopt::Long to parse C<@ARGV>. It then looks for any |
|
848
|
|
|
|
|
|
|
C and C options and, if it finds any, loads the appropriate |
|
849
|
|
|
|
|
|
|
classes and parses any options they requires from C<@ARGV>. Subclasses and |
|
850
|
|
|
|
|
|
|
filter classes should use C to register any attributes |
|
851
|
|
|
|
|
|
|
and options they require. |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
After that, on Perl 5.8 and later, it decodes all of the string option from |
|
854
|
|
|
|
|
|
|
the encoding specified by the C option or UTF-8. This allows options |
|
855
|
|
|
|
|
|
|
to be passed to SVN::Notify in that encoding and end up being displayed |
|
856
|
|
|
|
|
|
|
properly in the resulting notification message. |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=cut |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
sub get_options { |
|
861
|
4
|
|
|
4
|
1
|
281554
|
my $class = shift; |
|
862
|
4
|
|
|
|
|
15
|
my $opts = {}; |
|
863
|
4
|
|
|
|
|
970140
|
require Getopt::Long; |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
# Enable bundling and, at the same time, case-sensitive matching of |
|
866
|
|
|
|
|
|
|
# single character options. Also enable pass-through so that subclasses |
|
867
|
|
|
|
|
|
|
# can grab more options. |
|
868
|
4
|
|
|
|
|
32855
|
Getopt::Long::Configure (qw(bundling pass_through)); |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
# Get options. |
|
871
|
|
|
|
|
|
|
Getopt::Long::GetOptions( |
|
872
|
|
|
|
|
|
|
'repos-path|p=s' => \$opts->{repos_path}, |
|
873
|
|
|
|
|
|
|
'revision|r=s' => \$opts->{revision}, |
|
874
|
|
|
|
|
|
|
'to|t=s@' => \$opts->{to}, |
|
875
|
|
|
|
|
|
|
'to-regex-map|x=s%' => \$opts->{to_regex_map}, |
|
876
|
|
|
|
|
|
|
'to-email-map=s%' => \$opts->{to_email_map}, |
|
877
|
|
|
|
|
|
|
'from|f=s' => \$opts->{from}, |
|
878
|
|
|
|
|
|
|
'user-domain|D=s' => \$opts->{user_domain}, |
|
879
|
|
|
|
|
|
|
'svnlook|l=s' => \$opts->{svnlook}, |
|
880
|
|
|
|
|
|
|
'sendmail|s=s' => \$opts->{sendmail}, |
|
881
|
|
|
|
|
|
|
'set-sender|E' => \$opts->{set_sender}, |
|
882
|
|
|
|
|
|
|
'smtp=s' => \$opts->{smtp}, |
|
883
|
|
|
|
|
|
|
'smtp-port=i' => \$opts->{smtp_port}, |
|
884
|
|
|
|
|
|
|
'smtp-tls!' => \$opts->{smtp_tls}, |
|
885
|
|
|
|
|
|
|
'encoding|charset|c=s'=> \$opts->{encoding}, |
|
886
|
|
|
|
|
|
|
'diff-encoding=s' => \$opts->{diff_encoding}, |
|
887
|
|
|
|
|
|
|
'svn-encoding=s' => \$opts->{svn_encoding}, |
|
888
|
|
|
|
|
|
|
'language|g=s' => \$opts->{language}, |
|
889
|
|
|
|
|
|
|
'with-diff|d' => \$opts->{with_diff}, |
|
890
|
|
|
|
|
|
|
'attach-diff|a' => \$opts->{attach_diff}, |
|
891
|
|
|
|
|
|
|
'diff-switches|w=s' => \$opts->{diff_switches}, |
|
892
|
|
|
|
|
|
|
'diff-content-type=s' => \$opts->{diff_content_type}, |
|
893
|
|
|
|
|
|
|
'reply-to|R=s' => \$opts->{reply_to}, |
|
894
|
|
|
|
|
|
|
'subject-prefix|P=s' => \$opts->{subject_prefix}, |
|
895
|
|
|
|
|
|
|
'subject-cx|C' => \$opts->{subject_cx}, |
|
896
|
|
|
|
|
|
|
'strip-cx-regex|X=s@' => \$opts->{strip_cx_regex}, |
|
897
|
|
|
|
|
|
|
'no-first-line|O' => \$opts->{no_first_line}, |
|
898
|
|
|
|
|
|
|
'max-sub-length|i=i' => \$opts->{max_sub_length}, |
|
899
|
|
|
|
|
|
|
'max-diff-length|e=i' => \$opts->{max_diff_length}, |
|
900
|
|
|
|
|
|
|
'handler|H=s' => \$opts->{handler}, |
|
901
|
|
|
|
|
|
|
'filter|F=s@' => \$opts->{filters}, |
|
902
|
|
|
|
|
|
|
'author-url|A=s' => \$opts->{author_url}, |
|
903
|
|
|
|
|
|
|
'ticket-regex=s' => \$opts->{ticket_regex}, |
|
904
|
|
|
|
|
|
|
'ticket-map=s%' => \$opts->{ticket_map}, |
|
905
|
|
|
|
|
|
|
'verbose|V+' => \$opts->{verbose}, |
|
906
|
|
|
|
|
|
|
'help|h' => \$opts->{help}, |
|
907
|
|
|
|
|
|
|
'man|m' => \$opts->{man}, |
|
908
|
|
|
|
|
|
|
'version|v' => \$opts->{version}, |
|
909
|
|
|
|
|
|
|
'header=s' => \$opts->{header}, |
|
910
|
|
|
|
|
|
|
'footer=s' => \$opts->{footer}, |
|
911
|
|
|
|
|
|
|
'smtp-user=s' => \$opts->{smtp_user}, |
|
912
|
|
|
|
|
|
|
'smtp-pass=s' => \$opts->{smtp_pass}, |
|
913
|
|
|
|
|
|
|
'smtp-authtype=s' => \$opts->{smtp_authtype}, |
|
914
|
|
|
|
|
|
|
'add-header=s%' => sub { |
|
915
|
6
|
|
|
6
|
|
49471
|
shift; push @{ $opts->{add_headers}{+shift} }, shift |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
46
|
|
|
916
|
|
|
|
|
|
|
}, |
|
917
|
4
|
50
|
|
|
|
2480
|
'revision-url|U|svnweb-url|S|viewcvs-url=s' => \$opts->{revision_url}, |
|
918
|
|
|
|
|
|
|
'rt-url|T|bugzilla-url|B|jira-url|J|gnats-url|G|ticket-url=s' |
|
919
|
|
|
|
|
|
|
=> \$opts->{ticket_url}, |
|
920
|
|
|
|
|
|
|
) or return; |
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
# Load a subclass if one has been specified. |
|
923
|
4
|
100
|
|
|
|
5427
|
if (my $hand = $opts->{handler}) { |
|
924
|
1
|
50
|
|
|
|
149
|
eval "require " . __PACKAGE__ . "::$hand" or die $@; |
|
925
|
1
|
50
|
|
|
|
9
|
if ($hand eq 'Alternative') { |
|
926
|
|
|
|
|
|
|
# Load the alternative subclasses. |
|
927
|
0
|
|
|
|
|
0
|
Getopt::Long::GetOptions( |
|
928
|
0
|
|
|
|
|
0
|
map { delete $OPTS{$_} => \$opts->{$_} } keys %OPTS |
|
929
|
|
|
|
|
|
|
); |
|
930
|
0
|
0
|
|
|
|
0
|
for my $alt (@{ $opts->{alternatives} || ['HTML']}) { |
|
|
0
|
|
|
|
|
0
|
|
|
931
|
0
|
0
|
|
|
|
0
|
eval "require " . __PACKAGE__ . "::$alt" or die $@; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
} |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
# Load any filters. |
|
937
|
4
|
100
|
|
|
|
23
|
if ($opts->{filters}) { |
|
938
|
1
|
|
|
|
|
2
|
for my $pkg ( @{ $opts->{filters} } ) { |
|
|
1
|
|
|
|
|
6
|
|
|
939
|
1
|
50
|
|
|
|
6
|
$pkg = "SVN::Notify::Filter::$pkg" if $pkg !~ /::/; |
|
940
|
1
|
50
|
|
|
|
90
|
eval "require $pkg" or die $@; |
|
941
|
|
|
|
|
|
|
} |
|
942
|
|
|
|
|
|
|
} |
|
943
|
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
# Disallow pass-through so that any invalid options will now fail. |
|
945
|
4
|
|
|
|
|
19
|
Getopt::Long::Configure (qw(no_pass_through)); |
|
946
|
4
|
|
|
|
|
198
|
my @to_decode; |
|
947
|
4
|
100
|
|
|
|
18
|
if (%OPTS) { |
|
948
|
|
|
|
|
|
|
# Get a list of string options we'll need to decode. |
|
949
|
2
|
|
|
|
|
10
|
@to_decode = map { $OPTS{$_} } grep { /=s$/ } keys %OPTS |
|
|
0
|
|
|
|
|
0
|
|
|
|
4
|
|
|
|
|
13
|
|
|
950
|
|
|
|
|
|
|
if PERL58; |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
# Load any other options. |
|
953
|
4
|
|
|
|
|
21
|
Getopt::Long::GetOptions( |
|
954
|
2
|
|
|
|
|
7
|
map { delete $OPTS{$_} => \$opts->{$_} } keys %OPTS |
|
955
|
|
|
|
|
|
|
); |
|
956
|
|
|
|
|
|
|
} else { |
|
957
|
|
|
|
|
|
|
# Call GetOptions() again so that invalid options will be properly |
|
958
|
|
|
|
|
|
|
# caught. |
|
959
|
2
|
|
|
|
|
9
|
Getopt::Long::GetOptions(); |
|
960
|
|
|
|
|
|
|
} |
|
961
|
|
|
|
|
|
|
|
|
962
|
4
|
|
|
|
|
1168
|
if (PERL58) { |
|
963
|
|
|
|
|
|
|
# Decode all string options. |
|
964
|
4
|
|
50
|
|
|
61
|
my $encoding = $opts->{encoding} || 'UTF-8'; |
|
965
|
4
|
|
|
|
|
16
|
for my $opt ( qw( |
|
966
|
|
|
|
|
|
|
repos_path |
|
967
|
|
|
|
|
|
|
revision |
|
968
|
|
|
|
|
|
|
from |
|
969
|
|
|
|
|
|
|
user_domain |
|
970
|
|
|
|
|
|
|
svnlook |
|
971
|
|
|
|
|
|
|
sendmail |
|
972
|
|
|
|
|
|
|
smtp |
|
973
|
|
|
|
|
|
|
smtp_tls |
|
974
|
|
|
|
|
|
|
smtp_port |
|
975
|
|
|
|
|
|
|
diff_switches |
|
976
|
|
|
|
|
|
|
reply_to |
|
977
|
|
|
|
|
|
|
subject_prefix |
|
978
|
|
|
|
|
|
|
handler |
|
979
|
|
|
|
|
|
|
author_url |
|
980
|
|
|
|
|
|
|
ticket_regex |
|
981
|
|
|
|
|
|
|
header |
|
982
|
|
|
|
|
|
|
footer |
|
983
|
|
|
|
|
|
|
smtp_user |
|
984
|
|
|
|
|
|
|
smtp_pass |
|
985
|
|
|
|
|
|
|
revision_url |
|
986
|
|
|
|
|
|
|
ticket_url |
|
987
|
|
|
|
|
|
|
), @to_decode ) { |
|
988
|
84
|
100
|
|
|
|
7469
|
$opts->{$opt} = Encode::decode( $encoding, $opts->{$opt} ) |
|
989
|
|
|
|
|
|
|
if $opts->{$opt}; |
|
990
|
|
|
|
|
|
|
} |
|
991
|
|
|
|
|
|
|
} |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
# Clear the extra options specifications and return. |
|
994
|
4
|
|
|
|
|
40
|
%OPTS = (); |
|
995
|
4
|
|
|
|
|
34
|
return $opts; |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
############################################################################## |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
=head3 file_label_map |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
my $map = SVN::Notify->file_label_map; |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
Returns a hash reference of the labels to be used for the lists of files. A |
|
1005
|
|
|
|
|
|
|
hash reference of file lists is stored in the C attribute after |
|
1006
|
|
|
|
|
|
|
C has been called. The hash keys in that list correspond to |
|
1007
|
|
|
|
|
|
|
Subversion status codes, and these are mapped to their appropriate labels by |
|
1008
|
|
|
|
|
|
|
the hash reference returned by this method: |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
{ U => 'Modified Paths', |
|
1011
|
|
|
|
|
|
|
A => 'Added Paths', |
|
1012
|
|
|
|
|
|
|
D => 'Removed Paths', |
|
1013
|
|
|
|
|
|
|
_ => 'Property Changed' |
|
1014
|
|
|
|
|
|
|
} |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
=cut |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
2662
|
|
|
2662
|
1
|
20896
|
sub file_label_map { \%map } |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
############################################################################## |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=head3 find_exe |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
my $exe = SVN::Notify->find_exe($exe_name); |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
This method searches through the system path, as well as the extra directories |
|
1027
|
|
|
|
|
|
|
F and F (because they're common paths for |
|
1028
|
|
|
|
|
|
|
C and C for an executable file with the name C<$exe_name>. |
|
1029
|
|
|
|
|
|
|
The first one it finds is returned with its full path. If none is found, |
|
1030
|
|
|
|
|
|
|
C returns undef. |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
=cut |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
sub find_exe { |
|
1035
|
1
|
|
|
1
|
1
|
5
|
my ($class, $exe) = @_; |
|
1036
|
1
|
|
|
|
|
9
|
$exe .= '.exe' if WIN32; |
|
1037
|
1
|
|
|
|
|
19
|
require File::Spec; |
|
1038
|
1
|
|
|
|
|
9
|
require Config; |
|
1039
|
1
|
|
|
|
|
22
|
for my $path ( |
|
1040
|
|
|
|
|
|
|
File::Spec->path, |
|
1041
|
|
|
|
|
|
|
qw(/usr/local/bin /usr/bin /usr/sbin), |
|
1042
|
|
|
|
|
|
|
'C:\\program files\\subversion\\bin', |
|
1043
|
|
|
|
|
|
|
$Config::Config{installbin}, |
|
1044
|
|
|
|
|
|
|
$Config::Config{installscript}, |
|
1045
|
|
|
|
|
|
|
) { |
|
1046
|
3
|
|
|
|
|
78
|
my $file = File::Spec->catfile($path, $exe); |
|
1047
|
3
|
100
|
66
|
|
|
89
|
return $file if -f $file && -x _; |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
0
|
|
|
|
|
0
|
return; |
|
1050
|
|
|
|
|
|
|
} |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
############################################################################## |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
=head1 Instance Interface |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
=head2 Instance Methods |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
=head3 prepare |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$notifier->prepare; |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
Prepares the SVN::Notify object, collecting all the data it needs in |
|
1063
|
|
|
|
|
|
|
preparation for sending the notification email. Really it's just a shortcut |
|
1064
|
|
|
|
|
|
|
for: |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
$notifier->prepare_recipients; |
|
1067
|
|
|
|
|
|
|
$notifier->prepare_contents; |
|
1068
|
|
|
|
|
|
|
$notifier->prepare_files; |
|
1069
|
|
|
|
|
|
|
$notifier->prepare_subject; |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
Only it returns after the call to C if there are no |
|
1072
|
|
|
|
|
|
|
recipients (that is, as when recipients are specified solely by the |
|
1073
|
|
|
|
|
|
|
C or C parameter and none of the regular |
|
1074
|
|
|
|
|
|
|
expressions match any of the affected directories). |
|
1075
|
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
=cut |
|
1077
|
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
sub prepare { |
|
1079
|
2714
|
|
|
2714
|
1
|
14866
|
my $self = shift; |
|
1080
|
2714
|
|
|
|
|
19919
|
$self->run_filters('pre_prepare'); |
|
1081
|
2714
|
|
|
|
|
15460
|
_usage( |
|
1082
|
|
|
|
|
|
|
qq{Missing required "to", "to_regex_map", or "to_email_map" parameter} |
|
1083
|
2714
|
50
|
66
|
|
|
4678
|
) unless @{$self->{to}} || $self->{to_regex_map} || $self->{to_email_map}; |
|
|
|
|
66
|
|
|
|
|
|
1084
|
2713
|
|
|
|
|
20591
|
$self->prepare_recipients; |
|
1085
|
2707
|
50
|
|
|
|
4575
|
return $self unless @{ $self->{to} }; |
|
|
2707
|
|
|
|
|
16577
|
|
|
1086
|
2707
|
|
|
|
|
16935
|
$self->prepare_contents; |
|
1087
|
2624
|
|
|
|
|
39115
|
$self->prepare_files; |
|
1088
|
2541
|
|
|
|
|
45926
|
$self->prepare_subject; |
|
1089
|
2541
|
|
|
|
|
11012
|
$self->run_filters('post_prepare'); |
|
1090
|
2541
|
|
|
|
|
93667
|
return $self; |
|
1091
|
|
|
|
|
|
|
} |
|
1092
|
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
############################################################################## |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
=head3 prepare_recipients |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
$notifier->prepare_recipients; |
|
1098
|
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
Collects and prepares a list of the notification recipients. The recipients |
|
1100
|
|
|
|
|
|
|
are a combination of the value passed to the C parameter as well as any |
|
1101
|
|
|
|
|
|
|
email addresses specified as keys in the hash reference passed C |
|
1102
|
|
|
|
|
|
|
parameter or values passed to the C parameter, where the |
|
1103
|
|
|
|
|
|
|
corresponding regular expressions stored in the hash matches one or more of |
|
1104
|
|
|
|
|
|
|
the names of the directories affected by the commit. |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
If the F parameter to C has a true value, |
|
1107
|
|
|
|
|
|
|
C also determines the directory name to use for the |
|
1108
|
|
|
|
|
|
|
context. |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=cut |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
sub prepare_recipients { |
|
1113
|
2799
|
|
|
2799
|
1
|
5988
|
my $self = shift; |
|
1114
|
2799
|
100
|
|
|
|
10541
|
$self->_dbpnt( "Preparing recipients list") if $self->{verbose}; |
|
1115
|
2799
|
100
|
100
|
|
|
47706
|
unless ( |
|
|
|
|
100
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
$self->{to_regex_map} |
|
1117
|
|
|
|
|
|
|
|| $self->{subject_cx} |
|
1118
|
|
|
|
|
|
|
|| $self->{to_email_map} |
|
1119
|
|
|
|
|
|
|
) { |
|
1120
|
2493
|
|
|
|
|
9181
|
$self->{to} = $self->run_filters( recipients => $self->{to} ); |
|
1121
|
2493
|
|
|
|
|
45468
|
return $self; |
|
1122
|
|
|
|
|
|
|
} |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
# Prevent duplication. |
|
1125
|
306
|
|
|
|
|
1101
|
my $tos = $self->{to} = [ @{ $self->{to} } ]; |
|
|
306
|
|
|
|
|
2126
|
|
|
1126
|
|
|
|
|
|
|
|
|
1127
|
0
|
|
|
|
|
0
|
my $regexen = $self->{to_regex_map} && $self->{to_email_map} |
|
1128
|
0
|
|
|
|
|
0
|
? [ %{ $self->{to_regex_map} }, reverse %{ $self->{to_email_map } } ] |
|
|
75
|
|
|
|
|
600
|
|
|
1129
|
|
|
|
|
|
|
: $self->{to_regex_map} ? [ %{ $self->{to_regex_map} } ] |
|
1130
|
306
|
100
|
66
|
|
|
7206
|
: $self->{to_email_map} ? [ reverse %{ $self->{to_email_map } } ] |
|
|
71
|
100
|
|
|
|
355
|
|
|
|
|
50
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
: undef; |
|
1132
|
|
|
|
|
|
|
|
|
1133
|
306
|
100
|
|
|
|
1219
|
if ($regexen) { |
|
1134
|
146
|
50
|
|
|
|
655
|
$self->_dbpnt( "Compiling regex_map regular expressions") |
|
1135
|
|
|
|
|
|
|
if $self->{verbose} > 1; |
|
1136
|
146
|
|
|
|
|
809
|
for (my $i = 1; $i < @$regexen; $i += 2) { |
|
1137
|
438
|
50
|
|
|
|
1105
|
$self->_dbpnt( qq{Compiling "$_"}) if $self->{verbose} > 2; |
|
1138
|
|
|
|
|
|
|
# Remove initial slash and compile. |
|
1139
|
438
|
|
|
|
|
1823
|
$regexen->[$i] =~ s|^\^[/\\]|^|; |
|
1140
|
438
|
|
|
|
|
8129
|
$regexen->[$i] = qr/$regexen->[$i]/; |
|
1141
|
|
|
|
|
|
|
} |
|
1142
|
|
|
|
|
|
|
} else { |
|
1143
|
160
|
|
|
|
|
648
|
$regexen = []; |
|
1144
|
|
|
|
|
|
|
} |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
306
|
50
|
|
|
|
1303
|
local $ENV{LANG} = "$self->{svn_env_lang}" if $self->{svn_env_lang}; |
|
1147
|
306
|
|
|
|
|
1737
|
my $fh = $self->_pipe( |
|
1148
|
|
|
|
|
|
|
$self->{svn_encoding}, |
|
1149
|
|
|
|
|
|
|
'-|', $self->{svnlook}, |
|
1150
|
|
|
|
|
|
|
'changed', |
|
1151
|
|
|
|
|
|
|
$self->{repos_path}, |
|
1152
|
|
|
|
|
|
|
'-r', $self->{revision}, |
|
1153
|
|
|
|
|
|
|
); |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
# Read in a list of the files changed. |
|
1156
|
300
|
|
|
|
|
3968
|
my ($cx, %seen); |
|
1157
|
300
|
|
|
|
|
617674823
|
while (<$fh>) { |
|
1158
|
4993
|
|
|
|
|
46677
|
s/^.\s*//; |
|
1159
|
4993
|
|
|
|
|
77703
|
s/[\n\r\/\\]+$//; |
|
1160
|
4993
|
|
|
|
|
17178
|
for (my $i = 0; $i < @$regexen; $i += 2) { |
|
1161
|
8640
|
|
|
|
|
14936
|
my ($email, $rx) = @{$regexen}[$i, $i + 1]; |
|
|
8640
|
|
|
|
|
13216
|
|
|
1162
|
|
|
|
|
|
|
# If the file matches the regex, save the email. |
|
1163
|
8640
|
100
|
|
|
|
58034
|
if (/$rx/) { |
|
1164
|
2448
|
50
|
|
|
|
5526
|
$self->_dbpnt( qq{"$_" matched $rx}) if $self->{verbose} > 2; |
|
1165
|
2448
|
100
|
|
|
|
10628
|
push @$tos, $email unless $seen{$email}++; |
|
1166
|
|
|
|
|
|
|
} |
|
1167
|
|
|
|
|
|
|
} |
|
1168
|
|
|
|
|
|
|
# Grab the context if it's needed for the subject. |
|
1169
|
4993
|
100
|
|
|
|
102957
|
if ($self->{subject_cx}) { |
|
1170
|
|
|
|
|
|
|
# XXX Do we need to set utf8 here? |
|
1171
|
2113
|
|
|
|
|
5356
|
my $l = length; |
|
1172
|
2113
|
|
66
|
|
|
53390
|
$cx ||= $_; |
|
1173
|
2113
|
|
100
|
|
|
242862
|
$cx =~ s{[/\\]?[^/\\]+$}{} until !$cx || m{^\Q$cx\E(?:$|/|\\)}; |
|
1174
|
|
|
|
|
|
|
} |
|
1175
|
|
|
|
|
|
|
} |
|
1176
|
300
|
50
|
66
|
|
|
6649
|
$self->_dbpnt( qq{Context is "$cx"}) |
|
1177
|
|
|
|
|
|
|
if $self->{subject_cx} && $self->{verbose} > 1; |
|
1178
|
300
|
50
|
|
|
|
26164
|
close $fh or warn "Child process exited: $?\n"; |
|
1179
|
300
|
|
|
|
|
3094
|
$self->{cx} = $cx; |
|
1180
|
300
|
|
|
|
|
5205
|
$tos = $self->run_filters( recipients => $tos ); |
|
1181
|
300
|
50
|
|
|
|
1430
|
$self->_dbpnt( 'Recipients: "', join(', ', @$tos), '"') |
|
1182
|
|
|
|
|
|
|
if $self->{verbose} > 1; |
|
1183
|
300
|
|
|
|
|
7073
|
return $self; |
|
1184
|
|
|
|
|
|
|
} |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
############################################################################## |
|
1187
|
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
=head3 prepare_contents |
|
1189
|
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
$notifier->prepare_contents; |
|
1191
|
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
Prepares the contents of the commit message, including the name of the user |
|
1193
|
|
|
|
|
|
|
who triggered the commit (and therefore the contents of the "From" header to |
|
1194
|
|
|
|
|
|
|
be used in the email) and the log message. |
|
1195
|
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
=cut |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
sub prepare_contents { |
|
1199
|
2793
|
|
|
2793
|
1
|
6226
|
my $self = shift; |
|
1200
|
2793
|
100
|
|
|
|
9356
|
$self->_dbpnt( "Preparing contents") if $self->{verbose}; |
|
1201
|
2793
|
100
|
|
|
|
36863
|
local $ENV{LANG} = "$self->{svn_env_lang}" if $self->{svn_env_lang}; |
|
1202
|
2793
|
|
|
|
|
22170
|
my $lines = $self->_read_pipe($self->{svnlook}, 'info', $self->{repos_path}, |
|
1203
|
|
|
|
|
|
|
'-r', $self->{revision}); |
|
1204
|
2709
|
|
|
|
|
27896
|
$self->{user} = shift @$lines; |
|
1205
|
2709
|
|
|
|
|
20950
|
$self->{date} = shift @$lines; |
|
1206
|
2709
|
|
|
|
|
21068
|
$self->{message_size} = shift @$lines; |
|
1207
|
2709
|
|
|
|
|
12979
|
$self->{message} = $lines; |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# Set up the from address. |
|
1210
|
2709
|
50
|
|
|
|
13229
|
unless ($self->{from}) { |
|
1211
|
2709
|
100
|
|
|
|
57376
|
$self->{from} = $self->{user} |
|
1212
|
|
|
|
|
|
|
. ( $self->{user_domain} ? "\@$self->{user_domain}" : '' ); |
|
1213
|
|
|
|
|
|
|
} |
|
1214
|
2709
|
|
|
|
|
234845
|
$self->{from} = $self->run_filters( from => $self->{from} ); |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
2709
|
100
|
|
|
|
17675
|
if ($self->{verbose} > 1) { |
|
1217
|
2
|
|
|
|
|
148
|
$self->_dbpnt( "From: $self->{from}"); |
|
1218
|
2
|
|
|
|
|
40
|
$self->_dbpnt( "Message: @$lines"); |
|
1219
|
|
|
|
|
|
|
} |
|
1220
|
2709
|
|
|
|
|
30084
|
return $self; |
|
1221
|
|
|
|
|
|
|
} |
|
1222
|
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
############################################################################## |
|
1224
|
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
=head3 prepare_files |
|
1226
|
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
$notifier->prepare_files; |
|
1228
|
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
Prepares the lists of files affected by the commit, sorting them into their |
|
1230
|
|
|
|
|
|
|
categories: modified files, added files, and deleted files. It also compiles a |
|
1231
|
|
|
|
|
|
|
list of files wherein a property was set, which might have some overlap with |
|
1232
|
|
|
|
|
|
|
the list of modified files (if a single commit both modified a file and set a |
|
1233
|
|
|
|
|
|
|
property on it). |
|
1234
|
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
If the C parameter was specified and a single file was affected by |
|
1236
|
|
|
|
|
|
|
the commit, then C will also specify that file name as the |
|
1237
|
|
|
|
|
|
|
context to be used in the subject line of the commit email. |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
=cut |
|
1240
|
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
sub prepare_files { |
|
1242
|
2709
|
|
|
2709
|
1
|
9659
|
my $self = shift; |
|
1243
|
2709
|
100
|
|
|
|
28021
|
$self->_dbpnt( "Preparing file lists") if $self->{verbose}; |
|
1244
|
2709
|
|
|
|
|
5820
|
my %files; |
|
1245
|
2709
|
100
|
|
|
|
12759
|
local $ENV{LANG} = "$self->{svn_env_lang}" if $self->{svn_env_lang}; |
|
1246
|
2709
|
|
|
|
|
27996
|
my $fh = $self->_pipe( |
|
1247
|
|
|
|
|
|
|
$self->{svn_encoding}, |
|
1248
|
|
|
|
|
|
|
'-|', $self->{svnlook}, |
|
1249
|
|
|
|
|
|
|
'changed', |
|
1250
|
|
|
|
|
|
|
$self->{repos_path}, |
|
1251
|
|
|
|
|
|
|
'-r', $self->{revision}, |
|
1252
|
|
|
|
|
|
|
); |
|
1253
|
|
|
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
# Read in a list of changed files. |
|
1255
|
2625
|
|
|
|
|
8731877530
|
my $cx = $_ = <$fh>; |
|
1256
|
2625
|
|
|
|
|
152398
|
do { |
|
1257
|
46761
|
|
|
|
|
991677
|
s/[\n\r]+$//; |
|
1258
|
46761
|
50
|
|
|
|
567185
|
if (s/^(.)(.)\s+//) { |
|
1259
|
46761
|
50
|
|
|
|
118886
|
$self->_dbpnt( "$1,$2 => $_") if $self->{verbose} > 2; |
|
1260
|
46761
|
|
|
|
|
59179
|
push @{$files{$1}}, $_; |
|
|
46761
|
|
|
|
|
321105
|
|
|
1261
|
46761
|
100
|
100
|
|
|
2482699
|
push @{$files{_}}, $_ if $2 ne ' ' && $1 ne '_'; |
|
|
2404
|
|
|
|
|
25526
|
|
|
1262
|
|
|
|
|
|
|
} |
|
1263
|
|
|
|
|
|
|
} while (<$fh>); |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
2625
|
100
|
100
|
|
|
24379
|
if ($self->{subject_cx} && $. == 1) { |
|
1266
|
|
|
|
|
|
|
# There's only one file; it's the context. |
|
1267
|
51
|
|
|
|
|
1683
|
$cx =~ s/[\n\r]+$//; |
|
1268
|
51
|
|
|
|
|
1887
|
($self->{cx} = $cx) =~ s/^..\s+//; |
|
1269
|
51
|
50
|
|
|
|
765
|
$self->_dbpnt( qq{File context is "$self->{cx}"}) |
|
1270
|
|
|
|
|
|
|
if $self->{verbose} > 1; |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
# Wait till we get here to close the file handle, otherwise $. gets reset |
|
1273
|
|
|
|
|
|
|
# to 0! |
|
1274
|
2625
|
50
|
|
|
|
949447
|
close $fh or warn "Child process exited: $?\n"; |
|
1275
|
2625
|
|
|
|
|
34829
|
$self->{files} = \%files; |
|
1276
|
2625
|
|
|
|
|
58141
|
return $self; |
|
1277
|
|
|
|
|
|
|
} |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
############################################################################## |
|
1280
|
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
=head3 prepare_subject |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
$notifier->prepare_subject; |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
Prepares the subject line for the notification email. This method B be |
|
1286
|
|
|
|
|
|
|
called after C and C, since each of |
|
1287
|
|
|
|
|
|
|
those methods potentially sets up the context for use in the the subject |
|
1288
|
|
|
|
|
|
|
line. The subject may have a prefix defined by the C parameter |
|
1289
|
|
|
|
|
|
|
to C, it has the revision number, it might have the context if the |
|
1290
|
|
|
|
|
|
|
C specified a true value, and it will have the first sentence or |
|
1291
|
|
|
|
|
|
|
line of the commit, whichever is shorter. The subject may then be truncated to |
|
1292
|
|
|
|
|
|
|
the maximum length specified by the C parameter. |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
=cut |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
sub prepare_subject { |
|
1297
|
2625
|
|
|
2625
|
1
|
9539
|
my $self = shift; |
|
1298
|
2625
|
100
|
|
|
|
13100
|
$self->_dbpnt( "Preparing subject") if $self->{verbose}; |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
2625
|
|
|
|
|
20356
|
$self->{subject} = ''; |
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
# Start with the optional message and revision number.. |
|
1303
|
2625
|
100
|
|
|
|
13785
|
if ( defined $self->{subject_prefix} ) { |
|
1304
|
127
|
100
|
|
|
|
12432
|
if ( index($self->{subject_prefix}, '%d') > 0 ) { |
|
1305
|
59
|
|
|
|
|
3186
|
$self->{subject} .= |
|
1306
|
|
|
|
|
|
|
sprintf $self->{subject_prefix}, $self->{revision}; |
|
1307
|
|
|
|
|
|
|
} else { |
|
1308
|
68
|
|
|
|
|
870
|
$self->{subject} .= |
|
1309
|
|
|
|
|
|
|
$self->{subject_prefix} . "[$self->{revision}] "; |
|
1310
|
|
|
|
|
|
|
} |
|
1311
|
|
|
|
|
|
|
} else { |
|
1312
|
2498
|
|
|
|
|
18751
|
$self->{subject} .= "[$self->{revision}] "; |
|
1313
|
|
|
|
|
|
|
} |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
# Add the context if there is one. |
|
1316
|
2625
|
100
|
|
|
|
13276
|
if ($self->{cx}) { |
|
1317
|
148
|
100
|
|
|
|
1439
|
if (my $rx = $self->{strip_cx_regex}) { |
|
1318
|
42
|
|
|
|
|
4378
|
$self->{cx} =~ s/$_// for @$rx; |
|
1319
|
|
|
|
|
|
|
} |
|
1320
|
148
|
100
|
|
|
|
2219
|
my $space = $self->{no_first_line} ? '' : ': '; |
|
1321
|
148
|
50
|
|
|
|
1226
|
$self->{subject} .= $self->{cx} . $space if $self->{cx}; |
|
1322
|
|
|
|
|
|
|
} |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
# Add the first sentence/line from the log message. |
|
1325
|
2625
|
100
|
|
|
|
10962
|
unless ($self->{no_first_line}) { |
|
1326
|
|
|
|
|
|
|
# Truncate to first period after a minimum of 10 characters. |
|
1327
|
2583
|
|
|
|
|
21576
|
my $min = length $self->{message}[0]; |
|
1328
|
2583
|
50
|
|
|
|
13427
|
$min = 10 if $min > 10; |
|
1329
|
2583
|
|
|
|
|
37977
|
my $i = index substr($self->{message}[0], $min), '. '; |
|
1330
|
2583
|
100
|
|
|
|
24658
|
$self->{subject} .= $i > 0 |
|
1331
|
|
|
|
|
|
|
? substr($self->{message}[0], 0, $i + 11) |
|
1332
|
|
|
|
|
|
|
: $self->{message}[0]; |
|
1333
|
|
|
|
|
|
|
} |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
# Truncate to the last word under 72 characters. |
|
1336
|
2625
|
100
|
66
|
|
|
15687
|
$self->{subject} =~ s/^(.{0,$self->{max_sub_length}})\s+.*$/$1/m |
|
1337
|
|
|
|
|
|
|
if $self->{max_sub_length} |
|
1338
|
|
|
|
|
|
|
&& length $self->{subject} > $self->{max_sub_length}; |
|
1339
|
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# Now filter it. |
|
1341
|
2625
|
|
|
|
|
42003
|
$self->{subject} = $self->run_filters( subject => $self->{subject} ); |
|
1342
|
2625
|
100
|
|
|
|
9946
|
$self->_dbpnt( qq{Subject is "$self->{subject}"}) if $self->{verbose}; |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
2625
|
|
|
|
|
5654
|
return $self; |
|
1345
|
|
|
|
|
|
|
} |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
############################################################################## |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
=head3 execute |
|
1350
|
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
$notifier->execute; |
|
1352
|
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
Sends the notification message. This involves opening a file handle to |
|
1354
|
|
|
|
|
|
|
F or a tied file handle connected to an SMTP server and passing it |
|
1355
|
|
|
|
|
|
|
to C |
|
1356
|
|
|
|
|
|
|
any other actions in response to Subversion activity. |
|
1357
|
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
=cut |
|
1359
|
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
sub execute { |
|
1361
|
2625
|
|
|
2625
|
1
|
13558
|
my $self = shift; |
|
1362
|
2625
|
100
|
|
|
|
11244
|
$self->_dbpnt( "Sending message") if $self->{verbose}; |
|
1363
|
2625
|
|
|
|
|
9532
|
$self->run_filters('pre_execute'); |
|
1364
|
2625
|
50
|
|
|
|
6018
|
return $self unless @{ $self->{to} }; |
|
|
2625
|
|
|
|
|
15708
|
|
|
1365
|
|
|
|
|
|
|
|
|
1366
|
2625
|
100
|
|
|
|
10710
|
my $out = $self->{smtp} ? SVN::Notify::SMTP->get_handle($self) : do { |
|
1367
|
2621
|
100
|
|
|
|
10135
|
local $ENV{LANG} = $self->{env_lang} if $self->{env_lang}; |
|
1368
|
2621
|
50
|
|
|
|
24332
|
$self->_pipe( |
|
1369
|
|
|
|
|
|
|
$self->{encoding}, |
|
1370
|
|
|
|
|
|
|
'|-', $self->{sendmail}, |
|
1371
|
|
|
|
|
|
|
'-oi', '-t', |
|
1372
|
|
|
|
|
|
|
($self->{set_sender} ? ('-f', $self->{from}) : ()) |
|
1373
|
|
|
|
|
|
|
); |
|
1374
|
|
|
|
|
|
|
}; |
|
1375
|
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
# Output the message. |
|
1377
|
2543
|
|
|
|
|
488863
|
$self->output($out); |
|
1378
|
|
|
|
|
|
|
|
|
1379
|
2514
|
50
|
|
|
|
6776161588
|
close $out or warn "Child process exited: $?\n"; |
|
1380
|
2514
|
100
|
|
|
|
42711
|
$self->_dbpnt( 'Message sent' ) if $self->{verbose}; |
|
1381
|
2514
|
|
|
|
|
23909
|
$self->run_filters('post_execute'); |
|
1382
|
2514
|
|
|
|
|
201803
|
return $self; |
|
1383
|
|
|
|
|
|
|
} |
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
############################################################################## |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
=head3 output |
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
$notifier->output($file_handle); |
|
1390
|
|
|
|
|
|
|
$notifier->output($file_handle, $no_headers); |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
Called internally by C to output a complete email message. The file |
|
1393
|
|
|
|
|
|
|
a file handle, so that C |
|
1394
|
|
|
|
|
|
|
to the email message. The optional second argument, if true, will suppress the |
|
1395
|
|
|
|
|
|
|
output of the email headers. |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
Really C |
|
1398
|
|
|
|
|
|
|
It is thus essentially a shortcut for: |
|
1399
|
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
$notifier->output_headers($out) unless $no_headers; |
|
1401
|
|
|
|
|
|
|
$notifier->output_content_type($out); |
|
1402
|
|
|
|
|
|
|
$notifier->start_body($out); |
|
1403
|
|
|
|
|
|
|
$notifier->output_metadata($out); |
|
1404
|
|
|
|
|
|
|
$notifier->output_log_message($out); |
|
1405
|
|
|
|
|
|
|
$notifier->output_file_lists($out); |
|
1406
|
|
|
|
|
|
|
if ($notifier->with_diff) { |
|
1407
|
|
|
|
|
|
|
my $diff_handle = $self->diff_handle; |
|
1408
|
|
|
|
|
|
|
if ($notifier->attach_diff) { |
|
1409
|
|
|
|
|
|
|
$notifier->end_body($out); |
|
1410
|
|
|
|
|
|
|
$notifier->output_attached_diff($out, $diff_handle); |
|
1411
|
|
|
|
|
|
|
} else { |
|
1412
|
|
|
|
|
|
|
$notifier->output_diff($out, $diff_handle); |
|
1413
|
|
|
|
|
|
|
$notifier->end_body($out); |
|
1414
|
|
|
|
|
|
|
} |
|
1415
|
|
|
|
|
|
|
} else { |
|
1416
|
|
|
|
|
|
|
$notifier->end_body($out); |
|
1417
|
|
|
|
|
|
|
} |
|
1418
|
|
|
|
|
|
|
$notifier->end_message($out); |
|
1419
|
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
=cut |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
sub output { |
|
1423
|
2662
|
|
|
2662
|
1
|
19901
|
my ($self, $out, $no_headers) = @_; |
|
1424
|
2662
|
100
|
|
|
|
21156
|
$self->_dbpnt( "Outputting notification message") if $self->{verbose} > 1; |
|
1425
|
2662
|
100
|
|
|
|
38519
|
$self->output_headers($out) unless $no_headers; |
|
1426
|
2662
|
|
|
|
|
49209
|
$self->output_content_type($out); |
|
1427
|
2662
|
|
|
|
|
31381
|
$self->start_body($out); |
|
1428
|
2662
|
|
|
|
|
24138
|
$self->output_metadata($out); |
|
1429
|
2662
|
|
|
|
|
20981
|
$self->output_log_message($out); |
|
1430
|
2662
|
|
|
|
|
39521
|
$self->output_file_lists($out); |
|
1431
|
2662
|
100
|
|
|
|
12545
|
if ($self->{with_diff}) { |
|
1432
|
|
|
|
|
|
|
# Get a handle on the diff output. |
|
1433
|
704
|
|
|
|
|
19337
|
my $diff = $self->diff_handle; |
|
1434
|
675
|
100
|
|
|
|
59852
|
if ($self->{attach_diff}) { |
|
1435
|
155
|
|
|
|
|
10937
|
$self->end_body($out); |
|
1436
|
155
|
|
|
|
|
14353
|
$self->output_attached_diff($out, $diff); |
|
1437
|
|
|
|
|
|
|
} else { |
|
1438
|
520
|
|
|
|
|
128282
|
$self->output_diff($out, $diff); |
|
1439
|
520
|
|
|
|
|
6974
|
$self->end_body($out); |
|
1440
|
|
|
|
|
|
|
} |
|
1441
|
|
|
|
|
|
|
} else { |
|
1442
|
1958
|
|
|
|
|
19640
|
$self->end_body($out); |
|
1443
|
|
|
|
|
|
|
} |
|
1444
|
2633
|
|
|
|
|
24999
|
$self->end_message($out); |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
2633
|
|
|
|
|
26362
|
return $self; |
|
1447
|
|
|
|
|
|
|
} |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
############################################################################## |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
=head3 output_headers |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
$notifier->output_headers($file_handle); |
|
1454
|
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
Outputs the headers for the notification message headers. Should be called |
|
1456
|
|
|
|
|
|
|
only once for a single email message. |
|
1457
|
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
=cut |
|
1459
|
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
sub output_headers { |
|
1461
|
2543
|
|
|
2543
|
1
|
26994
|
my ($self, $out) = @_; |
|
1462
|
2543
|
50
|
|
|
|
14820
|
$self->_dbpnt( "Outputting headers") if $self->{verbose} > 2; |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# Q-Encoding (RFC 2047) |
|
1465
|
7629
|
|
|
|
|
6692686
|
my ($subj, $from, $to) = PERL58 ? map { |
|
1466
|
2543
|
|
|
|
|
187857
|
Encode::encode( 'MIME-Q', $_ ); |
|
1467
|
|
|
|
|
|
|
} $self->{subject}, $self->{from}, join ', ', @{ $self->{to} } : ( |
|
1468
|
2543
|
|
|
|
|
12536
|
$self->{subject}, $self->{from}, join ', ', @{ $self->{to} } |
|
1469
|
|
|
|
|
|
|
); |
|
1470
|
|
|
|
|
|
|
|
|
1471
|
2543
|
|
|
|
|
345208
|
my @headers = ( |
|
1472
|
|
|
|
|
|
|
"MIME-Version: 1.0\n", |
|
1473
|
|
|
|
|
|
|
"X-Mailer: SVN::Notify " . $self->VERSION |
|
1474
|
|
|
|
|
|
|
. ": http://search.cpan.org/dist/SVN-Notify/\n", |
|
1475
|
|
|
|
|
|
|
"From: $from\n", |
|
1476
|
|
|
|
|
|
|
"Errors-To: $from\n", |
|
1477
|
|
|
|
|
|
|
"To: $to\n", |
|
1478
|
|
|
|
|
|
|
"Subject: $subj\n" |
|
1479
|
|
|
|
|
|
|
); |
|
1480
|
|
|
|
|
|
|
|
|
1481
|
2543
|
100
|
|
|
|
21943
|
push @headers, "Reply-To: $self->{reply_to}\n" if $self->{reply_to}; |
|
1482
|
|
|
|
|
|
|
|
|
1483
|
2543
|
100
|
|
|
|
17411
|
if (my $heads = $self->{add_headers}) { |
|
1484
|
1
|
|
|
|
|
35
|
while (my ($k, $v) = each %{ $heads }) { |
|
|
3
|
|
|
|
|
58
|
|
|
1485
|
2
|
100
|
|
|
|
24
|
push @headers, "$k: $_\n" for ref $v ? @{ $v } : $v; |
|
|
1
|
|
|
|
|
21
|
|
|
1486
|
|
|
|
|
|
|
} |
|
1487
|
|
|
|
|
|
|
} |
|
1488
|
|
|
|
|
|
|
|
|
1489
|
2543
|
|
|
|
|
9151
|
print $out @{ $self->run_filters( headers => \@headers ) }; |
|
|
2543
|
|
|
|
|
79375
|
|
|
1490
|
2543
|
|
|
|
|
15130
|
return $self; |
|
1491
|
|
|
|
|
|
|
} |
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
############################################################################## |
|
1494
|
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
=head3 output_content_type |
|
1496
|
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
$notifier->output_content_type($file_handle); |
|
1498
|
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
Outputs the content type and transfer encoding headers. These demarcate the |
|
1500
|
|
|
|
|
|
|
body of the message. If the C parameter was set to true, then a |
|
1501
|
|
|
|
|
|
|
boundary string will be generated and the Content-Type set to |
|
1502
|
|
|
|
|
|
|
"multipart/mixed" and stored as the C attribute. |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
After that, this method outputs the content type returned by |
|
1505
|
|
|
|
|
|
|
C, the character set specified by the C attribute, |
|
1506
|
|
|
|
|
|
|
and a Content-Transfer-Encoding of "8bit". Subclasses can either rely on this |
|
1507
|
|
|
|
|
|
|
functionality or override this method to provide their own content type |
|
1508
|
|
|
|
|
|
|
headers. |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
=cut |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
sub output_content_type { |
|
1513
|
2662
|
|
|
2662
|
1
|
9160
|
my ($self, $out) = @_; |
|
1514
|
2662
|
50
|
|
|
|
20600
|
$self->_dbpnt( "Outputting content type") if $self->{verbose} > 2; |
|
1515
|
|
|
|
|
|
|
# Output the content type. |
|
1516
|
2662
|
100
|
|
|
|
9322
|
if ($self->{attach_diff}) { |
|
1517
|
|
|
|
|
|
|
# We need a boundary string. |
|
1518
|
159
|
|
66
|
|
|
6984
|
$self->{boundary} ||= join '', ('a'..'z', 'A'..'Z', 0..9)[ map { rand 62 } 0..10]; |
|
|
946
|
|
|
|
|
10286
|
|
|
1519
|
159
|
|
|
|
|
2153
|
print $out |
|
1520
|
|
|
|
|
|
|
qq{Content-Type: multipart/mixed; boundary="$self->{boundary}"\n\n}; |
|
1521
|
|
|
|
|
|
|
} |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
2662
|
|
|
|
|
163964
|
my $ctype = $self->content_type; |
|
1524
|
2662
|
100
|
|
|
|
12571
|
print $out "--$self->{boundary}\n" if $self->{attach_diff}; |
|
1525
|
2662
|
100
|
|
|
|
33106
|
print $out "Content-Type: $ctype; charset=$self->{encoding}\n", |
|
1526
|
|
|
|
|
|
|
($self->{language} ? "Content-Language: $self->{language}\n" : ()), |
|
1527
|
|
|
|
|
|
|
"Content-Transfer-Encoding: 8bit\n\n"; |
|
1528
|
2662
|
|
|
|
|
8144
|
return $self; |
|
1529
|
|
|
|
|
|
|
} |
|
1530
|
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
############################################################################## |
|
1532
|
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
=head3 start_body |
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
$notifier->start_body($file_handle); |
|
1536
|
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
This method starts the body of the notification message, which means that it |
|
1538
|
|
|
|
|
|
|
outputs the contents of the C attribute, if there are any. Otherwise |
|
1539
|
|
|
|
|
|
|
it outputs nothing, but see subclasses for other behaviors. |
|
1540
|
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
=cut |
|
1542
|
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
sub start_body { |
|
1544
|
1585
|
|
|
1585
|
1
|
9747
|
my ($self, $out) = @_; |
|
1545
|
1585
|
100
|
|
|
|
10707
|
my $start = [ $self->{header} ? ("$self->{header}\n") : () ]; |
|
1546
|
1585
|
|
|
|
|
4408
|
$start = $self->run_filters( start_body => $start ); |
|
1547
|
1585
|
100
|
66
|
|
|
34841
|
print $out @$start, "\n" if $start && @$start; |
|
1548
|
1585
|
|
|
|
|
3838
|
return $self; |
|
1549
|
|
|
|
|
|
|
} |
|
1550
|
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
############################################################################## |
|
1552
|
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
=head3 output_metadata |
|
1554
|
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
$notifier->output_metadata($file_handle); |
|
1556
|
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
This method outputs the metadata of the commit, including the revision number, |
|
1558
|
|
|
|
|
|
|
author (user), and date of the revision. If the C or |
|
1559
|
|
|
|
|
|
|
C attributes have been set, then the appropriate URL(s) for the |
|
1560
|
|
|
|
|
|
|
revision will also be output. |
|
1561
|
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
=cut |
|
1563
|
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
sub output_metadata { |
|
1565
|
1610
|
|
|
1610
|
1
|
4113
|
my ($self, $out) = @_; |
|
1566
|
1610
|
|
|
|
|
9164
|
my @lines = ("Revision: $self->{revision}\n"); |
|
1567
|
1610
|
100
|
|
|
|
6044
|
if (my $url = $self->{revision_url}) { |
|
1568
|
103
|
|
|
|
|
1637
|
push @lines, sprintf " $url\n", $self->{revision}; |
|
1569
|
|
|
|
|
|
|
} |
|
1570
|
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
# Output the Author any any relevant URL. |
|
1572
|
1610
|
|
|
|
|
11333
|
push @lines, "Author: $self->{user}\n"; |
|
1573
|
1610
|
100
|
|
|
|
6769
|
if (my $url = $self->{author_url}) { |
|
1574
|
32
|
|
|
|
|
1408
|
push @lines, sprintf " $url\n", $self->{user}; |
|
1575
|
|
|
|
|
|
|
} |
|
1576
|
|
|
|
|
|
|
|
|
1577
|
1610
|
|
|
|
|
6294
|
push @lines, "Date: $self->{date}\n"; |
|
1578
|
|
|
|
|
|
|
|
|
1579
|
1610
|
|
|
|
|
4246
|
print $out @{ $self->run_filters( metadata => \@lines ) }; |
|
|
1610
|
|
|
|
|
75784
|
|
|
1580
|
1610
|
|
|
|
|
5378
|
return $self; |
|
1581
|
|
|
|
|
|
|
} |
|
1582
|
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
############################################################################## |
|
1584
|
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
=head3 output_log_message |
|
1586
|
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
$notifier->output_log_message($file_handle); |
|
1588
|
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
Outputs the commit log message, as well as the label "Log Message". |
|
1590
|
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
=cut |
|
1592
|
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
sub output_log_message { |
|
1594
|
1585
|
|
|
1585
|
1
|
3465
|
my ($self, $out) = @_; |
|
1595
|
1585
|
100
|
|
|
|
5718
|
$self->_dbpnt( "Outputting log message") if $self->{verbose} > 1; |
|
1596
|
1585
|
|
|
|
|
6344
|
my $msg = join "\n", @{ |
|
1597
|
1585
|
|
|
|
|
3130
|
$self->run_filters( log_message => $self->{message} ) |
|
1598
|
|
|
|
|
|
|
}; |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
1585
|
|
|
|
|
17030
|
print $out "Log Message:\n-----------\n$msg\n"; |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
# Make Revision links. |
|
1603
|
1585
|
100
|
|
|
|
9960
|
if (my $url = $self->{revision_url}) { |
|
1604
|
103
|
50
|
|
|
|
12730
|
if (my @matches = $msg =~ /\b(?:(?:rev(?:ision)?\s*#?\s*|r)(\d+))\b/ig) { |
|
1605
|
103
|
|
|
|
|
1595693
|
print $out "\nRevision Links:\n--------------\n"; |
|
1606
|
103
|
|
|
|
|
3340
|
printf $out " $url\n", $_ for @matches; |
|
1607
|
|
|
|
|
|
|
} |
|
1608
|
|
|
|
|
|
|
} |
|
1609
|
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
# Make ticketing system links. |
|
1611
|
1585
|
100
|
|
|
|
42791
|
if (my $map = $self->ticket_map) { |
|
1612
|
26
|
|
|
|
|
702
|
my $has_header = 0; |
|
1613
|
|
|
|
|
|
|
$self->run_ticket_map( sub { |
|
1614
|
156
|
|
|
156
|
|
598
|
my ($regex, $url) = @_; |
|
1615
|
156
|
|
|
|
|
16614
|
while ($msg =~ /$regex/ig) { |
|
1616
|
234
|
100
|
|
|
|
1118
|
unless ($has_header) { |
|
1617
|
26
|
|
|
|
|
520
|
print $out "\nTicket Links:\n------------\n"; |
|
1618
|
26
|
|
|
|
|
78
|
$has_header = 1; |
|
1619
|
|
|
|
|
|
|
} |
|
1620
|
234
|
|
66
|
|
|
10322
|
printf $out " $url\n", $2 || $1; |
|
1621
|
|
|
|
|
|
|
} |
|
1622
|
26
|
|
|
|
|
1638
|
} ); |
|
1623
|
|
|
|
|
|
|
} |
|
1624
|
|
|
|
|
|
|
|
|
1625
|
1585
|
|
|
|
|
6012
|
return $self; |
|
1626
|
|
|
|
|
|
|
} |
|
1627
|
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
############################################################################## |
|
1629
|
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
=head3 output_file_lists |
|
1631
|
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
$notifier->output_file_lists($file_handle); |
|
1633
|
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
Outputs the lists of modified, added, and deleted files, as well as the list |
|
1635
|
|
|
|
|
|
|
of files for which properties were changed. The labels used for each group are |
|
1636
|
|
|
|
|
|
|
pulled in from the C class method. |
|
1637
|
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
=cut |
|
1639
|
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
sub output_file_lists { |
|
1641
|
1607
|
|
|
1607
|
1
|
4875
|
my ($self, $out) = @_; |
|
1642
|
1607
|
50
|
|
|
|
116824
|
my $files = $self->{files} or return $self; |
|
1643
|
1607
|
100
|
|
|
|
10871
|
$self->_dbpnt( "Outputting file lists") if $self->{verbose} > 1; |
|
1644
|
1607
|
|
|
|
|
20989
|
my $map = $self->file_label_map; |
|
1645
|
|
|
|
|
|
|
# Create the underlines. |
|
1646
|
1607
|
|
|
|
|
38211
|
my %dash = ( map { $_ => '-' x length($map->{$_}) } keys %$map ); |
|
|
6428
|
|
|
|
|
69422
|
|
|
1647
|
|
|
|
|
|
|
|
|
1648
|
1607
|
|
|
|
|
39967
|
foreach my $type (qw(U A D _)) { |
|
1649
|
|
|
|
|
|
|
# Skip it if there's nothing to report. |
|
1650
|
6428
|
100
|
|
|
|
25251
|
next unless $files->{$type}; |
|
1651
|
6059
|
50
|
|
|
|
13761
|
$self->_dbpnt( " Outputting $map->{$type} file list") |
|
1652
|
|
|
|
|
|
|
if $self->{verbose} > 2; |
|
1653
|
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
# Identify the action and output each file. |
|
1655
|
6059
|
|
|
|
|
14569
|
print $out "\n", @{ $self->run_filters( |
|
|
31287
|
|
|
|
|
803860
|
|
|
1656
|
|
|
|
|
|
|
file_lists => [ |
|
1657
|
|
|
|
|
|
|
"$map->{$type}:\n", |
|
1658
|
|
|
|
|
|
|
"$dash{$type}\n", |
|
1659
|
6059
|
|
|
|
|
25344
|
map { " $_\n" } @{ $files->{$type} } |
|
|
6059
|
|
|
|
|
103208
|
|
|
1660
|
|
|
|
|
|
|
] |
|
1661
|
|
|
|
|
|
|
) }; |
|
1662
|
|
|
|
|
|
|
} |
|
1663
|
1607
|
|
|
|
|
4895
|
print $out "\n"; |
|
1664
|
1607
|
|
|
|
|
6580
|
return $self; |
|
1665
|
|
|
|
|
|
|
} |
|
1666
|
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
############################################################################## |
|
1668
|
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
=head3 end_body |
|
1670
|
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
$notifier->end_body($file_handle); |
|
1672
|
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
Closes out the body of the email by outputting the contents of the C |
|
1674
|
|
|
|
|
|
|
attribute, if any, and then a couple of newlines. Designed to be called when |
|
1675
|
|
|
|
|
|
|
the body of the message is complete, and before any call to |
|
1676
|
|
|
|
|
|
|
C. |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
=cut |
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
sub end_body { |
|
1681
|
1576
|
|
|
1576
|
1
|
5575
|
my ($self, $out) = @_; |
|
1682
|
1576
|
50
|
|
|
|
6325
|
$self->_dbpnt( "Ending body") if $self->{verbose} > 2; |
|
1683
|
1576
|
100
|
|
|
|
11157
|
my $end = [ $self->{footer} ? ("$self->{footer}\n") : () ]; |
|
1684
|
1576
|
|
|
|
|
12177
|
$end = $self->run_filters( end_body => $end ); |
|
1685
|
1576
|
100
|
66
|
|
|
28124
|
print $out @$end, "\n" if $end && @$end; |
|
1686
|
1576
|
|
|
|
|
6764
|
return $self; |
|
1687
|
|
|
|
|
|
|
} |
|
1688
|
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
############################################################################## |
|
1690
|
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
=head3 output_diff |
|
1692
|
|
|
|
|
|
|
|
|
1693
|
|
|
|
|
|
|
$notifier->output_diff($out_file_handle, $diff_file_handle); |
|
1694
|
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
Reads diff data from C<$diff_file_handle> and outputs it to to |
|
1696
|
|
|
|
|
|
|
C<$out_file_handle>. |
|
1697
|
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
=cut |
|
1699
|
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
sub output_diff { |
|
1701
|
228
|
|
|
228
|
1
|
1321
|
my $self = shift; |
|
1702
|
228
|
50
|
|
|
|
4400
|
$self->_dbpnt( "Outputting diff") if $self->{verbose} > 1; |
|
1703
|
228
|
|
|
|
|
5035
|
$self->_dump_diff(@_); |
|
1704
|
|
|
|
|
|
|
} |
|
1705
|
|
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
############################################################################## |
|
1707
|
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
=head3 output_attached_diff |
|
1709
|
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
$notifier->output_attached_diff($out_file_handle, $diff_file_handle); |
|
1711
|
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
Reads diff data from C<$diff_file_handle> and outputs it to to |
|
1713
|
|
|
|
|
|
|
C<$out_file_handle> as an attachment. |
|
1714
|
|
|
|
|
|
|
|
|
1715
|
|
|
|
|
|
|
=cut |
|
1716
|
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
sub output_attached_diff { |
|
1718
|
155
|
|
|
155
|
1
|
2046
|
my ($self, $out, $diff) = @_; |
|
1719
|
155
|
50
|
|
|
|
3786
|
$self->_dbpnt( "Attaching diff") if $self->{verbose} > 2; |
|
1720
|
155
|
100
|
|
|
|
8976
|
print $out "\n--$self->{boundary}\n", |
|
1721
|
|
|
|
|
|
|
"Content-Disposition: attachment; filename=", |
|
1722
|
|
|
|
|
|
|
"r$self->{revision}-$self->{user}.diff\n", |
|
1723
|
|
|
|
|
|
|
"Content-Type: $self->{diff_content_type}; charset=$self->{encoding}\n", |
|
1724
|
|
|
|
|
|
|
($self->{language} ? "Content-Language: $self->{language}\n" : ()), |
|
1725
|
|
|
|
|
|
|
"Content-Transfer-Encoding: 8bit\n\n"; |
|
1726
|
155
|
|
|
|
|
3412
|
$self->_dump_diff($out, $diff); |
|
1727
|
|
|
|
|
|
|
} |
|
1728
|
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
############################################################################## |
|
1730
|
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
=head3 end_message |
|
1732
|
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
$notifier->end_message($file_handle); |
|
1734
|
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
Outputs the final part of the message,. In this case, that means only a |
|
1736
|
|
|
|
|
|
|
boundary if the C parameter is true. Designed to be called after |
|
1737
|
|
|
|
|
|
|
any call to C. |
|
1738
|
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
=cut |
|
1740
|
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
sub end_message { |
|
1742
|
2633
|
|
|
2633
|
1
|
11006
|
my ($self, $out) = @_; |
|
1743
|
2633
|
100
|
|
|
|
11869
|
print $out "--$self->{boundary}--\n" if $self->{attach_diff}; |
|
1744
|
2633
|
|
|
|
|
11057
|
return $self; |
|
1745
|
|
|
|
|
|
|
} |
|
1746
|
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
############################################################################## |
|
1748
|
|
|
|
|
|
|
|
|
1749
|
|
|
|
|
|
|
=head3 run_ticket_map |
|
1750
|
|
|
|
|
|
|
|
|
1751
|
|
|
|
|
|
|
$notifier->run_ticket_map( \&callback, @params ); |
|
1752
|
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
Loops over the ticket systems you have defined, calling the C<$callback> |
|
1754
|
|
|
|
|
|
|
function for each one, passing to it the regex, url and @params specified as |
|
1755
|
|
|
|
|
|
|
its parameters. |
|
1756
|
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
=cut |
|
1758
|
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
sub run_ticket_map { |
|
1760
|
65
|
|
|
65
|
1
|
789
|
my ($self, $callback, @params) = @_; |
|
1761
|
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
# Make ticketing system links. |
|
1763
|
65
|
50
|
|
|
|
1158
|
my $map = $self->ticket_map or return; |
|
1764
|
65
|
|
|
|
|
471
|
my $has_header = 0; |
|
1765
|
65
|
|
|
|
|
4082
|
while (my ($regex, $url) = each %$map) { |
|
1766
|
332
|
|
66
|
|
|
3816
|
$regex = $_ticket_regexen{ $regex } || $regex; |
|
1767
|
332
|
|
|
|
|
1732
|
$callback->( $regex, $url, @params ); |
|
1768
|
|
|
|
|
|
|
} |
|
1769
|
|
|
|
|
|
|
} |
|
1770
|
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
############################################################################## |
|
1772
|
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
=head3 run_filters |
|
1774
|
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
$data = $notifier->run_filters( $output_type => $data ); |
|
1776
|
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
Runs the filters for C<$output_type> on $data. Used internally by SVN::Notify |
|
1778
|
|
|
|
|
|
|
and by subclasses. |
|
1779
|
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
=cut |
|
1781
|
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
sub run_filters { |
|
1783
|
38181
|
|
|
38181
|
1
|
232512
|
my ($self, $type, $data) = @_; |
|
1784
|
38181
|
100
|
|
|
|
680354
|
my $filters = $self->{filters}{$type} or return $data; |
|
1785
|
1329
|
|
|
|
|
197910
|
$data = $_->($self, $data) for @$filters; |
|
1786
|
1329
|
|
|
|
|
5069559
|
return $data; |
|
1787
|
|
|
|
|
|
|
} |
|
1788
|
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
############################################################################## |
|
1790
|
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
=head3 filters_for |
|
1792
|
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
my $filters = $notifier->filters_for( $output_type ); |
|
1794
|
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
Returns an array reference of of the filters loaded for C<$output_type>. |
|
1796
|
|
|
|
|
|
|
Returns C if there are no filters have been loaded for C<$output_type>. |
|
1797
|
|
|
|
|
|
|
|
|
1798
|
|
|
|
|
|
|
=cut |
|
1799
|
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
sub filters_for { |
|
1801
|
3579
|
|
|
3579
|
1
|
38051
|
shift->{filters}{+shift}; |
|
1802
|
|
|
|
|
|
|
} |
|
1803
|
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
############################################################################## |
|
1805
|
|
|
|
|
|
|
|
|
1806
|
|
|
|
|
|
|
=head3 diff_handle |
|
1807
|
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
my $diff = $notifier->diff_handle; |
|
1809
|
|
|
|
|
|
|
while (<$diff>) { print } |
|
1810
|
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
Returns a file handle reference providing access to the the commit diff. It |
|
1812
|
|
|
|
|
|
|
will usually be passed as the second argument to C or |
|
1813
|
|
|
|
|
|
|
C. |
|
1814
|
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
=cut |
|
1816
|
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
sub diff_handle { |
|
1818
|
704
|
|
|
704
|
1
|
3678
|
my $self = shift; |
|
1819
|
|
|
|
|
|
|
# To avoid svnlook output except for diff contents, such as "Modified" |
|
1820
|
|
|
|
|
|
|
# etc., to be output in the localized string encoded with another encoding |
|
1821
|
|
|
|
|
|
|
# from diff contents. HTML and HTML::ColorDiff also expect the terms |
|
1822
|
|
|
|
|
|
|
# printed in English. |
|
1823
|
704
|
|
|
|
|
17735
|
local $ENV{LANG} = 'C'; |
|
1824
|
|
|
|
|
|
|
|
|
1825
|
48
|
50
|
|
|
|
49392
|
return $self->_pipe( |
|
1826
|
|
|
|
|
|
|
$self->{diff_encoding}, |
|
1827
|
|
|
|
|
|
|
'-|' => $self->{svnlook}, |
|
1828
|
|
|
|
|
|
|
'diff' => $self->{repos_path}, |
|
1829
|
|
|
|
|
|
|
'-r' => $self->{revision}, |
|
1830
|
|
|
|
|
|
|
( $self->{diff_switches} |
|
1831
|
704
|
100
|
|
|
|
11184
|
? grep { defined && $_ ne '' } |
|
1832
|
|
|
|
|
|
|
# Allow quoting of arguments, but strip out the quotes. |
|
1833
|
|
|
|
|
|
|
split /(?:'([^']+)'|"([^"]+)")?\s+(?:'([^']+)'|"([^"]+)")?/, |
|
1834
|
|
|
|
|
|
|
$self->{diff_switches} |
|
1835
|
|
|
|
|
|
|
: () |
|
1836
|
|
|
|
|
|
|
), |
|
1837
|
|
|
|
|
|
|
); |
|
1838
|
|
|
|
|
|
|
} |
|
1839
|
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
############################################################################## |
|
1841
|
|
|
|
|
|
|
# This method actually dumps the output of C. It's a separate |
|
1842
|
|
|
|
|
|
|
# method because output_attached_diff() and output_diff() do essentially the |
|
1843
|
|
|
|
|
|
|
# same thing, so they can both call it. The diff output will be truncated at |
|
1844
|
|
|
|
|
|
|
# max_diff_length, if specified. |
|
1845
|
|
|
|
|
|
|
############################################################################## |
|
1846
|
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
sub _dump_diff { |
|
1848
|
383
|
|
|
383
|
|
5992
|
my ($self, $out, $diff) = @_; |
|
1849
|
383
|
|
|
|
|
6991
|
$diff = $self->run_filters( diff => $diff ); |
|
1850
|
|
|
|
|
|
|
|
|
1851
|
383
|
100
|
|
|
|
3786
|
if (my $max = $self->{max_diff_length}) { |
|
1852
|
12
|
|
|
|
|
540
|
my $length = 0; |
|
1853
|
12
|
|
|
|
|
19959019
|
while (<$diff>) { |
|
1854
|
288
|
|
|
|
|
2650
|
s/[\n\r]+$//; |
|
1855
|
288
|
100
|
|
|
|
860
|
if (($length += length) < $max) { |
|
1856
|
276
|
|
|
|
|
2152
|
print $out $_, "\n"; |
|
1857
|
|
|
|
|
|
|
} |
|
1858
|
|
|
|
|
|
|
else { |
|
1859
|
12
|
|
|
|
|
207
|
print $out |
|
1860
|
|
|
|
|
|
|
"\n\@\@ Diff output truncated at $max characters. \@\@\n"; |
|
1861
|
12
|
|
|
|
|
82
|
last; |
|
1862
|
|
|
|
|
|
|
} |
|
1863
|
|
|
|
|
|
|
} |
|
1864
|
|
|
|
|
|
|
} |
|
1865
|
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
else { |
|
1867
|
371
|
|
|
|
|
2077771974
|
while (<$diff>) { |
|
1868
|
12765
|
|
|
|
|
190786438
|
s/[\n\r]+$//; |
|
1869
|
12765
|
|
|
|
|
624456
|
print $out $_, "\n"; |
|
1870
|
|
|
|
|
|
|
} |
|
1871
|
|
|
|
|
|
|
} |
|
1872
|
383
|
50
|
|
|
|
446309
|
close $diff or warn "Child process exited: $?\n"; |
|
1873
|
383
|
|
|
|
|
13080
|
return $self; |
|
1874
|
|
|
|
|
|
|
} |
|
1875
|
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
############################################################################## |
|
1877
|
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
__PACKAGE__->_accessors(qw( |
|
1879
|
|
|
|
|
|
|
repos_path |
|
1880
|
|
|
|
|
|
|
revision |
|
1881
|
|
|
|
|
|
|
to_regex_map |
|
1882
|
|
|
|
|
|
|
to_email_map |
|
1883
|
|
|
|
|
|
|
from |
|
1884
|
|
|
|
|
|
|
user_domain |
|
1885
|
|
|
|
|
|
|
svnlook |
|
1886
|
|
|
|
|
|
|
sendmail |
|
1887
|
|
|
|
|
|
|
set_sender |
|
1888
|
|
|
|
|
|
|
add_headers |
|
1889
|
|
|
|
|
|
|
smtp |
|
1890
|
|
|
|
|
|
|
encoding |
|
1891
|
|
|
|
|
|
|
diff_encoding |
|
1892
|
|
|
|
|
|
|
svn_encoding |
|
1893
|
|
|
|
|
|
|
env_lang |
|
1894
|
|
|
|
|
|
|
svn_env_lang |
|
1895
|
|
|
|
|
|
|
language |
|
1896
|
|
|
|
|
|
|
with_diff |
|
1897
|
|
|
|
|
|
|
attach_diff |
|
1898
|
|
|
|
|
|
|
diff_switches |
|
1899
|
|
|
|
|
|
|
reply_to |
|
1900
|
|
|
|
|
|
|
subject_prefix |
|
1901
|
|
|
|
|
|
|
subject_cx |
|
1902
|
|
|
|
|
|
|
max_sub_length |
|
1903
|
|
|
|
|
|
|
max_diff_length |
|
1904
|
|
|
|
|
|
|
author_url |
|
1905
|
|
|
|
|
|
|
revision_url |
|
1906
|
|
|
|
|
|
|
ticket_url |
|
1907
|
|
|
|
|
|
|
ticket_regex |
|
1908
|
|
|
|
|
|
|
ticket_map |
|
1909
|
|
|
|
|
|
|
header |
|
1910
|
|
|
|
|
|
|
footer |
|
1911
|
|
|
|
|
|
|
verbose |
|
1912
|
|
|
|
|
|
|
boundary |
|
1913
|
|
|
|
|
|
|
user |
|
1914
|
|
|
|
|
|
|
date |
|
1915
|
|
|
|
|
|
|
message |
|
1916
|
|
|
|
|
|
|
message_size |
|
1917
|
|
|
|
|
|
|
subject |
|
1918
|
|
|
|
|
|
|
files |
|
1919
|
|
|
|
|
|
|
)); |
|
1920
|
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
############################################################################## |
|
1922
|
|
|
|
|
|
|
# This method is used to create accessors for the list of attributes passed to |
|
1923
|
|
|
|
|
|
|
# it. It creates them both for SVN::Notify (just above) and for all subclasses |
|
1924
|
|
|
|
|
|
|
# in register_attributes(). |
|
1925
|
|
|
|
|
|
|
############################################################################## |
|
1926
|
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
sub _accessors { |
|
1928
|
562
|
|
|
562
|
|
1484
|
my $class = shift; |
|
1929
|
562
|
|
|
|
|
2083
|
for my $attr (@_) { |
|
1930
|
293
|
|
|
293
|
|
5214
|
no strict 'refs'; |
|
|
293
|
|
|
|
|
628
|
|
|
|
293
|
|
|
|
|
108750
|
|
|
1931
|
12385
|
|
|
|
|
60476
|
*{"$class\::$attr"} = sub { |
|
1932
|
32782
|
|
|
32782
|
|
103675
|
my $self = shift; |
|
1933
|
32782
|
100
|
|
|
|
2456940
|
return $self->{$attr} unless @_; |
|
1934
|
53
|
|
|
|
|
317
|
$self->{$attr} = shift; |
|
1935
|
53
|
|
|
|
|
305
|
return $self; |
|
1936
|
12385
|
|
|
|
|
34703
|
}; |
|
1937
|
|
|
|
|
|
|
} |
|
1938
|
|
|
|
|
|
|
} |
|
1939
|
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
# Aliases for deprecated attributes. |
|
1941
|
84
|
|
|
84
|
1
|
420
|
sub svnweb_url { shift->revision_url(@_) } |
|
1942
|
84
|
|
|
84
|
1
|
420
|
sub viewcvs_url { shift->revision_url(@_) } |
|
1943
|
0
|
|
|
0
|
1
|
0
|
sub charset { shift->encoding(@_) } |
|
1944
|
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
# Deprecated ticket URL systems. |
|
1946
|
|
|
|
|
|
|
for my $tick (qw(rt bugzilla jira gnats)) { |
|
1947
|
293
|
|
|
293
|
|
1847
|
no strict 'refs'; |
|
|
293
|
|
|
|
|
702
|
|
|
|
293
|
|
|
|
|
88657
|
|
|
1948
|
|
|
|
|
|
|
*{$tick . '_url'} = sub { |
|
1949
|
156
|
|
|
156
|
|
312
|
my $self = shift; |
|
1950
|
156
|
|
50
|
|
|
1560
|
my $map = $self->{ticket_map} || {}; |
|
1951
|
156
|
50
|
|
|
|
1196
|
return $map->{$tick} unless @_; |
|
1952
|
0
|
0
|
|
|
|
0
|
if (my $url = shift) { |
|
1953
|
0
|
|
|
|
|
0
|
$map->{$tick} = $url; |
|
1954
|
|
|
|
|
|
|
} else { |
|
1955
|
0
|
|
|
|
|
0
|
delete $map->{$tick}; |
|
1956
|
|
|
|
|
|
|
} |
|
1957
|
0
|
|
|
|
|
0
|
$self->{ticket_map} = $map; |
|
1958
|
0
|
|
|
|
|
0
|
return $self; |
|
1959
|
|
|
|
|
|
|
}; |
|
1960
|
|
|
|
|
|
|
} |
|
1961
|
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
for my $attr (qw(to strip_cx_regex)) { |
|
1963
|
293
|
|
|
293
|
|
2410
|
no strict 'refs'; |
|
|
293
|
|
|
|
|
673
|
|
|
|
293
|
|
|
|
|
487729
|
|
|
1964
|
|
|
|
|
|
|
*{__PACKAGE__ . "::$attr"} = sub { |
|
1965
|
117
|
|
|
117
|
|
281
|
my $self = shift; |
|
1966
|
117
|
50
|
|
|
|
973
|
return wantarray ? @{ $self->{$attr} } : $self->{$attr}[0] unless @_; |
|
|
117
|
50
|
|
|
|
2105
|
|
|
1967
|
0
|
|
|
|
|
0
|
$self->{$attr}= \@_; |
|
1968
|
0
|
|
|
|
|
0
|
return $self; |
|
1969
|
|
|
|
|
|
|
}; |
|
1970
|
|
|
|
|
|
|
} |
|
1971
|
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
=head2 Accessors |
|
1973
|
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
=head3 repos_path |
|
1975
|
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
my $repos_path = $notifier->repos_path; |
|
1977
|
|
|
|
|
|
|
$notifier = $notifier->repos_path($repos_path); |
|
1978
|
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
1980
|
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
=head3 revision |
|
1982
|
|
|
|
|
|
|
|
|
1983
|
|
|
|
|
|
|
my $revision = $notifier->revision; |
|
1984
|
|
|
|
|
|
|
$notifier = $notifier->revision($revision); |
|
1985
|
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
1987
|
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
=head3 to |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
my $to = $notifier->to; |
|
1991
|
|
|
|
|
|
|
$notifier = $notifier->to($to); |
|
1992
|
|
|
|
|
|
|
my @tos = $notifier->to; |
|
1993
|
|
|
|
|
|
|
$notifier = $notifier->to(@tos); |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
Gets or sets the list of values stored in the C attribute. In a scalar |
|
1996
|
|
|
|
|
|
|
context, it returns only the first value in the list, for backwards |
|
1997
|
|
|
|
|
|
|
compatibility with older versions of SVN::Notify. In list context, it of |
|
1998
|
|
|
|
|
|
|
course returns the entire list. Pass in one or more values to set all of the |
|
1999
|
|
|
|
|
|
|
values for the C attribute. |
|
2000
|
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
=head3 to_regex_map |
|
2002
|
|
|
|
|
|
|
|
|
2003
|
|
|
|
|
|
|
my $to_regex_map = $notifier->to_regex_map; |
|
2004
|
|
|
|
|
|
|
$notifier = $notifier->to_regex_map($to_regex_map); |
|
2005
|
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is a hash |
|
2007
|
|
|
|
|
|
|
reference of email addresses mapped to regular expressions. |
|
2008
|
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
=head3 to_email_map |
|
2010
|
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
my $to_email_map = $notifier->to_email_map; |
|
2012
|
|
|
|
|
|
|
$notifier = $notifier->to_email_map($to_email_map); |
|
2013
|
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is a hash |
|
2015
|
|
|
|
|
|
|
reference of regular expressions mapped to email addresses. |
|
2016
|
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
=head3 from |
|
2018
|
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
my $from = $notifier->from; |
|
2020
|
|
|
|
|
|
|
$notifier = $notifier->from($from); |
|
2021
|
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2023
|
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
=head3 user_domain |
|
2025
|
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
my $user_domain = $notifier->user_domain; |
|
2027
|
|
|
|
|
|
|
$notifier = $notifier->user_domain($user_domain); |
|
2028
|
|
|
|
|
|
|
|
|
2029
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2030
|
|
|
|
|
|
|
|
|
2031
|
|
|
|
|
|
|
=head3 svnlook |
|
2032
|
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
my $svnlook = $notifier->svnlook; |
|
2034
|
|
|
|
|
|
|
$notifier = $notifier->svnlook($svnlook); |
|
2035
|
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
=head3 sendmail |
|
2039
|
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
my $sendmail = $notifier->sendmail; |
|
2041
|
|
|
|
|
|
|
$notifier = $notifier->sendmail($sendmail); |
|
2042
|
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2044
|
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
=head3 set_sender |
|
2046
|
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
my $set_sender = $notifier->set_sender; |
|
2048
|
|
|
|
|
|
|
$notifier = $notifier->set_sender($set_sender); |
|
2049
|
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2051
|
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
=head3 smtp |
|
2053
|
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
my $smtp = $notifier->smtp; |
|
2055
|
|
|
|
|
|
|
$notifier = $notifier->smtp($smtp); |
|
2056
|
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2058
|
|
|
|
|
|
|
|
|
2059
|
|
|
|
|
|
|
=head3 encoding |
|
2060
|
|
|
|
|
|
|
|
|
2061
|
|
|
|
|
|
|
my $encoding = $notifier->encoding; |
|
2062
|
|
|
|
|
|
|
$notifier = $notifier->encoding($encoding); |
|
2063
|
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. C is an alias |
|
2065
|
|
|
|
|
|
|
preserved for backward compatibility. |
|
2066
|
|
|
|
|
|
|
|
|
2067
|
|
|
|
|
|
|
=head3 svn_encoding |
|
2068
|
|
|
|
|
|
|
|
|
2069
|
|
|
|
|
|
|
my $svn_encoding = $notifier->svn_encoding; |
|
2070
|
|
|
|
|
|
|
$notifier = $notifier->svn_encoding($svn_encoding); |
|
2071
|
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2073
|
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
=head3 diff_encoding |
|
2075
|
|
|
|
|
|
|
|
|
2076
|
|
|
|
|
|
|
my $diff_encoding = $notifier->diff_encoding; |
|
2077
|
|
|
|
|
|
|
$notifier = $notifier->diff_encoding($diff_encoding); |
|
2078
|
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2080
|
|
|
|
|
|
|
|
|
2081
|
|
|
|
|
|
|
=head3 language |
|
2082
|
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
my $language = $notifier->language; |
|
2084
|
|
|
|
|
|
|
$notifier = $notifier->language($language); |
|
2085
|
|
|
|
|
|
|
|
|
2086
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2087
|
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
=head3 env_lang |
|
2089
|
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
my $env_lang = $notifier->env_lang; |
|
2091
|
|
|
|
|
|
|
$notifier = $notifier->env_lang($env_lang); |
|
2092
|
|
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to C<< |
|
2094
|
|
|
|
|
|
|
$notify->language . '.' . $notify->encoding >> when C is set, and |
|
2095
|
|
|
|
|
|
|
otherwise is C. This attribute is used to set the C<$LANG> environment |
|
2096
|
|
|
|
|
|
|
variable, if it is not already set by the environment, before executing |
|
2097
|
|
|
|
|
|
|
C. |
|
2098
|
|
|
|
|
|
|
|
|
2099
|
|
|
|
|
|
|
=head3 svn_env_lang |
|
2100
|
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
my $svn_env_lang = $notifier->svn_env_lang; |
|
2102
|
|
|
|
|
|
|
$notifier = $notifier->svn_env_lang($svn_env_lang); |
|
2103
|
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to C<< |
|
2105
|
|
|
|
|
|
|
$notify->language . '.' . $notify->svn_encoding >> when C is set, |
|
2106
|
|
|
|
|
|
|
and otherwise is C. This attribute is used to set the C<$LANG> |
|
2107
|
|
|
|
|
|
|
environment variable, if it is not already set by the environment, before |
|
2108
|
|
|
|
|
|
|
executing C. It is not used for C, however, as the diff |
|
2109
|
|
|
|
|
|
|
itself will be emitted in raw octets except for headers such as "Modified", |
|
2110
|
|
|
|
|
|
|
which need to be in English so that subclasses can parse them. Thus, C<$LANG> |
|
2111
|
|
|
|
|
|
|
is always set to "C" for the execution of C. |
|
2112
|
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
=head3 with_diff |
|
2114
|
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
my $with_diff = $notifier->with_diff; |
|
2116
|
|
|
|
|
|
|
$notifier = $notifier->with_diff($with_diff); |
|
2117
|
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2119
|
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
=head3 attach_diff |
|
2121
|
|
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
my $attach_diff = $notifier->attach_diff; |
|
2123
|
|
|
|
|
|
|
$notifier = $notifier->attach_diff($attach_diff); |
|
2124
|
|
|
|
|
|
|
|
|
2125
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2126
|
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
=head3 diff_switches |
|
2128
|
|
|
|
|
|
|
|
|
2129
|
|
|
|
|
|
|
my $diff_switches = $notifier->diff_switches; |
|
2130
|
|
|
|
|
|
|
$notifier = $notifier->diff_switches($diff_switches); |
|
2131
|
|
|
|
|
|
|
|
|
2132
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2133
|
|
|
|
|
|
|
|
|
2134
|
|
|
|
|
|
|
=head3 reply_to |
|
2135
|
|
|
|
|
|
|
|
|
2136
|
|
|
|
|
|
|
my $reply_to = $notifier->reply_to; |
|
2137
|
|
|
|
|
|
|
$notifier = $notifier->reply_to($reply_to); |
|
2138
|
|
|
|
|
|
|
|
|
2139
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2140
|
|
|
|
|
|
|
|
|
2141
|
|
|
|
|
|
|
=head3 add_headers |
|
2142
|
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
my $add_headers = $notifier->add_headers; |
|
2144
|
|
|
|
|
|
|
$notifier = $notifier->add_headers({ |
|
2145
|
|
|
|
|
|
|
'X-Accept' => [qw(This That)], |
|
2146
|
|
|
|
|
|
|
'X-Reject' => 'Me!', |
|
2147
|
|
|
|
|
|
|
}); |
|
2148
|
|
|
|
|
|
|
|
|
2149
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is a hash |
|
2150
|
|
|
|
|
|
|
reference of the headers to be added to the email message. If one header needs |
|
2151
|
|
|
|
|
|
|
to appear multiple times, simply pass the corresponding hash value as an array |
|
2152
|
|
|
|
|
|
|
reference of each value for the header. Not to be confused with the C |
|
2153
|
|
|
|
|
|
|
accessor, which gets and sets text to be included at the beginning of the body |
|
2154
|
|
|
|
|
|
|
of the email message. |
|
2155
|
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
=head3 subject_prefix |
|
2157
|
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
my $subject_prefix = $notifier->subject_prefix; |
|
2159
|
|
|
|
|
|
|
$notifier = $notifier->subject_prefix($subject_prefix); |
|
2160
|
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2162
|
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
=head3 subject_cx |
|
2164
|
|
|
|
|
|
|
|
|
2165
|
|
|
|
|
|
|
my $subject_cx = $notifier->subject_cx; |
|
2166
|
|
|
|
|
|
|
$notifier = $notifier->subject_cx($subject_cx); |
|
2167
|
|
|
|
|
|
|
|
|
2168
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2169
|
|
|
|
|
|
|
|
|
2170
|
|
|
|
|
|
|
=head3 strip_cx_regex |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
my $strip_cx_regex = $notifier->strip_cx_regex; |
|
2173
|
|
|
|
|
|
|
$notifier = $notifier->strip_cx_regex($strip_cx_regex); |
|
2174
|
|
|
|
|
|
|
my @strip_cx_regexs = $notifier->strip_cx_regex; |
|
2175
|
|
|
|
|
|
|
$notifier = $notifier->strip_cx_regex(@strip_cx_regexs); |
|
2176
|
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
Gets or sets the list of values stored in the C attribute. In |
|
2178
|
|
|
|
|
|
|
a scalar context, it returns only the first value in the list; in list |
|
2179
|
|
|
|
|
|
|
context, it of course returns the entire list. Pass in one or more values to |
|
2180
|
|
|
|
|
|
|
set all of the values for the C attribute. |
|
2181
|
|
|
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
=head3 max_sub_length |
|
2183
|
|
|
|
|
|
|
|
|
2184
|
|
|
|
|
|
|
my $max_sub_length = $notifier->max_sub_length; |
|
2185
|
|
|
|
|
|
|
$notifier = $notifier->max_sub_length($max_sub_length); |
|
2186
|
|
|
|
|
|
|
|
|
2187
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2188
|
|
|
|
|
|
|
|
|
2189
|
|
|
|
|
|
|
=head3 max_diff_length |
|
2190
|
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
my $max_diff_length = $notifier->max_diff_length; |
|
2192
|
|
|
|
|
|
|
$notifier = $notifier->max_diff_length($max_diff_length); |
|
2193
|
|
|
|
|
|
|
|
|
2194
|
|
|
|
|
|
|
Gets or set the value of the C attribute. |
|
2195
|
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
=head3 author_url |
|
2197
|
|
|
|
|
|
|
|
|
2198
|
|
|
|
|
|
|
my $author_url = $notifier->author_url; |
|
2199
|
|
|
|
|
|
|
$notifier = $notifier->author_url($author_url); |
|
2200
|
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2202
|
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
=head3 revision_url |
|
2204
|
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
my $revision_url = $notifier->revision_url; |
|
2206
|
|
|
|
|
|
|
$notifier = $notifier->revision_url($revision_url); |
|
2207
|
|
|
|
|
|
|
|
|
2208
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2209
|
|
|
|
|
|
|
|
|
2210
|
|
|
|
|
|
|
=head3 svnweb_url |
|
2211
|
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
Deprecated. Pleas use C, instead. |
|
2213
|
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
=head3 viewcvs_url |
|
2215
|
|
|
|
|
|
|
|
|
2216
|
|
|
|
|
|
|
Deprecated. Pleas use C, instead. |
|
2217
|
|
|
|
|
|
|
|
|
2218
|
|
|
|
|
|
|
=head3 verbose |
|
2219
|
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
my $verbose = $notifier->verbose; |
|
2221
|
|
|
|
|
|
|
$notifier = $notifier->verbose($verbose); |
|
2222
|
|
|
|
|
|
|
|
|
2223
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. |
|
2224
|
|
|
|
|
|
|
|
|
2225
|
|
|
|
|
|
|
=head3 boundary |
|
2226
|
|
|
|
|
|
|
|
|
2227
|
|
|
|
|
|
|
my $boundary = $notifier->boundary; |
|
2228
|
|
|
|
|
|
|
$notifier = $notifier->boundary($boundary); |
|
2229
|
|
|
|
|
|
|
|
|
2230
|
|
|
|
|
|
|
Gets or sets the value of the C attribute. This string is normally |
|
2231
|
|
|
|
|
|
|
set by a call to C, but may be set ahead of time. |
|
2232
|
|
|
|
|
|
|
|
|
2233
|
|
|
|
|
|
|
=head3 user |
|
2234
|
|
|
|
|
|
|
|
|
2235
|
|
|
|
|
|
|
my $user = $notifier->user; |
|
2236
|
|
|
|
|
|
|
$notifier = $notifier->user($user); |
|
2237
|
|
|
|
|
|
|
|
|
2238
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to the value |
|
2239
|
|
|
|
|
|
|
pulled in from F by the call to C. |
|
2240
|
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
=head3 date |
|
2242
|
|
|
|
|
|
|
|
|
2243
|
|
|
|
|
|
|
my $date = $notifier->date; |
|
2244
|
|
|
|
|
|
|
$notifier = $notifier->date($date); |
|
2245
|
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to the value |
|
2247
|
|
|
|
|
|
|
pulled in from F by the call to C. |
|
2248
|
|
|
|
|
|
|
|
|
2249
|
|
|
|
|
|
|
=head3 message |
|
2250
|
|
|
|
|
|
|
|
|
2251
|
|
|
|
|
|
|
my $message = $notifier->message; |
|
2252
|
|
|
|
|
|
|
$notifier = $notifier->message($message); |
|
2253
|
|
|
|
|
|
|
|
|
2254
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to an array |
|
2255
|
|
|
|
|
|
|
reference of strings by the call to C. |
|
2256
|
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
=head3 message_size |
|
2258
|
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
my $message_size = $notifier->message_size; |
|
2260
|
|
|
|
|
|
|
$notifier = $notifier->message_size($message_size); |
|
2261
|
|
|
|
|
|
|
|
|
2262
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to the |
|
2263
|
|
|
|
|
|
|
value pulled in from F by the call to C. |
|
2264
|
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
=head3 subject |
|
2266
|
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
my $subject = $notifier->subject; |
|
2268
|
|
|
|
|
|
|
$notifier = $notifier->subject($subject); |
|
2269
|
|
|
|
|
|
|
|
|
2270
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is normally set |
|
2271
|
|
|
|
|
|
|
by a call to C, but may be set explicitly. |
|
2272
|
|
|
|
|
|
|
|
|
2273
|
|
|
|
|
|
|
=head3 files |
|
2274
|
|
|
|
|
|
|
|
|
2275
|
|
|
|
|
|
|
my $files = $notifier->files; |
|
2276
|
|
|
|
|
|
|
$notifier = $notifier->files($files); |
|
2277
|
|
|
|
|
|
|
|
|
2278
|
|
|
|
|
|
|
Gets or sets the value of the C attribute, which is set to a hash |
|
2279
|
|
|
|
|
|
|
reference of change type mapped to arrays of strings by the call to |
|
2280
|
|
|
|
|
|
|
C. |
|
2281
|
|
|
|
|
|
|
|
|
2282
|
|
|
|
|
|
|
=head3 header |
|
2283
|
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
my $header = $notifier->header; |
|
2285
|
|
|
|
|
|
|
$notifier = $notifier->header($header); |
|
2286
|
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
Gets or set the value of the C attribute. Not to be confused with the |
|
2288
|
|
|
|
|
|
|
C attribute, which manages headers to be inserted into the |
|
2289
|
|
|
|
|
|
|
notification email message headers. |
|
2290
|
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
=head3 footer |
|
2292
|
|
|
|
|
|
|
|
|
2293
|
|
|
|
|
|
|
my $footer = $notifier->footer; |
|
2294
|
|
|
|
|
|
|
$notifier = $notifier->footer($footer); |
|
2295
|
|
|
|
|
|
|
|
|
2296
|
|
|
|
|
|
|
Gets or set the value of the C |
|
2297
|
|
|
|
|
|
|
|
|
2298
|
|
|
|
|
|
|
=cut |
|
2299
|
|
|
|
|
|
|
|
|
2300
|
|
|
|
|
|
|
############################################################################## |
|
2301
|
|
|
|
|
|
|
# This method forks off a process to execute an external program and any |
|
2302
|
|
|
|
|
|
|
# associated arguments and returns a file handle that can be read from to |
|
2303
|
|
|
|
|
|
|
# fetch the output of the external program, or written to. Pass "-|" as the |
|
2304
|
|
|
|
|
|
|
# sole argument to read from another process (such as svnlook), and pass "|-" |
|
2305
|
|
|
|
|
|
|
# to write to another process (such as sendmail). |
|
2306
|
|
|
|
|
|
|
############################################################################## |
|
2307
|
|
|
|
|
|
|
|
|
2308
|
|
|
|
|
|
|
sub _pipe { |
|
2309
|
9133
|
|
|
9133
|
|
47437
|
my ($self, $encode, $mode) = (shift, shift, shift); |
|
2310
|
9133
|
100
|
|
|
|
48956
|
$self->_dbpnt( q{Piping execution of "} . join(q{" "}, @_) . q{"}) |
|
2311
|
|
|
|
|
|
|
if $self->{verbose}; |
|
2312
|
|
|
|
|
|
|
# Safer version of backtick (see perlipc(1)). |
|
2313
|
9133
|
|
|
|
|
38617
|
local *PIPE; |
|
2314
|
9133
|
|
|
|
|
10715
|
if (WIN32) { |
|
2315
|
|
|
|
|
|
|
my $cmd = $mode eq '-|' |
|
2316
|
|
|
|
|
|
|
? q{"} . join(q{" "}, @_) . q{"|} |
|
2317
|
|
|
|
|
|
|
: q{|"} . join(q{" "}, @_) . q{"}; |
|
2318
|
|
|
|
|
|
|
open PIPE, $cmd or die "Cannot fork: $!\n"; |
|
2319
|
|
|
|
|
|
|
binmode PIPE, ":encoding($encode)" if PERL58 && $encode; |
|
2320
|
|
|
|
|
|
|
return *PIPE; |
|
2321
|
|
|
|
|
|
|
} |
|
2322
|
|
|
|
|
|
|
|
|
2323
|
9133
|
|
|
|
|
22883861
|
my $pid = open PIPE, $mode; |
|
2324
|
9133
|
50
|
|
|
|
599706
|
die "Cannot fork: $!\n" unless defined $pid; |
|
2325
|
|
|
|
|
|
|
|
|
2326
|
9133
|
100
|
|
|
|
332832
|
if ($pid) { |
|
2327
|
|
|
|
|
|
|
# Parent process. Set the encoding layer and return the file handle. |
|
2328
|
8848
|
50
|
|
326
|
|
2363961
|
binmode PIPE, ":encoding($encode)" if PERL58 && $encode; |
|
|
326
|
|
|
|
|
14044
|
|
|
|
326
|
|
|
|
|
2242
|
|
|
|
326
|
|
|
|
|
23123
|
|
|
2329
|
8848
|
|
|
|
|
7120043
|
return *PIPE; |
|
2330
|
|
|
|
|
|
|
} else { |
|
2331
|
|
|
|
|
|
|
# Child process. Execute the commands. |
|
2332
|
285
|
0
|
|
|
|
0
|
exec @_ or die "Cannot exec $_[0]: $!\n"; |
|
2333
|
|
|
|
|
|
|
# Not reached. |
|
2334
|
|
|
|
|
|
|
} |
|
2335
|
|
|
|
|
|
|
} |
|
2336
|
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
############################################################################## |
|
2338
|
|
|
|
|
|
|
# This method passes its arguments to _pipe(), but then fetches each line |
|
2339
|
|
|
|
|
|
|
# off output from the returned file handle, safely strips out and replaces any |
|
2340
|
|
|
|
|
|
|
# newlines and carriage returns, and returns an array reference of those |
|
2341
|
|
|
|
|
|
|
# lines. |
|
2342
|
|
|
|
|
|
|
############################################################################## |
|
2343
|
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
sub _read_pipe { |
|
2345
|
2793
|
|
|
2793
|
|
6202
|
my $self = shift; |
|
2346
|
2793
|
|
|
|
|
17416
|
my $fh = $self->_pipe( $self->{svn_encoding}, '-|', @_ ); |
|
2347
|
2709
|
|
|
|
|
92441
|
local $/; my @lines = split /(?:\r\n|\r|\n)/, <$fh>; |
|
|
2709
|
|
|
|
|
9352496425
|
|
|
2348
|
2709
|
50
|
|
|
|
3583100
|
close $fh or warn "Child process exited: $?\n"; |
|
2349
|
2709
|
|
|
|
|
73952
|
return \@lines; |
|
2350
|
|
|
|
|
|
|
} |
|
2351
|
|
|
|
|
|
|
|
|
2352
|
|
|
|
|
|
|
############################################################################## |
|
2353
|
|
|
|
|
|
|
# This method is used for debugging output in various verbose modes. |
|
2354
|
|
|
|
|
|
|
############################################################################## |
|
2355
|
|
|
|
|
|
|
|
|
2356
|
0
|
|
|
0
|
|
0
|
sub _dbpnt { print ref(shift), ': ', join ' ', @_; } |
|
2357
|
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
############################################################################## |
|
2359
|
|
|
|
|
|
|
# This function is used to exit the program with an error if a parameter is |
|
2360
|
|
|
|
|
|
|
# missing. |
|
2361
|
|
|
|
|
|
|
############################################################################## |
|
2362
|
|
|
|
|
|
|
|
|
2363
|
|
|
|
|
|
|
sub _usage { |
|
2364
|
3
|
|
|
3
|
|
9
|
my ($msg) = @_; |
|
2365
|
|
|
|
|
|
|
|
|
2366
|
|
|
|
|
|
|
# Just die if the API is used. |
|
2367
|
3
|
50
|
|
|
|
54
|
die $msg if $0 !~ /\bsvnnotify(?:[.]bat)?$/; |
|
2368
|
|
|
|
|
|
|
|
|
2369
|
|
|
|
|
|
|
# Otherwise, tell 'em how to use it. |
|
2370
|
0
|
|
|
|
|
0
|
$msg =~ s/_/-/g; |
|
2371
|
0
|
|
|
|
|
0
|
$msg =~ s/(\s+")/$1--/g; |
|
2372
|
0
|
|
|
|
|
0
|
$msg =~ s/\bparameter\b/option/g; |
|
2373
|
0
|
|
|
|
|
0
|
require Pod::Usage; |
|
2374
|
0
|
|
|
|
|
0
|
Pod::Usage::pod2usage( |
|
2375
|
|
|
|
|
|
|
'-message' => $msg, |
|
2376
|
|
|
|
|
|
|
'-verbose' => 99, |
|
2377
|
|
|
|
|
|
|
'-sections' => '(?i:(Usage|Options))', |
|
2378
|
|
|
|
|
|
|
'-exitval' => 1, |
|
2379
|
|
|
|
|
|
|
); |
|
2380
|
|
|
|
|
|
|
} |
|
2381
|
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
package SVN::Notify::SMTP; |
|
2383
|
|
|
|
|
|
|
|
|
2384
|
|
|
|
|
|
|
sub get_handle { |
|
2385
|
4
|
|
|
4
|
|
39
|
my ($class, $notifier) = @_; |
|
2386
|
|
|
|
|
|
|
|
|
2387
|
|
|
|
|
|
|
# Load Net::SMTP::TLS. |
|
2388
|
4
|
|
|
|
|
195
|
require Net::SMTP::TLS; |
|
2389
|
4
|
|
|
|
|
49686
|
require Sys::Hostname; |
|
2390
|
4
|
100
|
|
|
|
8565
|
my $smtp = Net::SMTP::TLS->new( |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
$notifier->{smtp}, |
|
2392
|
|
|
|
|
|
|
Hello => Sys::Hostname::hostname(), |
|
2393
|
|
|
|
|
|
|
( $notifier->{smtp_port} ? ( Port => $notifier->{smtp_port} ) : () ), |
|
2394
|
|
|
|
|
|
|
( $notifier->{smtp_tls} ? () : (NoTLS => 1) ), |
|
2395
|
|
|
|
|
|
|
( $notifier->{smtp_user} ? ( User => $notifier->{smtp_user} ) : () ), |
|
2396
|
|
|
|
|
|
|
( $notifier->{smtp_pass} ? ( Password => $notifier->{smtp_pass} ) : () ), |
|
2397
|
|
|
|
|
|
|
( $notifier->{verbose} ? ( Debug => 1 ) : () ) |
|
2398
|
|
|
|
|
|
|
) or die "Unable to create SMTP object: $!"; |
|
2399
|
|
|
|
|
|
|
|
|
2400
|
4
|
|
|
|
|
383
|
$smtp->mail($notifier->{from}); |
|
2401
|
4
|
|
|
|
|
40
|
$smtp->to(map { split /\s*,\s*/ } @{ $notifier->{to} }); |
|
|
8
|
|
|
|
|
73
|
|
|
|
4
|
|
|
|
|
32
|
|
|
2402
|
4
|
|
|
|
|
55
|
$smtp->data; |
|
2403
|
4
|
|
|
|
|
84
|
tie local(*SMTP), $class, $smtp, $notifier; |
|
2404
|
|
|
|
|
|
|
# Perl 5.6 requires the escape. |
|
2405
|
4
|
|
|
|
|
44
|
return SVN::Notify::PERL58 ? *SMTP : \*SMTP; |
|
2406
|
|
|
|
|
|
|
} |
|
2407
|
|
|
|
|
|
|
|
|
2408
|
|
|
|
|
|
|
sub TIEHANDLE { |
|
2409
|
4
|
|
|
4
|
|
12
|
my ($class, $smtp, $notifier) = @_; |
|
2410
|
4
|
|
|
|
|
128
|
bless { smtp => $smtp, notifier => $notifier }, $class; |
|
2411
|
|
|
|
|
|
|
} |
|
2412
|
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
sub PRINT { |
|
2414
|
44
|
|
|
44
|
|
81
|
my $self = shift; |
|
2415
|
44
|
|
|
|
|
53
|
if (SVN::Notify::PERL58) { |
|
2416
|
44
|
|
|
|
|
204
|
my $encode = $self->{notifier}->encoding; |
|
2417
|
196
|
|
|
|
|
7519
|
return $self->{smtp}->datasend( map { |
|
2418
|
44
|
|
|
|
|
176
|
Encode::encode( $encode, $_ ) |
|
2419
|
|
|
|
|
|
|
} @_ ) |
|
2420
|
|
|
|
|
|
|
} |
|
2421
|
0
|
|
|
|
|
0
|
return $self->{smtp}->datasend(@_); |
|
2422
|
|
|
|
|
|
|
} |
|
2423
|
|
|
|
|
|
|
|
|
2424
|
|
|
|
|
|
|
sub PRINTF { |
|
2425
|
4
|
|
|
4
|
|
14
|
my $self = shift; |
|
2426
|
4
|
|
|
|
|
43
|
$self->PRINT( sprintf(shift, @_) ); |
|
2427
|
|
|
|
|
|
|
} |
|
2428
|
|
|
|
|
|
|
|
|
2429
|
|
|
|
|
|
|
sub CLOSE { |
|
2430
|
4
|
|
|
4
|
|
11
|
my $self = shift; |
|
2431
|
4
|
|
|
|
|
16
|
$self->{smtp}->dataend; |
|
2432
|
4
|
|
|
|
|
35
|
$self->{smtp}->quit; |
|
2433
|
|
|
|
|
|
|
} |
|
2434
|
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
1; |
|
2436
|
|
|
|
|
|
|
__END__ |