source: trunk/lib/Trac.cc @ 296

Last change on this file since 296 was 296, checked in by Peter Johansson, 14 years ago

Trac support. fixes #180

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.4 KB
Line 
1// $Id: Trac.cc 296 2007-05-08 19:44:10Z peter $
2
3/*
4  Copyright (C) 2007 Peter Johansson
5
6  This file is part of svndigest, http://lev.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "Trac.h"
25
26#include "Configuration.h"
27#include "HtmlStream.h"
28#include "html_utility.h"
29#include "utility.h"
30
31namespace theplu{
32namespace svndigest{
33
34  Trac::Trac(HtmlStream& hs)
35    : hs_(hs) 
36  {}
37
38  bool Trac::changeset(std::string::const_iterator& first, 
39                       const std::string::const_iterator& last)
40  {
41    if (changeset1(first, last))
42      return true;
43    if (changeset2(first, last))
44      return true;
45    if (changeset3(first, last))
46      return true;
47    return false;
48  }
49
50
51  bool Trac::changeset1(std::string::const_iterator& first, 
52                        const std::string::const_iterator& last)
53  {
54    if (first==last)
55      return false;
56    if (*first != 'r')
57      return false;
58    const std::string::const_iterator first_orig(first);
59    ++first;
60    std::string rev = match(first, last, Digit());
61    if (rev.empty()){
62      first = first_orig;
63      return false;
64    }
65    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
66    hs_.stream() << anchor(href, std::string(first_orig,first)); 
67    return true;
68  }
69
70
71  bool Trac::changeset2(std::string::const_iterator& first, 
72                        const std::string::const_iterator& last)
73  {
74    if (first==last)
75      return false;
76    if (*first != '[')
77      return false;
78    const std::string::const_iterator first_orig(first);
79    ++first;
80    std::string rev = match(first, last, Digit());
81    if (rev.empty() || first==last || *first!=']'){
82      first = first_orig;
83      return false;
84    }
85    ++first;
86    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
87    hs_.stream() << anchor(href, std::string(first_orig,first)); 
88    return true;
89  }
90
91
92  bool Trac::changeset3(std::string::const_iterator& first, 
93                        const std::string::const_iterator& last)
94  {
95    if (first==last)
96      return false;
97    const std::string::const_iterator first_orig(first);
98    if (match(first, last, Str("changeset:")).empty()){
99      first = first_orig;
100      return false;
101    }
102    std::string rev = match(first, last, Digit());
103    if (rev.empty()){
104      first = first_orig;
105      return false;
106    }
107    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
108    hs_.stream() << anchor(href, std::string(first_orig,first)); 
109    return true;
110  }
111
112
113  void Trac::print(std::string str)
114  {
115    std::string::const_iterator first(str.begin());
116    while (first!=str.end()) {
117      if (log(first, str.end()))
118        continue;
119      if (ticket(first, str.end()))
120        continue;
121      if (comment(first, str.end()))
122        continue;
123      if (changeset(first, str.end()))
124        continue;
125      if (diff(first, str.end()))
126        continue;
127      if (milestone(first, str.end()))
128        continue;
129      if (source(first, str.end()))
130        continue;
131      hs_ << *first;
132      ++first;
133    }
134  }
135
136
137  bool Trac::comment(std::string::const_iterator& first, 
138                     const std::string::const_iterator& last)
139  {
140    if (first==last)
141      return false;
142
143    const std::string::const_iterator first_orig(first);
144    if (match(first, last, Str("comment:ticket:")).empty()){
145      first = first_orig;
146      return false;
147    }
148     
149    std::string ticket = match(first, last, Digit());
150    if (ticket.empty() || first == last || *first != ':') {
151      first = first_orig;
152      return false;
153    }
154    ++first;
155    std::string comment = match(first, last, Digit());
156    if (comment.empty() ) {
157      first = first_orig;
158      return false;
159    }
160    std::string href(Configuration::instance().trac_root()+"ticket/"+ticket+
161                     "#comment:"+comment);
162    std::string str(first_orig, first);
163    hs_.stream() << anchor(href, str); 
164    return true;
165
166
167    const Configuration& conf = Configuration::instance();
168    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,"#"+ticket); 
169    return true;
170
171  }
172
173
174  bool Trac::milestone(std::string::const_iterator& first, 
175                       const std::string::const_iterator& last)
176  {
177    if (first==last)
178      return false;
179
180    const std::string::const_iterator first_orig(first);
181
182    if (match(first, last, Str("milestone:")).empty()){
183      first = first_orig;
184      return false;
185    }
186
187    const std::string::const_iterator milestone_begin;
188
189    // find the last alphanumerical char before next space (or last)
190    for (std::string::const_iterator i(first); i!=last && *i!=' '; ++i)
191      if (isalnum(*i)) 
192        first = i+1;
193
194    std::string milestone(milestone_begin, first);
195    if (milestone.empty()){
196      first = first_orig;
197      return false;
198    }
199
200    const Configuration& conf = Configuration::instance();
201    hs_.stream() << anchor(conf.trac_root()+"milestone/"+milestone,
202                           std::string(first_orig, first)); 
203    return true;
204  }
205
206
207  bool Trac::source(std::string::const_iterator& first, 
208                    const std::string::const_iterator& last)
209  {
210    if (first==last)
211      return false;
212
213    const std::string::const_iterator first_orig(first);
214
215    if (match(first, last, Str("source:")).empty()){
216      first = first_orig;
217      return false;
218    }
219
220    std::string node;
221    std::string rev;
222    std::string line;
223    const std::string::const_iterator node_begin(first);
224
225    node = match(first, last, not2Char('@', ' '));
226    if (!node.empty() && node[0]=='/')
227      node = node.substr(1, node.size()-1); 
228 
229    if (*first == '@'){
230      ++first;
231      rev = match(first, last, Digit());
232      if (*first == '#') {
233        ++first;
234        line = match(first, last, notChar(' '));
235      }
236    }
237
238    const Configuration& conf = Configuration::instance();
239    std::string href(conf.trac_root()+node);
240    if (!rev.empty()) {
241      href += "@"+rev;
242      if (!line.empty())
243        href += "#"+line;
244    }
245    hs_.stream() << anchor(href, std::string(first_orig, first)); 
246    return true;
247  }
248
249
250  bool Trac::ticket(std::string::const_iterator& first, 
251                    const std::string::const_iterator& last)
252  {
253    if (ticket1(first, last))
254      return true;
255    if (ticket2(first, last))
256      return true;
257    return false;
258  }
259
260
261  bool Trac::ticket1(std::string::const_iterator& first, 
262                     const std::string::const_iterator& last)
263  {
264    if (first==last)
265      return false;
266
267    const std::string::const_iterator first_orig(first);
268    if (*first != '#')
269      return false;
270    ++first;
271    std::string ticket = match(first, last, Digit());
272
273    if (ticket.empty()) {
274      first = first_orig;
275      return false;
276    }
277
278    const Configuration& conf = Configuration::instance();
279    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,
280                           std::string(first_orig, first)); 
281    return true;
282  }
283
284
285  bool Trac::ticket2(std::string::const_iterator& first, 
286                     const std::string::const_iterator& last)
287  {
288    if (first==last)
289      return false;
290
291    const std::string::const_iterator first_orig(first);
292
293    if (match(first, last, Str("ticket:")).empty()){
294      first = first_orig;
295      return false;
296    }
297     
298    std::string ticket = match(first, last, Digit());
299
300    const Configuration& conf = Configuration::instance();
301    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,"#"+ticket); 
302    return true;
303  }
304
305
306  bool Trac::diff(std::string::const_iterator& first, 
307                  const std::string::const_iterator& last)
308  {
309    if (diff1(first, last))
310      return true;
311    if (diff3(first, last))
312      return true;
313    if (diff2(first, last))
314      return true;
315    return false;
316  }
317
318
319  bool Trac::diff1(std::string::const_iterator& first, 
320                   const std::string::const_iterator& last)
321  {
322    if (first==last)
323      return false;
324
325    const std::string::const_iterator first_orig(first);
326    if (match(first, last, Str("diff:")).empty()){
327      first = first_orig;
328      return false;
329    }
330    std::string node = match(first, last, notChar('@'));
331    if (first==last){
332      first = first_orig;
333      return false;
334    }
335    ++first; 
336    std::string old_rev = match(first, last, Digit());
337    if (old_rev.empty() || first == last || *first != ':') {
338      first = first_orig;
339      return false;
340    }
341    ++first;
342    std::string new_rev = match(first, last, Digit());
343    if (new_rev.empty() ) {
344      first = first_orig;
345      return false;
346    }
347    std::string href;
348    if (node.empty())
349      href = std::string(Configuration::instance().trac_root()+
350                         "changeset?new="+new_rev+"&old="+old_rev);
351    else
352      href = std::string(Configuration::instance().trac_root()+
353                         "changeset?new="+new_rev+"&new_path="+node+"&old="+
354                         old_rev+"&oldpath="+node);
355    hs_.stream() << anchor(href, std::string(first_orig, first)); 
356    return true;
357  }
358
359
360  bool Trac::diff2(std::string::const_iterator& first, 
361                   const std::string::const_iterator& last)
362  {
363    if (first==last)
364      return false;
365
366    const std::string::const_iterator first_orig(first);
367    if (match(first, last, Str("diff:")).empty()){
368      first = first_orig;
369      return false;
370    }
371    std::string old_path(match(first, last, not2Str("//", " ")));
372    std::string new_path;
373    if (first==last || *first==' ')
374      new_path = old_path;
375    else {
376      first += 2;
377      new_path = match(first, last, notChar(' '));
378    }
379    if (new_path.empty() || old_path.empty()){
380      first = first_orig;
381      return false;
382    }
383    std::string href(Configuration::instance().trac_root()+
384                     "changeset?new_path="+new_path+"&old_path="+old_path);
385    hs_.stream() << anchor(href, std::string(first_orig, first)); 
386    return true;
387  }
388
389
390  bool Trac::diff3(std::string::const_iterator& first, 
391                   const std::string::const_iterator& last)
392  {
393    if (first==last)
394      return false;
395
396    const std::string::const_iterator first_orig(first);
397    if (match(first, last, Str("diff:")).empty()){
398      first = first_orig;
399      return false;
400    }
401    std::string old_path(match(first, last, not2Char('@', ' ')));
402    if (*first!='@'){
403      first = first_orig;
404      return false;
405    }
406    ++first;
407    std::string old_rev(match(first, last, Digit()));
408    if (!match_begin(first, first+1, std::string("//"))) {
409      first = first_orig;
410      return false;
411    }
412    first+2;
413    std::string new_path = match(first, last, not2Char('@', ' '));
414    if (*first!='@'){
415      first = first_orig;
416      return false;
417    }
418    ++first;
419    std::string new_rev(match(first, last, Digit()));
420    if (new_rev.empty()){
421      first = first_orig;
422      return false;
423    }
424   
425    std::string href(Configuration::instance().trac_root()+
426                     "changeset?new="+new_rev+"&new_path="+new_path+
427                     "&old="+old_rev+"&old_path="+old_path);
428    hs_.stream() << anchor(href, std::string(first_orig, first)); 
429    return true;
430  }
431
432
433  bool Trac::log(std::string::const_iterator& first, 
434                 const std::string::const_iterator& last)
435  {
436    if (log1(first, last))
437      return true;
438    if (log2(first, last))
439      return true;
440    if (log3(first, last))
441      return true;
442    return false;
443  }
444
445
446  bool Trac::log1(std::string::const_iterator& first, 
447                     const std::string::const_iterator& last)
448  {
449    if (first==last)
450      return false;
451
452    const std::string::const_iterator first_orig(first);
453    if (*first != 'r')
454      return false;
455    ++first;
456
457    std::string stop_rev = match(first, last, Digit());
458    if (stop_rev.empty() || first == last || *first != ':') {
459      first = first_orig;
460      return false;
461    }
462    ++first;
463    std::string rev = match(first, last, Digit());
464    if (rev.empty() ) {
465      first = first_orig;
466      return false;
467    }
468    std::string href(Configuration::instance().trac_root()+"log/?rev="+
469                     rev+"&stop_rev="+stop_rev);
470    hs_.stream() << anchor(href, std::string(first_orig, first)); 
471    return true;
472  }
473
474
475  bool Trac::log2(std::string::const_iterator& first, 
476                     const std::string::const_iterator& last)
477  {
478    if (first==last)
479      return false;
480
481    const std::string::const_iterator first_orig(first);
482    if (*first != '[')
483      return false;
484    ++first;
485
486    std::string stop_rev = match(first, last, Digit());
487    if (stop_rev.empty() || first == last || *first != ':') {
488      first = first_orig;
489      return false;
490    }
491    ++first;
492    std::string rev = match(first, last, Digit());
493    if (rev.empty() || first == last || *first != ']') {
494      first = first_orig;
495      return false;
496    }
497    std::string href(Configuration::instance().trac_root()+"log/?rev="+
498                     rev+"&stop_rev="+stop_rev);
499    hs_.stream() << anchor(href, std::string(first_orig, first)); 
500    return true;
501  }
502
503
504  bool Trac::log3(std::string::const_iterator& first, 
505                  const std::string::const_iterator& last)
506  {
507    if (first==last)
508      return false;
509
510    const std::string::const_iterator first_orig(first);
511
512    const std::string log_str("log:"); 
513    if (!match_begin(first, last, log_str)) {
514      first = first_orig;
515      return false;
516    }
517    first += log_str.size();
518    std::string node = match(first, last, not2Char('#', '@'));
519    ++first;
520    std::string stop_rev = match(first, last, Digit());
521    if (stop_rev.empty() || first == last || *first != ':') {
522      first = first_orig;
523      return false;
524    }
525    ++first;
526    std::string rev = match(first, last, Digit());
527    if (rev.empty() ) {
528      first = first_orig;
529      return false;
530    }
531    std::string href;
532    if (!node.empty() && node[0]=='/')
533      href = std::string(Configuration::instance().trac_root()+"log"+node+
534                         "?rev="+rev+"&stop_rev="+stop_rev);
535    else
536      href = std::string(Configuration::instance().trac_root()+"log/"+node+
537                         "?rev="+rev+"&stop_rev="+stop_rev);
538     
539    hs_.stream() << anchor(href, std::string(first_orig, first)); 
540    return true;
541  }
542
543}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.