File Coverage

blib/lib/Apache/Sling/Content.pm
Criterion Covered Total %
statement 112 240 46.6
branch 27 74 36.4
condition 1 3 33.3
subroutine 26 29 89.6
pod 14 18 77.7
total 180 364 49.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package Apache::Sling::Content;
4              
5 4     4   6835 use 5.008001;
  4         15  
  4         213  
6 4     4   26 use strict;
  4         6  
  4         137  
7 4     4   21 use warnings;
  4         9  
  4         172  
8 4     4   21 use Carp;
  4         10  
  4         325  
9 4     4   4725 use Getopt::Long qw(:config bundling);
  4         2921975  
  4         29  
10 4     4   1044 use Apache::Sling;
  4         9  
  4         192  
11 4     4   2935 use Apache::Sling::ContentUtil;
  4         12  
  4         209  
12 4     4   23 use Apache::Sling::Print;
  4         10  
  4         149  
13 4     4   24 use Apache::Sling::Request;
  4         7  
  4         158  
14              
15             require Exporter;
16              
17 4     4   19 use base qw(Exporter);
  4         9  
  4         327850  
18              
19             our @EXPORT_OK = qw(command_line);
20              
21             our $VERSION = '0.27';
22              
23             #{{{sub new
24             sub new {
25 5     5 1 1446 my ( $class, $authn, $verbose, $log ) = @_;
26 5 100       34 if ( !defined $authn ) { croak 'no authn provided!'; }
  1         30  
27 4         9 my $response;
28 4 50       23 $verbose = ( defined $verbose ? $verbose : 0 );
29 4         53 my $content = {
30 4         11 BaseURL => ${$authn}->{'BaseURL'},
31             Authn => $authn,
32             Message => q{},
33             Response => \$response,
34             Verbose => $verbose,
35             Log => $log
36             };
37 4         15 bless $content, $class;
38 4         21 return $content;
39             }
40              
41             #}}}
42              
43             #{{{sub set_results
44             sub set_results {
45 1     1 1 3151 my ( $content, $message, $response ) = @_;
46 1         4 $content->{'Message'} = $message;
47 1         2 $content->{'Response'} = $response;
48 1         4 return 1;
49             }
50              
51             #}}}
52              
53             #{{{sub add
54             sub add {
55 1     1 1 1003 my ( $content, $remote_dest, $properties ) = @_;
56 1         9 my $res = Apache::Sling::Request::request(
57             \$content,
58             Apache::Sling::ContentUtil::add_setup(
59             $content->{'BaseURL'}, $remote_dest, $properties
60             )
61             );
62 0         0 my $success = Apache::Sling::ContentUtil::add_eval($res);
63 0         0 my $message = "Content addition to \"$remote_dest\" ";
64 0 0       0 $message .= ( $success ? 'succeeded!' : 'failed!' );
65 0         0 $content->set_results( "$message", $res );
66 0         0 return $success;
67             }
68              
69             #}}}
70              
71             #{{{ sub command_line
72             sub command_line {
73 0     0 0 0 my ( $content, @ARGV ) = @_;
74 0         0 my $sling = Apache::Sling->new;
75 0         0 my $config = $content->config( $sling, @ARGV );
76 0         0 return $content->run( $sling, $config );
77             }
78              
79             #}}}
80              
81             #{{{sub config
82              
83             sub config {
84 1     1 1 1215 my ( $content, $sling, @ARGV ) = @_;
85 1         6 my $content_config = $content->config_hash( $sling, @ARGV );
86              
87 1 50       9 GetOptions(
88             $content_config, 'auth=s',
89             'help|?', 'log|L=s',
90             'man|M', 'pass|p=s',
91             'threads|t=s', 'url|U=s',
92             'user|u=s', 'verbose|v+',
93             'add|a', 'additions|A=s',
94             'copy|c', 'delete|d',
95             'exists|e', 'filename|n=s',
96             'local|l=s', 'move|m',
97             'property|P=s', 'remote|r=s',
98             'remote-source|S=s', 'replace|R',
99             'view|V'
100             ) or $content->help();
101              
102 1         1627 return $content_config;
103             }
104              
105             #}}}
106              
107             #{{{sub config_hash
108              
109             sub config_hash {
110 1     1 0 3 my ( $content, $sling, @ARGV ) = @_;
111 1         3 my $add;
112             my $additions;
113 0         0 my $copy;
114 0         0 my $delete;
115 0         0 my $exists;
116 0         0 my $filename;
117 0         0 my $local;
118 0         0 my $move;
119 0         0 my @property;
120 0         0 my $remote;
121 0         0 my $remote_source;
122 0         0 my $replace;
123 0         0 my $view;
124              
125 1         31 my %content_config = (
126             'auth' => \$sling->{'Auth'},
127             'help' => \$sling->{'Help'},
128             'log' => \$sling->{'Log'},
129             'man' => \$sling->{'Man'},
130             'pass' => \$sling->{'Pass'},
131             'threads' => \$sling->{'Threads'},
132             'url' => \$sling->{'URL'},
133             'user' => \$sling->{'User'},
134             'verbose' => \$sling->{'Verbose'},
135             'add' => \$add,
136             'additions' => \$additions,
137             'copy' => \$copy,
138             'delete' => \$delete,
139             'exists' => \$exists,
140             'filename' => \$filename,
141             'local' => \$local,
142             'move' => \$move,
143             'property' => \@property,
144             'remote' => \$remote,
145             'remote-source' => \$remote_source,
146             'replace' => \$replace,
147             'view' => \$view
148             );
149              
150 1         5 return \%content_config;
151             }
152              
153             #}}}
154              
155             #{{{sub copy
156             sub copy {
157 1     1 1 1155 my ( $content, $remote_src, $remote_dest, $replace ) = @_;
158 1         6 my $res = Apache::Sling::Request::request(
159             \$content,
160             Apache::Sling::ContentUtil::copy_setup(
161             $content->{'BaseURL'}, $remote_src, $remote_dest, $replace
162             )
163             );
164 0         0 my $success = Apache::Sling::ContentUtil::copy_eval($res);
165 0         0 my $message = "Content copy from \"$remote_src\" to \"$remote_dest\" ";
166 0 0       0 $message .= ( $success ? 'completed!' : 'did not complete successfully!' );
167 0         0 $content->set_results( "$message", $res );
168 0         0 return $success;
169             }
170              
171             #}}}
172              
173             #{{{sub check_exists
174             sub check_exists {
175 1     1 1 1003 my ( $content, $remote_dest ) = @_;
176 1         7 my $res = Apache::Sling::Request::request(
177             \$content,
178             Apache::Sling::ContentUtil::exists_setup(
179             $content->{'BaseURL'}, $remote_dest
180             )
181             );
182 0         0 my $success = Apache::Sling::ContentUtil::exists_eval($res);
183 0         0 my $message = "Content \"$remote_dest\" ";
184 0 0       0 $message .= ( $success ? 'exists!' : 'does not exist!' );
185 0         0 $content->set_results( "$message", $res );
186 0         0 return $success;
187             }
188              
189             #}}}
190              
191             #{{{sub del
192             sub del {
193 1     1 1 1027 my ( $content, $remote_dest ) = @_;
194 1         6 my $res = Apache::Sling::Request::request(
195             \$content,
196             Apache::Sling::ContentUtil::delete_setup(
197             $content->{'BaseURL'}, $remote_dest
198             )
199             );
200 0         0 my $success = Apache::Sling::ContentUtil::delete_eval($res);
201 0         0 my $message = "Content \"$remote_dest\" ";
202 0 0       0 $message .= ( $success ? 'deleted!' : 'was not deleted!' );
203 0         0 $content->set_results( "$message", $res );
204 0         0 return $success;
205             }
206              
207             #}}}
208              
209             #{{{ sub help
210             sub help {
211              
212 1     1 0 1818 print <<"EOF";
213             Usage: perl $0 [-OPTIONS [-MORE_OPTIONS]] [--] [PROGRAM_ARG1 ...]
214             The following options are accepted:
215              
216             --additions or -A (file) - File containing list of content to be uploaded.
217             --add or -a - Add content.
218             --auth (type) - Specify auth type. If ommitted, default is used.
219             --copy or -c - Copy content.
220             --delete or -d - Delete content.
221             --filename or -n (filename) - Specify file name to use for content upload.
222             --help or -? - view the script synopsis and options.
223             --local or -l (localPath) - Local path to content to upload.
224             --log or -L (log) - Log script output to specified log file.
225             --man or -M - view the full script documentation.
226             --move or -m - Move content.
227             --pass or -p (password) - Password of user performing content manipulations.
228             --property or -P (property) - Specify property to set on node.
229             --remote or -r (remoteNode) - specify remote destination under JCR root to act on.
230             --remote-source or -S (remoteSrc) - specify remote source node under JCR root to act on.
231             --replace or -R - when copying or moving, overwrite remote destination if it exists.
232             --threads or -t (threads) - Used with -A, defines number of parallel
233             processes to have running through file.
234             --url or -U (URL) - URL for system being tested against.
235             --user or -u (username) - Name of user to perform content manipulations as.
236             --verbose or -v or -vv or -vvv - Increase verbosity of output.
237             --view or -V (actOnGroup) - view details for specified group in json format.
238              
239             Options may be merged together. -- stops processing of options.
240             Space is not required between options and their arguments.
241             For full details run: perl $0 --man
242             EOF
243              
244 1         4 return 1;
245             }
246              
247             #}}}
248              
249             #{{{ sub man
250             sub man {
251 0     0 0 0 my ($content) = @_;
252              
253 0         0 print <<'EOF';
254             content perl script. Provides a means of uploading content into sling from the
255             command line. The script also acts as a reference implementation for the
256             Content perl library.
257              
258             EOF
259              
260 0         0 $content->help();
261              
262 0         0 print <<"EOF";
263             Example Usage
264              
265             * Authenticate and add a node at /test:
266              
267             perl $0 -U http://localhost:8080 -a -r /test -u admin -p admin
268              
269             * Authenticate and add a node at /test with property p1 set to v1:
270              
271             perl $0 -U http://localhost:8080 -a -r /test -P p1=v1 -u admin -p admin
272              
273             * Authenticate and add a node at /test with property p1 set to v1, and p2 set to v2:
274              
275             perl $0 -U http://localhost:8080 -a -r /test -P p1=v1 -P p2=v2 -u admin -p admin
276              
277             * View json for node at /test:
278              
279             perl $0 -U http://localhost:8080 -V -r /test
280              
281             * Check whether node at /test exists:
282              
283             perl $0 -U http://localhost:8080 -V -r /test
284              
285             * Authenticate and copy content at /test to /test2
286              
287             perl $0 -U http://localhost:8080 -c -S /test -r /test2 -u admin -p admin
288              
289             * Authenticate and move content at /test to /test2, replacing test2 if it already exists
290              
291             perl $0 -U http://localhost:8080 -m -S /test -r /test2 -R -u admin -p admin
292              
293             * Authenticate and delete content at /test
294              
295             perl $0 -U http://localhost:8080 -d -r /test -u admin -p admin
296             EOF
297              
298 0         0 return 1;
299             }
300              
301             #}}}
302              
303             #{{{sub move
304             sub move {
305 1     1 1 1208 my ( $content, $remote_src, $remote_dest, $replace ) = @_;
306 1         7 my $res = Apache::Sling::Request::request(
307             \$content,
308             Apache::Sling::ContentUtil::move_setup(
309             $content->{'BaseURL'}, $remote_src, $remote_dest, $replace
310             )
311             );
312 0         0 my $success = Apache::Sling::ContentUtil::move_eval($res);
313 0         0 my $message = "Content move from \"$remote_src\" to \"$remote_dest\" ";
314 0 0       0 $message .= ( $success ? 'completed!' : 'did not complete successfully!' );
315 0         0 $content->set_results( "$message", $res );
316 0         0 return $success;
317             }
318              
319             #}}}
320              
321             #{{{sub run
322             sub run {
323 2     2 1 38 my ( $content, $sling, $config ) = @_;
324 2 100       8 if ( !defined $config ) {
325 1         16 croak 'No content config supplied!';
326             }
327 1         8 $sling->check_forks;
328 1         2 ${ $config->{'remote'} } =
  1         8  
329 1         3 Apache::Sling::URL::strip_leading_slash( ${ $config->{'remote'} } );
330 1         2 ${ $config->{'remote-source'} } = Apache::Sling::URL::strip_leading_slash(
  1         4  
331 1         3 ${ $config->{'remote-source'} } );
332 1         3 my $authn =
333             defined $sling->{'Authn'}
334 1 50       5 ? ${ $sling->{'Authn'} }
335             : Apache::Sling::Authn->new( \$sling );
336 1         3 my $success = 1;
337              
338 1 50       10 if ( $sling->{'Help'} ) { $content->help(); }
  0 50       0  
    50          
339 0         0 elsif ( $sling->{'Man'} ) { $content->man(); }
  1         4  
340             elsif ( defined ${ $config->{'additions'} } ) {
341 0         0 my $message =
342 0         0 "Adding content from file \"" . ${ $config->{'additions'} } . "\":\n";
343 0         0 Apache::Sling::Print::print_with_lock( "$message", $sling->{'Log'} );
344 0         0 my @childs = ();
345 0         0 for my $i ( 0 .. $sling->{'Threads'} ) {
346 0         0 my $pid = fork;
347 0 0       0 if ($pid) { push @childs, $pid; } # parent
  0 0       0  
348             elsif ( $pid == 0 ) { # child
349             # Create a new separate user agent per fork in order to
350             # ensure cookie stores are separate, then log the user in:
351 0         0 $authn->{'LWP'} = $authn->user_agent( $sling->{'Referer'} );
352 0         0 $authn->login_user();
353 0         0 my $content =
354             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
355             $sling->{'Log'} );
356 0         0 $content->upload_from_file( ${ $config->{'additions'} },
  0         0  
357             $i, $sling->{'Threads'} );
358 0         0 exit 0;
359             }
360             else {
361 0         0 croak "Could not fork $i!";
362             }
363             }
364 0         0 foreach (@childs) { waitpid $_, 0; }
  0         0  
365             }
366             else {
367 1         6 $authn->login_user();
368 1 50 33     2 if ( defined ${ $config->{'local'} }
  1 50       14  
  0 50       0  
    50          
    50          
    50          
    50          
369             && defined ${ $config->{'remote'} } )
370 1         5 {
371 0         0 $content =
372             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
373             $sling->{'Log'} );
374 0         0 $success = $content->upload_file(
375 0         0 ${ $config->{'local'} },
376 0         0 ${ $config->{'remote'} },
377 0         0 ${ $config->{'filename'} }
378             );
379             }
380 1         4 elsif ( defined ${ $config->{'exists'} } ) {
381 0         0 $content =
382             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
383             $sling->{'Log'} );
384 0         0 $success = $content->check_exists( ${ $config->{'remote'} } );
  0         0  
