Annotation of /trunk/pkgtools/svn2cl-0.14/svn2cl.xsl
Parent Directory | Revision Log
Revision 3106 -
(hide annotations)
(download)
(as text)
Fri Mar 15 10:20:17 2019 UTC (5 years, 2 months ago) by niro
File MIME type: application/xml
File size: 16115 byte(s)
Fri Mar 15 10:20:17 2019 UTC (5 years, 2 months ago) by niro
File MIME type: application/xml
File size: 16115 byte(s)
-added working svn2cl version
1 | niro | 3106 | <?xml version="1.0" encoding="utf-8"?> |
2 | |||
3 | <!-- | ||
4 | |||
5 | svn2cl.xsl - xslt stylesheet for converting svn log to a normal | ||
6 | changelog | ||
7 | |||
8 | version 0.14 | ||
9 | |||
10 | Usage (replace ++ with two minus signs which aren't allowed | ||
11 | inside xml comments): | ||
12 | svn ++verbose ++xml log | \ | ||
13 | xsltproc ++stringparam strip-prefix `basename $(pwd)` \ | ||
14 | ++stringparam linelen 75 \ | ||
15 | ++stringparam groupbyday yes \ | ||
16 | ++stringparam separate-daylogs yes \ | ||
17 | ++stringparam include-rev yes \ | ||
18 | ++stringparam include-actions yes \ | ||
19 | ++stringparam breakbeforemsg yes/2 \ | ||
20 | ++stringparam reparagraph yes \ | ||
21 | ++stringparam authorsfile FILE \ | ||
22 | ++stringparam ignore-message-starting \ | ||
23 | svn2cl.xsl - > ChangeLog | ||
24 | |||
25 | This file is based on several implementations of this conversion | ||
26 | that I was not completely happy with and some other common | ||
27 | xslt constructs found on the web. | ||
28 | |||
29 | Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 Arthur de Jong. | ||
30 | |||
31 | Redistribution and use in source and binary forms, with or without | ||
32 | modification, are permitted provided that the following conditions | ||
33 | are met: | ||
34 | 1. Redistributions of source code must retain the above copyright | ||
35 | notice, this list of conditions and the following disclaimer. | ||
36 | 2. Redistributions in binary form must reproduce the above copyright | ||
37 | notice, this list of conditions and the following disclaimer in | ||
38 | the documentation and/or other materials provided with the | ||
39 | distribution. | ||
40 | 3. The name of the author may not be used to endorse or promote | ||
41 | products derived from this software without specific prior | ||
42 | written permission. | ||
43 | |||
44 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
45 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
46 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
47 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
48 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
49 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
50 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
51 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
52 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
53 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
54 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
55 | |||
56 | --> | ||
57 | |||
58 | <xsl:stylesheet | ||
59 | version="1.0" | ||
60 | xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | ||
61 | |||
62 | <xsl:output | ||
63 | method="text" | ||
64 | encoding="utf-8" | ||
65 | media-type="text/plain" | ||
66 | omit-xml-declaration="yes" | ||
67 | standalone="yes" | ||
68 | indent="no" /> | ||
69 | |||
70 | <xsl:strip-space elements="*" /> | ||
71 | |||
72 | <!-- the prefix of pathnames to strip --> | ||
73 | <xsl:param name="strip-prefix" select="'/'" /> | ||
74 | |||
75 | <!-- the length of a line to wrap messages at --> | ||
76 | <xsl:param name="linelen" select="75" /> | ||
77 | |||
78 | <!-- whether entries should be grouped by day --> | ||
79 | <xsl:param name="groupbyday" select="'no'" /> | ||
80 | |||
81 | <!-- whether to seperate log messages by empty lines --> | ||
82 | <xsl:param name="separate-daylogs" select="'no'" /> | ||
83 | |||
84 | <!-- whether a revision number should be included --> | ||
85 | <xsl:param name="include-rev" select="'no'" /> | ||
86 | |||
87 | <!-- whether aaction labels should be added to files --> | ||
88 | <xsl:param name="include-actions" select="'no'" /> | ||
89 | |||
90 | <!-- whether the log message should start on a new line --> | ||
91 | <xsl:param name="breakbeforemsg" select="'no'" /> | ||
92 | |||
93 | <!-- whether the message should be rewrapped within one paragraph --> | ||
94 | <xsl:param name="reparagraph" select="'no'" /> | ||
95 | |||
96 | <!-- whether certain messages should be ignored --> | ||
97 | <xsl:param name="ignore-message-starting" select="''" /> | ||
98 | |||
99 | <!-- location of authors file if any --> | ||
100 | <xsl:param name="authorsfile" select="''" /> | ||
101 | <xsl:key name="author-lookup" match="author" use="@uid" /> | ||
102 | <xsl:variable name="authors-top" select="document($authorsfile)/authors" /> | ||
103 | |||
104 | <!-- determin the path part to strip --> | ||
105 | <xsl:variable name="strip-path"> | ||
106 | <!-- if strip-prefix does not start with a slash, prepend it --> | ||
107 | <xsl:if test="not(starts-with($strip-prefix,'/'))"> | ||
108 | <xsl:text>/</xsl:text> | ||
109 | </xsl:if> | ||
110 | <!-- the prefix itself --> | ||
111 | <xsl:value-of select="$strip-prefix" /> | ||
112 | <!-- if strip-prefix does not end with a slash, append it --> | ||
113 | <xsl:if test="substring($strip-prefix,string-length($strip-prefix),1)!='/'"> | ||
114 | <xsl:text>/</xsl:text> | ||
115 | </xsl:if> | ||
116 | </xsl:variable> | ||
117 | |||
118 | <!-- match the topmost log entry --> | ||
119 | <xsl:template match="log"> | ||
120 | <xsl:choose> | ||
121 | <xsl:when test="$ignore-message-starting != ''"> | ||
122 | <!-- only handle logentries with don't contain the string --> | ||
123 | <xsl:apply-templates select="logentry[not(starts-with(msg,$ignore-message-starting))]" /> | ||
124 | </xsl:when> | ||
125 | <xsl:otherwise> | ||
126 | <xsl:apply-templates select="logentry" /> | ||
127 | </xsl:otherwise> | ||
128 | </xsl:choose> | ||
129 | <!-- add newlines at the end of the changelog --> | ||
130 | <xsl:text> </xsl:text> | ||
131 | </xsl:template> | ||
132 | |||
133 | <!-- format one entry from the log --> | ||
134 | <xsl:template match="logentry"> | ||
135 | <xsl:choose> | ||
136 | <!-- if we're grouping we should omit some headers --> | ||
137 | <xsl:when test="$groupbyday='yes'"> | ||
138 | <!-- fetch previous entry's date --> | ||
139 | <xsl:variable name="prevdate"> | ||
140 | <xsl:apply-templates select="preceding-sibling::logentry[position()=1]/date" /> | ||
141 | </xsl:variable> | ||
142 | <!-- fetch previous entry's author --> | ||
143 | <xsl:variable name="prevauthor"> | ||
144 | <xsl:value-of select="normalize-space(preceding-sibling::logentry[position()=1]/author)" /> | ||
145 | </xsl:variable> | ||
146 | <!-- fetch this entry's date --> | ||
147 | <xsl:variable name="date"> | ||
148 | <xsl:apply-templates select="date" /> | ||
149 | </xsl:variable> | ||
150 | <!-- fetch this entry's author --> | ||
151 | <xsl:variable name="author"> | ||
152 | <xsl:value-of select="normalize-space(author)" /> | ||
153 | </xsl:variable> | ||
154 | <!-- check if header is changed --> | ||
155 | <xsl:if test="($prevdate!=$date) or ($prevauthor!=$author)"> | ||
156 | <!-- add newline --> | ||
157 | <xsl:if test="not(position()=1)"> | ||
158 | <xsl:text> </xsl:text> | ||
159 | </xsl:if> | ||
160 | <!-- date --> | ||
161 | <xsl:value-of select="$date" /> | ||
162 | <!-- two spaces --> | ||
163 | <xsl:text>  </xsl:text> | ||
164 | <!-- author's name --> | ||
165 | <xsl:apply-templates select="author" /> | ||
166 | <!-- two newlines --> | ||
167 | <xsl:text> </xsl:text> | ||
168 | <xsl:if test="$separate-daylogs!='yes'"><xsl:text> </xsl:text></xsl:if> | ||
169 | </xsl:if> | ||
170 | </xsl:when> | ||
171 | <!-- write the log header --> | ||
172 | <xsl:otherwise> | ||
173 | <!-- add newline --> | ||
174 | <xsl:if test="not(position()=1)"> | ||
175 | <xsl:text> </xsl:text> | ||
176 | </xsl:if> | ||
177 | <!-- date --> | ||
178 | <xsl:apply-templates select="date" /> | ||
179 | <!-- two spaces --> | ||
180 | <xsl:text>  </xsl:text> | ||
181 | <!-- author's name --> | ||
182 | <xsl:apply-templates select="author" /> | ||
183 | <!-- two newlines --> | ||
184 | <xsl:text> </xsl:text> | ||
185 | </xsl:otherwise> | ||
186 | </xsl:choose> | ||
187 | <!-- get paths string --> | ||
188 | <xsl:variable name="paths"> | ||
189 | <xsl:apply-templates select="paths" /> | ||
190 | </xsl:variable> | ||
191 | <!-- get revision number --> | ||
192 | <xsl:variable name="rev"> | ||
193 | <xsl:if test="$include-rev='yes'"> | ||
194 | <xsl:text>[r</xsl:text> | ||
195 | <xsl:value-of select="@revision" /> | ||
196 | <xsl:text>] </xsl:text> | ||
197 | </xsl:if> | ||
198 | </xsl:variable> | ||
199 | <!-- trim trailing newlines --> | ||
200 | <xsl:variable name="msg"> | ||
201 | <!-- add a line break before the log message --> | ||
202 | <xsl:choose> | ||
203 | <xsl:when test="$breakbeforemsg='yes'"> | ||
204 | <xsl:text> </xsl:text> | ||
205 | </xsl:when> | ||
206 | <xsl:when test="number($breakbeforemsg)>0"> | ||
207 | <xsl:call-template name="newlines"> | ||
208 | <xsl:with-param name="count" select="number($breakbeforemsg)" /> | ||
209 | </xsl:call-template> | ||
210 | </xsl:when> | ||
211 | </xsl:choose> | ||
212 | <xsl:call-template name="trim-newln"> | ||
213 | <xsl:with-param name="txt" select="msg" /> | ||
214 | </xsl:call-template> | ||
215 | </xsl:variable> | ||
216 | <!-- add newline here if separate-daylogs is in effect --> | ||
217 | <xsl:if test="$groupbyday='yes' and $separate-daylogs='yes'"><xsl:text> </xsl:text></xsl:if> | ||
218 | <!-- first line is indented (other indents are done in wrap template) --> | ||
219 | <xsl:text>	* </xsl:text> | ||
220 | <!-- set up the text to wrap --> | ||
221 | <xsl:variable name="txt"> | ||
222 | <xsl:value-of select="$rev" /> | ||
223 | <xsl:if test="$paths!=''"> | ||
224 | <xsl:value-of select="concat($paths,': ')" /> | ||
225 | </xsl:if> | ||
226 | <xsl:value-of select="$msg" /> | ||
227 | </xsl:variable> | ||
228 | <!-- print the paths and message nicely wrapped --> | ||
229 | <xsl:call-template name="wrap"> | ||
230 | <xsl:with-param name="txt" select="$txt" /> | ||
231 | </xsl:call-template> | ||
232 | </xsl:template> | ||
233 | |||
234 | <!-- format date --> | ||
235 | <xsl:template match="date"> | ||
236 | <xsl:variable name="date" select="normalize-space(.)" /> | ||
237 | <!-- output date part --> | ||
238 | <xsl:value-of select="substring($date,1,10)" /> | ||
239 | <!-- output time part --> | ||
240 | <xsl:if test="$groupbyday!='yes'"> | ||
241 | <xsl:text> </xsl:text> | ||
242 | <xsl:value-of select="substring($date,12,5)" /> | ||
243 | </xsl:if> | ||
244 | </xsl:template> | ||
245 | |||
246 | <!-- format author --> | ||
247 | <xsl:template match="author"> | ||
248 | <xsl:variable name="uid" select="normalize-space(.)" /> | ||
249 | <!-- try to lookup author in authorsfile --> | ||
250 | <xsl:choose> | ||
251 | <xsl:when test="$authorsfile!=''"> | ||
252 | <xsl:for-each select="$authors-top"> | ||
253 | <xsl:variable name="author" select="key('author-lookup',$uid)" /> | ||
254 | <!-- present result --> | ||
255 | <xsl:choose> | ||
256 | <xsl:when test="string($author/.)"> | ||
257 | <xsl:apply-templates select="$author/node()" mode="copy" /> | ||
258 | </xsl:when> | ||
259 | <xsl:otherwise> | ||
260 | <xsl:value-of select="$uid" /> | ||
261 | </xsl:otherwise> | ||
262 | </xsl:choose> | ||
263 | </xsl:for-each> | ||
264 | </xsl:when> | ||
265 | <xsl:otherwise> | ||
266 | <xsl:value-of select="$uid" /> | ||
267 | </xsl:otherwise> | ||
268 | </xsl:choose> | ||
269 | </xsl:template> | ||
270 | |||
271 | <!-- copy but normalize text --> | ||
272 | <xsl:template match="text()" mode="copy"> | ||
273 | <xsl:value-of select="normalize-space(.)" /> | ||
274 | </xsl:template> | ||
275 | |||
276 | <!-- simple copy template --> | ||
277 | <xsl:template match="@*|node()" mode="copy"> | ||
278 | <xsl:copy> | ||
279 | <xsl:apply-templates select="@*|node()" mode="copy" /> | ||
280 | </xsl:copy> | ||
281 | </xsl:template> | ||
282 | |||
283 | <!-- present a list of paths names --> | ||
284 | <xsl:template match="paths"> | ||
285 | <xsl:choose> | ||
286 | <!-- only handle paths that begin with the path and strip the path --> | ||
287 | <xsl:when test="$strip-prefix != ''"> | ||
288 | <!-- filter on all entries within directory --> | ||
289 | <xsl:for-each select="path[starts-with(concat(normalize-space(.),'/'),$strip-path)]"> | ||
290 | <xsl:sort select="normalize-space(.)" data-type="text" /> | ||
291 | <!-- unless we are the first entry, add a comma --> | ||
292 | <xsl:if test="not(position()=1)"> | ||
293 | <xsl:text>, </xsl:text> | ||
294 | </xsl:if> | ||
295 | <!-- get path part --> | ||
296 | <xsl:variable name="path" select="substring(normalize-space(.),string-length($strip-path)+1)" /> | ||
297 | <!-- translate empty string to dot and print result --> | ||
298 | <xsl:if test="$path = ''"> | ||
299 | <xsl:text>.</xsl:text> | ||
300 | </xsl:if> | ||
301 | <xsl:value-of select="$path" /> | ||
302 | <!-- add the action flag --> | ||
303 | <xsl:if test="$include-actions='yes'"> | ||
304 | <xsl:apply-templates select="." mode="action"/> | ||
305 | </xsl:if> | ||
306 | </xsl:for-each> | ||
307 | </xsl:when> | ||
308 | <!-- print a simple list of all paths --> | ||
309 | <xsl:otherwise> | ||
310 | <xsl:for-each select="path"> | ||
311 | <xsl:sort select="normalize-space(.)" data-type="text" /> | ||
312 | <!-- unless we are the first entry, add a comma --> | ||
313 | <xsl:if test="not(position()=1)"> | ||
314 | <xsl:text>, </xsl:text> | ||
315 | </xsl:if> | ||
316 | <!-- print the path name --> | ||
317 | <xsl:value-of select="normalize-space(.)" /> | ||
318 | <!-- add the action flag --> | ||
319 | <xsl:if test="$include-actions='yes'"> | ||
320 | <xsl:apply-templates select="." mode="action"/> | ||
321 | </xsl:if> | ||
322 | </xsl:for-each> | ||
323 | </xsl:otherwise> | ||
324 | </xsl:choose> | ||
325 | </xsl:template> | ||
326 | |||
327 | <xsl:template match="path" mode="action"> | ||
328 | <xsl:choose> | ||
329 | <xsl:when test="@action='D'"> | ||
330 | <xsl:text>[DEL]</xsl:text> | ||
331 | </xsl:when> | ||
332 | <xsl:when test="@copyfrom-path"> | ||
333 | <xsl:text>[CPY]</xsl:text> | ||
334 | </xsl:when> | ||
335 | <xsl:when test="@action='A'"> | ||
336 | <xsl:text>[ADD]</xsl:text> | ||
337 | </xsl:when> | ||
338 | </xsl:choose> | ||
339 | </xsl:template> | ||
340 | |||
341 | <!-- string-wrapping template --> | ||
342 | <xsl:template name="wrap"> | ||
343 | <xsl:param name="txt" /> | ||
344 | <xsl:variable name="normtxt" select="normalize-space($txt)" /> | ||
345 | <xsl:choose> | ||
346 | <xsl:when test="contains($txt,' ')"> | ||
347 | <!-- text contains newlines, do the first line --> | ||
348 | <xsl:call-template name="wrap"> | ||
349 | <xsl:with-param name="txt" select="substring-before($txt,' ')" /> | ||
350 | </xsl:call-template> | ||
351 | <!-- print tab --> | ||
352 | <xsl:text>	  </xsl:text> | ||
353 | <!-- wrap the rest of the text --> | ||
354 | <xsl:call-template name="wrap"> | ||
355 | <xsl:with-param name="txt" select="substring-after($txt,' ')" /> | ||
356 | </xsl:call-template> | ||
357 | </xsl:when> | ||
358 | <xsl:when test="(string-length($normtxt) < (($linelen)-9)) or not(contains($normtxt,' '))"> | ||
359 | <!-- this is easy, nothing to do --> | ||
360 | <xsl:value-of select="$normtxt" /> | ||
361 | <!-- add newline --> | ||
362 | <xsl:text> </xsl:text> | ||
363 | </xsl:when> | ||
364 | <xsl:otherwise> | ||
365 | <!-- find the first line --> | ||
366 | <xsl:variable name="tmp" select="substring($normtxt,1,(($linelen)-9))" /> | ||
367 | <xsl:variable name="line"> | ||
368 | <xsl:choose> | ||
369 | <!-- if our attempt contains spaces wrap on that --> | ||
370 | <xsl:when test="contains($tmp,' ')"> | ||
371 | <xsl:call-template name="find-line"> | ||
372 | <xsl:with-param name="txt" select="$tmp" /> | ||
373 | </xsl:call-template> | ||
374 | </xsl:when> | ||
375 | <!-- otherwise use the first non-space characters from the text --> | ||
376 | <xsl:otherwise> | ||
377 | <xsl:value-of select="substring-before($normtxt,' ')" /> | ||
378 | </xsl:otherwise> | ||
379 | </xsl:choose> | ||
380 | </xsl:variable> | ||
381 | <!-- print line --> | ||
382 | <xsl:value-of select="$line" /> | ||
383 | <!-- print newline and tab --> | ||
384 | <xsl:text> 	  </xsl:text> | ||
385 | <!-- wrap the rest of the text --> | ||
386 | <xsl:call-template name="wrap"> | ||
387 | <xsl:with-param name="txt" select="normalize-space(substring($normtxt,string-length($line)+1))" /> | ||
388 | </xsl:call-template> | ||
389 | </xsl:otherwise> | ||
390 | </xsl:choose> | ||
391 | </xsl:template> | ||
392 | |||
393 | <!-- template to trim line to contain space as last char --> | ||
394 | <xsl:template name="find-line"> | ||
395 | <xsl:param name="txt" /> | ||
396 | <xsl:choose> | ||
397 | <xsl:when test="substring($txt,string-length($txt),1)=' '"> | ||
398 | <xsl:value-of select="substring($txt,1,string-length($txt)-1)" /> | ||
399 | </xsl:when> | ||
400 | <xsl:otherwise> | ||
401 | <xsl:call-template name="find-line"> | ||
402 | <xsl:with-param name="txt" select="substring($txt,1,string-length($txt)-1)" /> | ||
403 | </xsl:call-template> | ||
404 | </xsl:otherwise> | ||
405 | </xsl:choose> | ||
406 | </xsl:template> | ||
407 | |||
408 | <!-- template to trim trailing and starting newlines --> | ||
409 | <xsl:template name="trim-newln"> | ||
410 | <xsl:param name="txt" /> | ||
411 | <xsl:choose> | ||
412 | <!-- find starting newlines --> | ||
413 | <xsl:when test="substring($txt,1,1) = ' '"> | ||
414 | <xsl:call-template name="trim-newln"> | ||
415 | <xsl:with-param name="txt" select="substring($txt,2)" /> | ||
416 | </xsl:call-template> | ||
417 | </xsl:when> | ||
418 | <!-- find trailing newlines --> | ||
419 | <xsl:when test="substring($txt,string-length($txt),1) = ' '"> | ||
420 | <xsl:call-template name="trim-newln"> | ||
421 | <xsl:with-param name="txt" select="substring($txt,1,string-length($txt)-1)" /> | ||
422 | </xsl:call-template> | ||
423 | </xsl:when> | ||
424 | <!-- if the message has paragraphs, find the first one --> | ||
425 | <xsl:when test="$reparagraph='yes' and contains($txt,' ')"> | ||
426 | <!-- remove newlines from first paragraph --> | ||
427 | <xsl:value-of select="normalize-space(substring-before($txt,' '))" /> | ||
428 | <!-- paragraph separator --> | ||
429 | <xsl:text> </xsl:text> | ||
430 | <!-- do the rest of the text --> | ||
431 | <xsl:call-template name="trim-newln"> | ||
432 | <xsl:with-param name="txt" select="substring-after($txt,' ')" /> | ||
433 | </xsl:call-template> | ||
434 | </xsl:when> | ||
435 | <!-- remove more single newlines --> | ||
436 | <xsl:when test="$reparagraph='yes'"> | ||
437 | <xsl:value-of select="normalize-space($txt)" /> | ||
438 | </xsl:when> | ||
439 | <!-- no newlines found, we're done --> | ||
440 | <xsl:otherwise> | ||
441 | <xsl:value-of select="$txt" /> | ||
442 | </xsl:otherwise> | ||
443 | </xsl:choose> | ||
444 | </xsl:template> | ||
445 | |||
446 | <!-- insert a number of newlines --> | ||
447 | <xsl:template name="newlines"> | ||
448 | <xsl:param name="count" /> | ||
449 | <xsl:text> </xsl:text> | ||
450 | <xsl:if test="$count>1"> | ||
451 | <xsl:call-template name="newlines"> | ||
452 | <xsl:with-param name="count" select="($count)-1" /> | ||
453 | </xsl:call-template> | ||
454 | </xsl:if> | ||
455 | </xsl:template> | ||
456 | |||
457 | </xsl:stylesheet> |