File Coverage

blib/lib/SVN/RaWeb/Light.pm
Criterion Covered Total %
statement 218 218 100.0
branch 48 48 100.0
condition 16 16 100.0
subroutine 44 44 100.0
pod 2 2 100.0
total 328 328 100.0


line stmt bran cond sub pod time code
1             package SVN::RaWeb::Light;
2              
3 5     5   179694 use strict;
  5         13  
  5         235  
4 5     5   31 use warnings;
  5         8  
  5         188  
5              
6 5     5   108 use 5.008;
  5         22  
  5         262  
7 5     5   28 use vars qw($VERSION);
  5         8  
  5         326  
8              
9             $VERSION = '0.60004';
10              
11 5     5   1740 use CGI ();
  5         18012  
  5         98  
12 5     5   533 use IO::Scalar;
  5         8800  
  5         322  
13              
14             require SVN::Core;
15             require SVN::Ra;
16              
17 5     5   41 use base 'Class::Accessor';
  5         8  
  5         3265  
18              
19 5     5   11086 use SVN::RaWeb::Light::Help;
  5         9  
  5         11796  
20              
21             __PACKAGE__->mk_accessors(qw(cgi dir_contents esc_url_suffix path rev_num),
22             qw(should_be_dir svn_ra url_suffix));
23              
24             # Preloaded methods go here.
25              
26             # We alias _escape() to CGI::escapeHTML().
27             *_escape = \&CGI::escapeHTML;
28              
29             sub new
30             {
31 41     41 1 24524 my $self = {};
32 41         68 my $class = shift;
33 41         84 bless $self, $class;
34 41         93 $self->_init(@_);
35 41         75 return $self;
36             }
37              
38             sub _init
39             {
40 41     41   43 my $self = shift;
41              
42 41         80 my %args = (@_);
43              
44 41         122 my $cgi = CGI->new();
45 41         614 $self->cgi($cgi);
46              
47 41         523 my $svn_ra =
48             SVN::Ra->new(
49             'url' => $args{'url'},
50             );
51              
52 41         831 $self->svn_ra($svn_ra);
53              
54 41   100     397 my $url_translations = $args{'url_translations'} || [];
55 41         58 $self->{'url_translations'} = $url_translations;
56              
57 41         62 return $self;
58             }
59              
60             sub _get_user_url_translations
61             {
62 23     23   24 my $self = shift;
63              
64 23         42 my @transes = $self->cgi()->param('trans_user');
65              
66 23         274 my @ret;
67 23         58 for my $i (0 .. $#transes)
68             {
69 11         13 my $elem = $transes[$i];
70 11 100       91 push @ret,
71             (($elem =~ /^([^:,]*),(.*)$/) ?
72             { 'label' => $1, 'url' => $2, } :
73             { 'label' => ("UserDef" . ($i+1)), 'url' => $elem, }
74             );
75             }
76 23         92 return \@ret;
77             }
78              
79             # TODO :
80             # Create a way for the user to specify one extra url translation of his own.
81             sub _get_url_translations
82             {
83 26     26   42 my $self = shift;
84              
85 26         46 my (%args) = (@_);
86              
87 26         49 my $cgi = $self->cgi();
88              
89 26         188 my $is_list_item = $args{'is_list_item'};
90              
91 26 100 100     87 if ($is_list_item && $cgi->param('trans_no_list'))
92             {
93 3         33 return [];
94             }
95              
96             return [
97 18         151 ($cgi->param('trans_hide_all') ?
98             () :
99 23         95 (@{$self->{'url_translations'}})
100             ),
101 23 100       147 @{$self->_get_user_url_translations()},
102             ];
103             }
104              
105             sub _get_mode
106             {
107 19     19   21 my $self = shift;
108              
109 19         30 my $mode = $self->cgi()->param("mode");
110              
111 19 100       272 return (defined($mode) ? $mode : "view");
112             }
113              
114             # This function must be called before rev_num() and url_suffix() are valid.
115             sub _calc_rev_num
116             {
117 20     20   25 my $self = shift;
118              
119 20         39 my $rev_param = $self->cgi()->param('rev');
120              
121 20         211 my ($rev_num, $url_suffix);
122              
123             # If a revision is specified - get the tree out of it, and persist with
124             # it throughout the browsing session. Otherwise, get the latest revision.
125 20 100       33 if (defined($rev_param))
126             {
127 2         7 $rev_num = abs(int($rev_param));
128             }
129             else
130             {
131 18         82 $rev_num = $self->svn_ra()->get_latest_revnum();
132             }
133              
134 20         193 $self->rev_num($rev_num);
135 20         149 $self->url_suffix($self->_get_url_suffix_with_extras());
136 20         138 $self->esc_url_suffix(_escape($self->url_suffix()));
137             }
138              
139             # Gets the URL suffix calculated with optional extra components.
140             sub _get_url_suffix_with_extras
141             {
142 27     27   62 my $self = shift;
143 27         26 my $components = shift;
144              
145 27         51 my $query_string = $self->cgi->query_string();
146 27 100       245 if ($query_string eq "")
147             {
148 19 100       40 if (defined($components))
149             {
150 4         15 return "?" . $components;
151             }
152             else
153             {
154 15         39 return "";
155             }
156             }
157             else
158             {
159 8 100       40 if (defined($components))
160             {
161 1         6 return "?" . $query_string . ";" . $components;
162             }
163             else
164             {
165 7         35 return "?" . $query_string;
166             }
167             }
168             }
169              
170             sub _calc_path
171             {
172 19     19   24 my $self = shift;
173              
174 19         37 my $path = $self->cgi()->path_info();
175 19 100       157 if ($path eq "")
176             {
177             die +{
178             'callback' =>
179             sub {
180 1     1   2 $self->cgi()->script_name() =~ m{([^/]+)$};
181 1         18 print $self->cgi()->redirect("./$1/");
182             },
183 1         11 };
184             }
185 18 100       45 if ($path =~ /\/\//)
186             {
187 1     1   9 die +{ 'callback' => sub { $self->_multi_slashes(); } };
  1         3  
188             }
189              
190 17         68 $path =~ s!^/!!;
191              
192 17   100     107 $self->should_be_dir(($path eq "") || ($path =~ s{/$}{}));
193 17         132 $self->path($path);
194             }
195              
196             sub _get_correct_node_kind
197             {
198 13     13   15 my $self = shift;
199 13 100       34 return $self->should_be_dir() ? $SVN::Node::dir : $SVN::Node::file;
200             }
201              
202             sub _get_escaped_path
203             {
204 3     3   23 my $self = shift;
205 3         10 return _escape($self->path());
206             }
207              
208             sub _check_node_kind
209             {
210 15     15   17 my $self = shift;
211 15         15 my $node_kind = shift;
212              
213 15 100 100     69 if (($node_kind eq $SVN::Node::none) || ($node_kind eq $SVN::Node::unknown))
    100          
214             {
215             die +{
216             'callback' =>
217             sub {
218 2     2   5 print $self->cgi()->header();
219 2         47 print "Does not exist!";
220 2         12 print "

Does not exist!

";
221             },
222 2         13 };
223             }
224             elsif ($node_kind ne $self->_get_correct_node_kind())
225             {
226             die +{
227             'callback' =>
228             sub {
229 2     2   5 $self->path() =~ m{([^/]+)$};
230 2 100       27 print $self->cgi()->redirect(
231             ($node_kind eq $SVN::Node::dir) ?
232             "./$1/" :
233             "../$1"
234             );
235             },
236 2         27 };
237             }
238             }
239              
240             sub _get_esc_item_url_translations
241             {
242 27     27   21 my $self = shift;
243              
244 27 100       56 if (!exists($self->{'escaped_item_url_translations'}))
245             {
246 5         38 $self->{'escaped_item_url_translations'} =
247             [
248             (
249             map {
250 9         21 +{
251             'url' => _escape($_->{'url'}),
252             'label' => _escape($_->{'label'}),
253             }
254             }
255 9         8 @{$self->_get_url_translations('is_list_item' => 1)}
256             )
257             ];
258             }
259 27         136 return $self->{'escaped_item_url_translations'};
260             }
261              
262             sub _render_list_item
263             {
264 27     27   195 my ($self, $args) = (@_);
265              
266             return
267 13         68 qq(
  • 268
  • 27         64 qq(@{[$self->esc_url_suffix()]}">$args->{label}) .
    269             join("",
    270             map
    271             {
    272 27         220 " [{url}$args->{path_in_repos}\">$_->{label}]"
    273             }
    274 27         41 @{$self->_get_esc_item_url_translations()}
    275             ) .
    276             "\n";
    277             }
    278              
    279             sub _get_esc_up_path
    280             {
    281 7     7   7 my $self = shift;
    282              
    283 7         15 $self->path() =~ /^(.*?)[^\/]+$/;
    284              
    285 7         77 return _escape($1);
    286             }
    287              
    288             sub _real_render_up_list_item
    289             {
    290 7     7   9 my $self = shift;
    291 7         22 return $self->_render_list_item(
    292             {
    293             'link' => "../",
    294             'label' => "..",
    295             'path_in_repos' => $self->_get_esc_up_path(),
    296             }
    297             );
    298             }
    299              
    300             # The purpose of this function ios to get the list item of the ".." directory
    301             # that goes one level up in the repository.
    302             sub _render_up_list_item
    303             {
    304 9     9   8 my $self = shift;
    305             # If the path is the root - then we cannot have an upper directory
    306 9 100       21 if ($self->path() eq "")
    307             {
    308 2         13 return ();
    309             }
    310             else
    311             {
    312 7         58 return $self->_real_render_up_list_item();
    313             }
    314             }
    315              
    316             # This method gets the escaped path along with a potential trailing slash
    317             # (if it isn't empty)
    318             sub _get_normalized_path
    319             {
    320 28     28   26 my $self = shift;
    321              
    322 28         45 my $url = $self->path();
    323 28 100       170 if ($url ne "")
    324             {
    325 21         28 $url .= "/";
    326             }
    327 28         51 return $url;
    328             }
    329              
    330             sub _render_regular_list_item
    331             {
    332 20     20   20 my ($self, $entry) = @_;
    333              
    334 20         35 my $escaped_name = _escape($entry);
    335 20 100       114 if ($self->dir_contents->{$entry}->kind() eq $SVN::Node::dir)
    336             {
    337 9         79 $escaped_name .= "/";
    338             }
    339              
    340 40         72 return $self->_render_list_item(
    341             {
    342 20         110 (map { $_ => $escaped_name } qw(link label)),
    343             'path_in_repos' =>
    344             (_escape($self->_get_normalized_path()).$escaped_name),
    345             }
    346             );
    347             }
    348              
    349             sub _render_top_url_translations_text
    350             {
    351 8     8   49 my $self = shift;
    352              
    353 8         18 my $top_url_translations =
    354             $self->_get_url_translations('is_list_item' => 0);
    355 8         10 my $ret = "";
    356 8 100       18 if (@$top_url_translations)
    357             {
    358 5         9 $ret .= "\n"; \n";
    359 5         7 foreach my $trans (@$top_url_translations)
    360             {
    361 8         16 my $url = $self->_get_normalized_path();
    362 8         20 my $escaped_url = _escape($trans->{'url'} . $url);
    363 8         49 my $escaped_label = _escape($trans->{'label'});
    364 8         43 $ret .= "
    $escaped_label
    365             }
    366 5         9 $ret .= "
    \n";
    367             }
    368 8         31 return $ret;
    369             }
    370              
    371             sub _render_dir_header
    372             {
    373 3     3   4 my $self = shift;
    374              
    375 3         6 my $title = "Revision ". $self->rev_num() . ": /" .
    376             $self->_get_escaped_path();
    377 3         32 my $ret = "";
    378 3         7 $ret .= $self->cgi()->header();
    379 3         38 $ret .= "$title\n";
    380 3         3 $ret .= "\n";
    381 3         6 $ret .="

    $title

    \n";
    382              
    383 3         14 return $ret;
    384             }
    385              
    386             sub _get_items_list_items_order
    387             {
    388 9     9   9 my $self = shift;
    389 9         10 return [ sort { $a cmp $b } keys(%{$self->dir_contents()}) ];
      12         116  
      9         20  
    390             }
    391              
    392             sub _get_items_list_regular_items
    393             {
    394 9     9   9 my $self = shift;
    395             return
    396 20         38 [map
    397             {
    398 9         21 $self->_render_regular_list_item($_)
    399             }
    400 9         12 (@{$self->_get_items_list_items_order()})
    401             ];
    402             }
    403              
    404             sub _get_items_list_items
    405             {
    406 9     9   8 my $self = shift;
    407             return
    408             [
    409 9         27 $self->_render_up_list_item(),
    410 9         24 @{$self->_get_items_list_regular_items()},
    411             ];
    412             }
    413              
    414             sub _print_items_list
    415             {
    416 9     9   90 my ($self) = @_;
    417 9         19 print "
      \n";
    418              
    419 9         61 print @{$self->_get_items_list_items()};
      9         22  
    420 9         108 print "\n";
    421             }
    422              
    423             sub _print_control_section
    424             {
    425 3     3   4 my $self = shift;
    426 3         7 print "
      \n" .
    427             "
  • Show Help Screen
  • \n" .
    428             "
  • _get_url_suffix_with_extras("panel=1")) . "\">Show Control Panel
  • \n" .
    429             "\n";
    430             }
    431              
    432             sub _get_dir
    433             {
    434 9     9   24 my $self = shift;
    435              
    436 9         18 my ($dir_contents, $fetched_rev) =
    437             $self->svn_ra()->get_dir($self->path(), $self->rev_num());
    438 9         501 $self->dir_contents($dir_contents);
    439             }
    440              
    441             sub _process_dir
    442             {
    443 3     3   4 my $self = shift;
    444 3         8 $self->_get_dir();
    445 3         24 print $self->_render_dir_header();
    446 3         152 print $self->_render_top_url_translations_text();
    447 3         26 $self->_print_items_list();
    448 3         21 $self->_print_control_section();
    449 3         37 print "\n";
    450             }
    451              
    452             sub _process_file
    453             {
    454 2     2   2 my $self = shift;
    455              
    456 2         3 my $buffer = "";
    457 2         12 my $fh = IO::Scalar->new(\$buffer);
    458 2         61 my ($fetched_rev, $props)
    459             = $self->svn_ra()->get_file($self->path(), $self->rev_num(), $fh);
    460 2   100     69 print $self->cgi()->header(
    461             -type => ($props->{'svn:mime-type'} || 'text/plain')
    462             );
    463 2         48 print $buffer;
    464             }
    465              
    466             sub _process_help
    467             {
    468 1     1   2 my $self = shift;
    469              
    470 1         4 print $self->cgi()->header();
    471 1         33 SVN::RaWeb::Light::Help::print_data();
    472             }
    473              
    474             sub _real_run
    475             {
    476 19     19   16 my $self = shift;
    477 19         36 my $cgi = $self->cgi();
    478              
    479 19 100       151 if ($self->_get_mode() eq "help")
    480             {
    481 1         4 return $self->_process_help();
    482             }
    483 18 100       32 if ($cgi->param("panel"))
    484             {
    485 1         8 print $cgi->header();
    486 1         17 print <<"EOF";
    487            

    Not Implemented Yet

    488            

    Sorry but the control panel is not implemented yet.

    489            
    490            
    491             EOF
    492 1         8 return 0;
    493             }
    494              
    495 17         116 $self->_calc_rev_num();
    496 17         314 $self->_calc_path();
    497              
    498 15         106 my $node_kind =
    499             $self->svn_ra()->check_path($self->path(), $self->rev_num());
    500              
    501 15         311 $self->_check_node_kind($node_kind);
    502              
    503 11 100       89 if ($node_kind eq $SVN::Node::dir)
    504             {
    505 9         25 return $self->_process_dir();
    506             }
    507             # This means $node_kind eq $SVN::Node::file
    508             else
    509             {
    510 2         5 return $self->_process_file();
    511             }
    512             }
    513              
    514             sub run
    515             {
    516 22     22 1 502 my $self = shift;
    517              
    518 22         22 my @ret;
    519 22         21 eval {
    520 22         45 @ret = $self->_real_run();
    521             };
    522              
    523 22 100       177 if ($@)
    524             {
    525 9 100 100     39 if ((ref($@) eq "HASH") && (exists($@->{'callback'})))
    526             {
    527 6         12 return $@->{'callback'}->();
    528             }
    529             else
    530             {
    531 3         7 die $@;
    532             }
    533             }
    534             else
    535             {
    536 13         49 return @ret;
    537             }
    538             }
    539              
    540             sub _multi_slashes
    541             {
    542 2     2   7 my $self = shift;
    543 2         6 print $self->cgi()->header();
    544 2         213 print "Wrong URL!";
    545 2         25 print "

    Wrong URL - Multiple Adjacent Slashes (//) in the URL." .

    546             "";
    547             }
    548              
    549             # Autoload methods go after =cut, and are processed by the autosplit program.
    550              
    551             1;
    552              
    553              
    554             __END__