385             }
386 1         5 elsif ( defined ${ $config->{'add'} } ) {
387 0         0 $content =
388             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
389             $sling->{'Log'} );
390 0         0 $success =
391 0         0 $content->add( ${ $config->{'remote'} }, $config->{'property'} );
392             }
393 1         4 elsif ( defined ${ $config->{'copy'} } ) {
394 0         0 $content =
395             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
396             $sling->{'Log'} );
397 0         0 $success = $content->copy(
398 0         0 ${ $config->{'remote-source'} },
399 0         0 ${ $config->{'remote'} },
400 0         0 ${ $config->{'replace'} }
401             );
402             }
403 1         4 elsif ( defined ${ $config->{'delete'} } ) {
404 0         0 $content =
405             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
406             $sling->{'Log'} );
407 0         0 $success = $content->del( ${ $config->{'remote'} } );
  0         0  
408             }
409 1         5 elsif ( defined ${ $config->{'move'} } ) {
410 0         0 $content =
411             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
412             $sling->{'Log'} );
413 0         0 $success = $content->move(
414 0         0 ${ $config->{'remote-source'} },
415 0         0 ${ $config->{'remote'} },
416 0         0 ${ $config->{'replace'} }
417             );
418             }
419             elsif ( defined ${ $config->{'view'} } ) {
420 0         0 $content =
421             Apache::Sling::Content->new( \$authn, $sling->{'Verbose'},
422             $sling->{'Log'} );
423 0         0 $success = $content->view( ${ $config->{'remote'} } );
  0         0  
424             }
425             else {
426 1         4 $content->help();
427 1         6 return 1;
428             }
429 0         0 Apache::Sling::Print::print_result($content);
430             }
431 0         0 return $success;
432             }
433              
434             #}}}
435              
436             #{{{sub upload_file
437             sub upload_file {
438 1     1 1 1109 my ( $content, $local_path, $remote_path, $filename ) = @_;
439 1 50       8 $filename = defined $filename ? $filename : q{};
440 1         7 my $res = Apache::Sling::Request::request(
441             \$content,
442             Apache::Sling::ContentUtil::upload_file_setup(
443             $content->{'BaseURL'}, $local_path, $remote_path, $filename
444             )
445             );
446 0         0 my $success = Apache::Sling::ContentUtil::upload_file_eval($res);
447 0         0 my $basename = $local_path;
448 0         0 $basename =~ s/^(.*\/)([^\/]*)$/$2/msx;
449 0 0       0 my $remote_dest =
450             $remote_path . ( $filename ne q{} ? "/$filename" : "/$basename" );
451 0         0 my $message = "Content: \"$local_path\" upload to \"$remote_dest\" ";
452 0 0       0 $message .= ( $success ? 'succeeded!' : 'failed!' );
453 0         0 $content->set_results( "$message", $res );
454 0         0 return $success;
455             }
456              
457             #}}}
458              
459             #{{{sub upload_from_file
460             sub upload_from_file {
461 3     3 1 3171 my ( $content, $file, $fork_id, $number_of_forks ) = @_;
462 3 50       10 $fork_id = defined $fork_id ? $fork_id : 0;
463 3 50       11 $number_of_forks = defined $number_of_forks ? $number_of_forks : 1;
464 3         4 my $count = 0;
465 3 100       9 if ( !defined $file ) {
466 1         13 croak 'File to upload from not defined';
467             }
468 1 100   1   13 if ( open my ($input), '<', $file ) {
  1         1  
  1         8  
  2         89  
469 1         1776 while (<$input>) {
470 1 50       6 if ( $fork_id == ( $count++ % $number_of_forks ) ) {
471 1         3 chomp;
472 1 50       27 $_ =~ /^(\S.*?),(\S.*?)$/msx
473             or croak 'Problem parsing content to add';
474 0         0 my $local_path = $1;
475 0         0 my $remote_path = $2;
476 0         0 $content->upload_file( $local_path, $remote_path, q{} );
477 0         0 Apache::Sling::Print::print_result($content);
478             }
479             }
480 0 0       0 close $input or croak 'Problem closing input!';
481             }
482             else {
483 1         18 croak "Problem opening file: '$file'";
484             }
485 0         0 return 1;
486             }
487              
488             #}}}
489              
490             #{{{sub view
491             sub view {
492 1     1 1 1036 my ( $content, $remote_dest ) = @_;
493 1         6 my $res = Apache::Sling::Request::request(
494             \$content,
495             Apache::Sling::ContentUtil::exists_setup(
496             $content->{'BaseURL'}, $remote_dest
497             )
498             );
499 0         0 my $success = Apache::Sling::ContentUtil::exists_eval($res);
500 0         0 my $message = (
501             $success
502 0 0       0 ? ${$res}->content
503             : "Problem viewing content: \"$remote_dest\""
504             );
505 0         0 $content->set_results( "$message", $res );
506 0         0 return $success;
507             }
508              
509             #}}}
510              
511             #{{{sub view_file
512             sub view_file {
513 1     1 1 957 my ( $content, $remote_dest ) = @_;
514 1 50       5 if ( !defined $remote_dest ) {
515 1         14 croak 'No file to view specified!';
516             }
517 0           my $res = Apache::Sling::Request::request( \$content,
518             "get $content->{ 'BaseURL' }/$remote_dest" );
519 0           my $success = Apache::Sling::ContentUtil::exists_eval($res);
520 0           my $message = (
521             $success
522 0 0         ? ${$res}->content
523             : "Problem viewing content: \"$remote_dest\""
524             );
525 0           $content->set_results( "$message", $res );
526 0           return $success;
527             }
528              
529             #}}}
530              
531             #{{{sub view_full_json
532             sub view_full_json {
533 0     0 1   my ( $content, $remote_dest ) = @_;
534 0 0         if ( !defined $remote_dest ) {
535 0           croak 'No file to view specified!';
536             }
537 0           my $res = Apache::Sling::Request::request(
538             \$content,
539             Apache::Sling::ContentUtil::full_json_setup(
540             $content->{'BaseURL'}, $remote_dest
541             )
542             );
543 0           my $success = Apache::Sling::ContentUtil::full_json_eval($res);
544 0           my $message = (
545             $success
546 0 0         ? ${$res}->content
547             : "Problem viewing json: \"$remote_dest\""
548             );
549 0           $content->set_results( "$message", $res );
550 0           return $success;
551             }
552              
553             #}}}
554              
555             1;
556              
557             __END__