source: trunk/lib/Trac.cc @ 309

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

added test for Trac class. fixes #189

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.6 KB
Line 
1// $Id: Trac.cc 309 2007-05-12 13:26:38Z 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, std::string("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  bool Trac::comment(std::string::const_iterator& first, 
114                     const std::string::const_iterator& last)
115  {
116    if (first==last)
117      return false;
118
119    const std::string::const_iterator first_orig(first);
120    if (match(first, last, std::string("comment:ticket:")).empty()){
121      first = first_orig;
122      return false;
123    }
124     
125    std::string ticket = match(first, last, AlNum());
126    if (ticket.empty() || first == last || *first != ':') {
127      first = first_orig;
128      return false;
129    }
130    ++first;
131    std::string comment = match(first, last, Digit());
132    if (comment.empty() ) {
133      first = first_orig;
134      return false;
135    }
136    std::string href(Configuration::instance().trac_root()+"ticket/"+ticket+
137                     "#comment:"+comment);
138    std::string str(first_orig, first);
139    hs_.stream() << anchor(href, str); 
140    return true;
141
142
143    const Configuration& conf = Configuration::instance();
144    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket+
145                           "#comment:"+comment,
146                           std::string(first_orig, first)); 
147    return true;
148
149  }
150
151
152  bool Trac::diff(std::string::const_iterator& first, 
153                  const std::string::const_iterator& last)
154  {
155    if (diff3(first, last))
156      return true;
157    if (diff1(first, last))
158      return true;
159    if (diff2(first, last))
160      return true;
161    return false;
162  }
163
164
165  bool Trac::diff1(std::string::const_iterator& first, 
166                   const std::string::const_iterator& last)
167  {
168    if (first==last)
169      return false;
170
171    const std::string::const_iterator first_orig(first);
172    if (match(first, last, std::string("diff:")).empty()){
173      first = first_orig;
174      return false;
175    }
176    std::string node = match(first, last, notChar('@'));
177    if (first==last){
178      first = first_orig;
179      return false;
180    }
181    ++first; 
182    std::string old_rev = match(first, last, AlNum());
183    if (old_rev.empty() || first == last || *first != ':') {
184      first = first_orig;
185      return false;
186    }
187    ++first;
188    std::string new_rev = match(first, last, AlNum());
189    if (new_rev.empty() ) {
190      first = first_orig;
191      return false;
192    }
193    std::string href;
194    if (node.empty())
195      href = std::string(Configuration::instance().trac_root()+
196                         "changeset?new="+new_rev+"&old="+old_rev);
197    else
198      href = std::string(Configuration::instance().trac_root()+
199                         "changeset?new="+new_rev+"&new_path="+node+"&old="+
200                         old_rev+"&old_path="+node);
201    hs_.stream() << anchor(href, std::string(first_orig, first)); 
202    return true;
203  }
204
205
206  bool Trac::diff2(std::string::const_iterator& first, 
207                   const std::string::const_iterator& last)
208  {
209    if (first==last)
210      return false;
211
212    const std::string::const_iterator first_orig(first);
213    if (match(first, last, std::string("diff:")).empty()){
214      first = first_orig;
215      return false;
216    }
217    std::string old_path(match(first, last, not2Str("//", " ")));
218    std::string new_path;
219    if (first==last || *first==' ')
220      new_path = old_path;
221    else {
222      first += 2;
223      new_path = match(first, last, notChar(' '));
224    }
225    if (new_path.empty() || old_path.empty()){
226      first = first_orig;
227      return false;
228    }
229    std::string href(Configuration::instance().trac_root()+
230                     "changeset?new_path="+new_path+"&old_path="+old_path);
231    hs_.stream() << anchor(href, std::string(first_orig, first)); 
232    return true;
233  }
234
235
236  bool Trac::diff3(std::string::const_iterator& first, 
237                   const std::string::const_iterator& last)
238  {
239    if (first==last)
240      return false;
241
242    const std::string::const_iterator first_orig(first);
243    if (match(first, last, std::string("diff:")).empty()){
244      first = first_orig;
245      return false;
246    }
247    std::string old_path(match(first, last, not2Char('@', ' ')));
248    if (*first!='@'){
249      first = first_orig;
250      return false;
251    }
252    ++first;
253    std::string old_rev(match(first, last, AlNum()));
254    if (match(first, last, std::string("//")).empty()) {
255      first = first_orig;
256      return false;
257    }
258    std::string new_path = match(first, last, not2Char('@', ' '));
259    if (*first!='@'){
260      first = first_orig;
261      return false;
262    }
263    ++first;
264    std::string new_rev(match(first, last, AlNum()));
265    if (new_rev.empty()){
266      first = first_orig;
267      return false;
268    }
269   
270    std::string href(Configuration::instance().trac_root()+
271                     "changeset?new="+new_rev+"&new_path="+new_path+
272                     "&old="+old_rev+"&old_path="+old_path);
273    hs_.stream() << anchor(href, std::string(first_orig, first)); 
274    return true;
275  }
276
277
278  bool Trac::log(std::string::const_iterator& first, 
279                 const std::string::const_iterator& last)
280  {
281    if (log1(first, last))
282      return true;
283    if (log2(first, last))
284      return true;
285    if (log3(first, last))
286      return true;
287    return false;
288  }
289
290
291  bool Trac::log1(std::string::const_iterator& first, 
292                     const std::string::const_iterator& last)
293  {
294    if (first==last)
295      return false;
296
297    const std::string::const_iterator first_orig(first);
298    if (*first != 'r')
299      return false;
300    ++first;
301
302    std::string stop_rev = match(first, last, AlNum());
303    if (stop_rev.empty() || first == last || *first != ':') {
304      first = first_orig;
305      return false;
306    }
307    ++first;
308    std::string rev = match(first, last, AlNum());
309    if (rev.empty() ) {
310      first = first_orig;
311      return false;
312    }
313    std::string href(Configuration::instance().trac_root()+"log/?rev="+
314                     rev+"&stop_rev="+stop_rev);
315    hs_.stream() << anchor(href, std::string(first_orig, first)); 
316    return true;
317  }
318
319
320  bool Trac::log2(std::string::const_iterator& first, 
321                     const std::string::const_iterator& last)
322  {
323    if (first==last)
324      return false;
325
326    const std::string::const_iterator first_orig(first);
327    if (*first != '[')
328      return false;
329    ++first;
330
331    std::string stop_rev = match(first, last, AlNum());
332    if (stop_rev.empty() || first == last || *first != ':') {
333      first = first_orig;
334      return false;
335    }
336    ++first;
337    std::string rev = match(first, last, AlNum());
338    if (rev.empty() || first == last || *first != ']') {
339      first = first_orig;
340      return false;
341    }
342    ++first; // eating ']'
343    std::string href(Configuration::instance().trac_root()+"log/?rev="+
344                     rev+"&stop_rev="+stop_rev);
345    hs_.stream() << anchor(href, std::string(first_orig, first)); 
346    return true;
347  }
348
349
350  bool Trac::log3(std::string::const_iterator& first, 
351                  const std::string::const_iterator& last)
352  {
353    if (first==last)
354      return false;
355
356    const std::string::const_iterator first_orig(first);
357
358    const std::string log_str("log:"); 
359    if (!match_begin(first, last, log_str)) {
360      first = first_orig;
361      return false;
362    }
363    first += log_str.size();
364    std::string node = match(first, last, not2Char('#', '@'));
365    ++first;
366    std::string stop_rev = match(first, last, AlNum());
367    if (stop_rev.empty() || first == last || *first != ':') {
368      first = first_orig;
369      return false;
370    }
371    ++first;
372    std::string rev = match(first, last, AlNum());
373    if (rev.empty() ) {
374      first = first_orig;
375      return false;
376    }
377    std::string href;
378    if (!node.empty() && node[0]=='/')
379      href = std::string(Configuration::instance().trac_root()+"log"+node+
380                         "?rev="+rev+"&stop_rev="+stop_rev);
381    else
382      href = std::string(Configuration::instance().trac_root()+"log/"+node+
383                         "?rev="+rev+"&stop_rev="+stop_rev);
384     
385    hs_.stream() << anchor(href, std::string(first_orig, first)); 
386    return true;
387  }
388
389
390  bool Trac::milestone(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
398    if (match(first, last, std::string("milestone:")).empty()){
399      first = first_orig;
400      return false;
401    }
402
403    const std::string::const_iterator milestone_begin(first);
404
405    // find the last alphanumerical char before next space (or last)
406    for (std::string::const_iterator i(first); i!=last && *i!=' '; ++i)
407      if (isalnum(*i)) 
408        first = i+1;
409
410    std::string milestone(milestone_begin, first);
411    if (milestone.empty()){
412      first = first_orig;
413      return false;
414    }
415
416    const Configuration& conf = Configuration::instance();
417    hs_.stream() << anchor(conf.trac_root()+"milestone/"+milestone,
418                           std::string(first_orig, first)); 
419    return true;
420  }
421
422
423  void Trac::print(std::string str)
424  {
425    std::string::const_iterator first(str.begin());
426    while (first!=str.end()) {
427      if (log(first, str.end()))
428        continue;
429      if (comment(first, str.end()))
430        continue;
431      if (ticket(first, str.end()))
432        continue;
433      if (changeset(first, str.end()))
434        continue;
435      if (diff(first, str.end()))
436        continue;
437      if (milestone(first, str.end()))
438        continue;
439      if (source(first, str.end()))
440        continue;
441      hs_ << *first;
442      ++first;
443    }
444  }
445
446
447  bool Trac::source(std::string::const_iterator& first, 
448                    const std::string::const_iterator& last)
449  {
450    if (first==last)
451      return false;
452
453    const std::string::const_iterator first_orig(first);
454
455    if (match(first, last, std::string("source:")).empty()){
456      first = first_orig;
457      return false;
458    }
459
460    std::string node;
461    std::string rev;
462    std::string line;
463    const std::string::const_iterator node_begin(first);
464
465    node = match(first, last, not2Char('@', ' '));
466    if (!node.empty() && node[0]=='/')
467      node = node.substr(1, node.size()-1); 
468 
469    if (*first == '@'){
470      ++first;
471      rev = match(first, last, AlNum());
472      if (*first == '#') {
473        ++first;
474        line = match(first, last, notChar(' '));
475      }
476    }
477
478    const Configuration& conf = Configuration::instance();
479    std::string href(conf.trac_root()+"browser/"+node);
480    if (!rev.empty()) {
481      href += "?rev="+rev;
482      if (!line.empty())
483        href += "#"+line;
484    }
485    hs_.stream() << anchor(href, std::string(first_orig, first)); 
486    return true;
487  }
488
489
490  bool Trac::ticket(std::string::const_iterator& first, 
491                    const std::string::const_iterator& last)
492  {
493    if (ticket1(first, last))
494      return true;
495    if (ticket2(first, last))
496      return true;
497    return false;
498  }
499
500
501  bool Trac::ticket1(std::string::const_iterator& first, 
502                     const std::string::const_iterator& last)
503  {
504    if (first==last)
505      return false;
506
507    const std::string::const_iterator first_orig(first);
508    if (*first != '#')
509      return false;
510    ++first;
511    std::string ticket = match(first, last, Digit());
512
513    if (ticket.empty()) {
514      first = first_orig;
515      return false;
516    }
517
518    const Configuration& conf = Configuration::instance();
519    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,
520                           std::string(first_orig, first)); 
521    return true;
522  }
523
524
525  bool Trac::ticket2(std::string::const_iterator& first, 
526                     const std::string::const_iterator& last)
527  {
528    if (first==last)
529      return false;
530
531    const std::string::const_iterator first_orig(first);
532
533    if (match(first, last, std::string("ticket:")).empty()){
534      first = first_orig; 
535      return false;
536    }
537    std::string ticket = match(first, last, Digit());
538
539    const Configuration& conf = Configuration::instance();
540    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,
541                           std::string(first_orig, first)); 
542    return true;
543  }
544
545
546}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.