source: trunk/lib/Trac.cc @ 815

Last change on this file since 815 was 768, checked in by Peter Johansson, 13 years ago

Merged patch release 0.6.7 to trunk. Delta 0.6.7 - 0.6.6

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