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   234900 use strict;
  5         10  
  5         166  
4 5     5   29 use warnings;
  5         9  
  5         153  
5              
6 5     5   122 use 5.008;
  5         20  
  5         184  
7 5     5   25 use vars qw($VERSION);
  5         11  
  5         272  
8              
9             $VERSION = '0.60003';
10              
11 5     5   2193 use CGI ();
  5         17121  
  5         89  
12 5     5   1161 use IO::Scalar;
  5         12975  
  5         218  
13              
14             require SVN::Core;
15             require SVN::Ra;
16              
17 5     5   28 use base 'Class::Accessor';
  5         7  
  5         13539  
18              
19 5     5   14513 use SVN::RaWeb::Light::Help;
  5         13  
  5         17421  
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 36687 my $self = {};
32 41         66 my $class = shift;
33 41         96 bless $self, $class;
34 41         111 $self->_init(@_);
35 41         78 return $self;
36             }
37              
38             sub _init
39             {
40 41     41   51 my $self = shift;
41              
42 41         99 my %args = (@_);
43              
44 41         136 my $cgi = CGI->new();
45 41         710 $self->cgi($cgi);
46              
47 41         585 my $svn_ra =
48             SVN::Ra->new(
49             'url' => $args{'url'},
50             );
51              
52 41         891 $self->svn_ra($svn_ra);
53              
54 41   100     480 my $url_translations = $args{'url_translations'} || [];
55 41         66 $self->{'url_translations'} = $url_translations;
56              
57 41         75 return $self;
58             }
59              
60             sub _get_user_url_translations
61             {
62 23     23   27 my $self = shift;
63              
64 23         53 my @transes = $self->cgi()->param('trans_user');
65              
66 23         337 my @ret;
67 23         87 for my $i (0 .. $#transes)
68             {
69 11         16 my $elem = $transes[$i];
70 11 100       85 push @ret,
71             (($elem =~ /^([^:,]*),(.*)$/) ?
72             { 'label' => $1, 'url' => $2, } :
73             { 'label' => ("UserDef" . ($i+1)), 'url' => $elem, }
74             );
75             }
76 23         122 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   48 my $self = shift;
84              
85 26         61 my (%args) = (@_);
86              
87 26         70 my $cgi = $self->cgi();
88              
89 26         223 my $is_list_item = $args{'is_list_item'};
90              
91 26 100 100     89 if ($is_list_item && $cgi->param('trans_no_list'))
92             {
93 3         39 return [];
94             }
95              
96             return [
97 18         170 ($cgi->param('trans_hide_all') ?
98             () :
99 23         186 (@{$self->{'url_translations'}})
100             ),
101 23 100       130 @{$self->_get_user_url_translations()},
102             ];
103             }
104              
105             sub _get_mode
106             {
107 19     19   26 my $self = shift;
108              
109 19         38 my $mode = $self->cgi()->param("mode");
110              
111 19 100       335 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   33 my $self = shift;
118              
119 20         48 my $rev_param = $self->cgi()->param('rev');
120              
121 20         279 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       37 if (defined($rev_param))
126             {
127 2         4 $rev_num = abs(int($rev_param));
128             }
129             else
130             {
131 18         44 $rev_num = $self->svn_ra()->get_latest_revnum();
132             }
133              
134 20         263 $self->rev_num($rev_num);
135 20         199 $self->url_suffix($self->_get_url_suffix_with_extras());
136 20         187 $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   71 my $self = shift;
143 27         32 my $components = shift;
144              
145 27         64 my $query_string = $self->cgi->query_string();
146 27 100       299 if ($query_string eq "")
147             {
148 19 100       36 if (defined($components))
149             {
150 4         17 return "?" . $components;
151             }
152             else
153             {
154 15         58 return "";
155             }
156             }
157             else
158             {
159 8 100       52 if (defined($components))
160             {
161 1         6 return "?" . $query_string . ";" . $components;
162             }
163             else
164             {
165 7         32 return "?" . $query_string;
166             }
167             }
168             }
169              
170             sub _calc_path
171             {
172 19     19   28 my $self = shift;
173              
174 19         76 my $path = $self->cgi()->path_info();
175 19 100       221 if ($path eq "")
176             {
177             die +{
178             'callback' =>
179             sub {
180 1     1   5 $self->cgi()->script_name() =~ m{([^/]+)$};
181 1         18 print $self->cgi()->redirect("./$1/");
182             },
183 1         8 };
184             }
185 18 100       48 if ($path =~ /\/\//)
186             {
187 1     1   11 die +{ 'callback' => sub { $self->_multi_slashes(); } };
  1         3  
188             }
189              
190 17         69 $path =~ s!^/!!;
191              
192 17   100     117 $self->should_be_dir(($path eq "") || ($path =~ s{/$}{}));
193 17         175 $self->path($path);
194             }
195              
196             sub _get_correct_node_kind
197             {
198 13     13   14 my $self = shift;
199 13 100       28 return $self->should_be_dir() ? $SVN::Node::dir : $SVN::Node::file;
200             }
201              
202             sub _get_escaped_path
203             {
204 3     3   33 my $self = shift;
205 3         9 return _escape($self->path());
206             }
207              
208             sub _check_node_kind
209             {
210 15     15   49 my $self = shift;
211 15         20 my $node_kind = shift;
212              
213 15 100 100     90 if (($node_kind eq $SVN::Node::none) || ($node_kind eq $SVN::Node::unknown))
    100          
214             {
215             die +{
216             'callback' =>
217             sub {
218 2     2   7 print $self->cgi()->header();
219 2         74 print "Does not exist!";
220 2         21 print "

Does not exist!

";
221             },
222 2         15 };
223             }
224             elsif ($node_kind ne $self->_get_correct_node_kind())
225             {
226             die +{
227             'callback' =>
228             sub {
229 2     2   6 $self->path() =~ m{([^/]+)$};
230 2 100       28 print $self->cgi()->redirect(
231             ($node_kind eq $SVN::Node::dir) ?
232             "./$1/" :
233             "../$1"
234             );
235             },
236 2         38 };
237             }
238             }
239              
240             sub _get_esc_item_url_translations
241             {
242 27     27   32 my $self = shift;
243              
244 27 100       64 if (!exists($self->{'escaped_item_url_translations'}))
245             {
246 5         36 $self->{'escaped_item_url_translations'} =
247             [
248             (
249             map {
250 9         20 +{
251             'url' => _escape($_->{'url'}),
252             'label' => _escape($_->{'label'}),
253             }
254             }
255 9         9 @{$self->_get_url_translations('is_list_item' => 1)}
256             )
257             ];
258             }
259 27         178 return $self->{'escaped_item_url_translations'};
260             }
261              
262             sub _render_list_item
263             {
264 27     27   241 my ($self, $args) = (@_);
265              
266             return
267 13         82 qq(
  • 268
  • 27         56 qq(@{[$self->esc_url_suffix()]}">$args->{label}) .
    269             join("",
    270             map
    271             {
    272 27         276 " [{url}$args->{path_in_repos}\">$_->{label}]"
    273             }
    274 27         44 @{$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         89 return _escape($1);
    286             }
    287              
    288             sub _real_render_up_list_item
    289             {
    290 7     7   10 my $self = shift;
    291 7         23 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   10 my $self = shift;
    305             # If the path is the root - then we cannot have an upper directory
    306 9 100       27 if ($self->path() eq "")
    307             {
    308 2         21 return ();
    309             }
    310             else
    311             {
    312 7         68 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   32 my $self = shift;
    321              
    322 28         60 my $url = $self->path();
    323 28 100       243 if ($url ne "")
    324             {
    325 21         33 $url .= "/";
    326             }
    327 28         104 return $url;
    328             }
    329              
    330             sub _render_regular_list_item
    331             {
    332 20     20   23 my ($self, $entry) = @_;
    333              
    334 20         47 my $escaped_name = _escape($entry);
    335 20 100       141 if ($self->dir_contents->{$entry}->kind() eq $SVN::Node::dir)
    336             {
    337 9         108 $escaped_name .= "/";
    338             }
    339              
    340 40         106 return $self->_render_list_item(
    341             {
    342 20         145 (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   54 my $self = shift;
    352              
    353 8         20 my $top_url_translations =
    354             $self->_get_url_translations('is_list_item' => 0);
    355 8         13 my $ret = "";
    356 8 100       21 if (@$top_url_translations)
    357             {
    358 5         10 $ret .= "\n"; \n";
    359 5         8 foreach my $trans (@$top_url_translations)
    360             {
    361 8         19 my $url = $self->_get_normalized_path();
    362 8         26 my $escaped_url = _escape($trans->{'url'} . $url);
    363 8         66 my $escaped_label = _escape($trans->{'label'});
    364 8         64 $ret .= "
    $escaped_label
    365             }
    366 5         11 $ret .= "
    \n";
    367             }
    368 8         36 return $ret;
    369             }
    370              
    371             sub _render_dir_header
    372             {
    373 3     3   10 my $self = shift;
    374              
    375 3         10 my $title = "Revision ". $self->rev_num() . ": /" .
    376             $self->_get_escaped_path();
    377 3         44 my $ret = "";
    378 3         11 $ret .= $self->cgi()->header();
    379 3         84 $ret .= "$title\n";
    380 3         3 $ret .= "\n";
    381 3         9 $ret .="

    $title

    \n";
    382              
    383 3         21 return $ret;
    384             }
    385              
    386             sub _get_items_list_items_order
    387             {
    388 9     9   11 my $self = shift;
    389 9         12 return [ sort { $a cmp $b } keys(%{$self->dir_contents()}) ];
      12         126  
      9         19  
    390             }
    391              
    392             sub _get_items_list_regular_items
    393             {
    394 9     9   10 my $self = shift;
    395             return
    396 20         54 [map
    397             {
    398 9         20 $self->_render_regular_list_item($_)
    399             }
    400 9         10 (@{$self->_get_items_list_items_order()})
    401             ];
    402             }
    403              
    404             sub _get_items_list_items
    405             {
    406 9     9   10 my $self = shift;
    407             return
    408             [
    409 9         28 $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   101 my ($self) = @_;
    417 9         35 print "
      \n";
    418              
    419 9         86 print @{$self->_get_items_list_items()};
      9         25  
    420 9         136 print "\n";
    421             }
    422              
    423             sub _print_control_section
    424             {
    425 3     3   6 my $self = shift;
    426 3         8 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   30 my $self = shift;
    435              
    436 9         22 my ($dir_contents, $fetched_rev) =
    437             $self->svn_ra()->get_dir($self->path(), $self->rev_num());
    438 9         624 $self->dir_contents($dir_contents);
    439             }
    440              
    441             sub _process_dir
    442             {
    443 3     3   5 my $self = shift;
    444 3         10 $self->_get_dir();
    445 3         36 print $self->_render_dir_header();
    446 3         189 print $self->_render_top_url_translations_text();
    447 3         43 $self->_print_items_list();
    448 3         35 $self->_print_control_section();
    449 3         56 print "\n";
    450             }
    451              
    452             sub _process_file
    453             {
    454 2     2   4 my $self = shift;
    455              
    456 2         3 my $buffer = "";
    457 2         14 my $fh = IO::Scalar->new(\$buffer);
    458 2         69 my ($fetched_rev, $props)
    459             = $self->svn_ra()->get_file($self->path(), $self->rev_num(), $fh);
    460 2   100     79 print $self->cgi()->header(
    461             -type => ($props->{'svn:mime-type'} || 'text/plain')
    462             );
    463 2         60 print $buffer;
    464             }
    465              
    466             sub _process_help
    467             {
    468 1     1   1 my $self = shift;
    469              
    470 1         4 print $self->cgi()->header();
    471 1         28 SVN::RaWeb::Light::Help::print_data();
    472             }
    473              
    474             sub _real_run
    475             {
    476 19     19   22 my $self = shift;
    477 19         71 my $cgi = $self->cgi();
    478              
    479 19 100       190 if ($self->_get_mode() eq "help")
    480             {
    481 1         4 return $self->_process_help();
    482             }
    483 18 100       48 if ($cgi->param("panel"))
    484             {
    485 1         10 print $cgi->header();
    486 1         18 print <<"EOF";
    487            

    Not Implemented Yet

    488            

    Sorry but the control panel is not implemented yet.

    489            
    490            
    491             EOF
    492 1         11 return 0;
    493             }
    494              
    495 17         160 $self->_calc_rev_num();
    496 17         380 $self->_calc_path();
    497              
    498 15         152 my $node_kind =
    499             $self->svn_ra()->check_path($self->path(), $self->rev_num());
    500              
    501 15         424 $self->_check_node_kind($node_kind);
    502              
    503 11 100       123 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 847 my $self = shift;
    517              
    518 22         25 my @ret;
    519 22         26 eval {
    520 22         47 @ret = $self->_real_run();
    521             };
    522              
    523 22 100       213 if ($@)
    524             {
    525 9 100 100     69 if ((ref($@) eq "HASH") && (exists($@->{'callback'})))
    526             {
    527 6         17 return $@->{'callback'}->();
    528             }
    529             else
    530             {
    531 3         10 die $@;
    532             }
    533             }
    534             else
    535             {
    536 13         65 return @ret;
    537             }
    538             }
    539              
    540             sub _multi_slashes
    541             {
    542 2     2   7 my $self = shift;
    543 2         11 print $self->cgi()->header();
    544 2         212 print "Wrong URL!";
    545 2         27 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__