source: trunk/lib/Trac.cc @ 693

Last change on this file since 693 was 693, checked in by Jari Häkkinen, 13 years ago

Fixes #339. Change to GPLv3.

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