| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package UR::Namespace::Command::Update::Pod; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 23 | use strict; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 28 |  | 
| 4 | 1 |  |  | 1 |  | 3 | use warnings; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 24 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 4 | use UR; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 6 |  | 
| 7 |  |  |  |  |  |  | our $VERSION = "0.46"; # UR $VERSION; | 
| 8 | 1 |  |  | 1 |  | 4 | use IO::File; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 815 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | class UR::Namespace::Command::Update::Pod { | 
| 11 |  |  |  |  |  |  | is => 'Command::V2', | 
| 12 |  |  |  |  |  |  | has => [ | 
| 13 |  |  |  |  |  |  | executable_name => { | 
| 14 |  |  |  |  |  |  | is => 'Text', | 
| 15 |  |  |  |  |  |  | shell_args_position => 1, | 
| 16 |  |  |  |  |  |  | doc => 'the name of the executable to document' | 
| 17 |  |  |  |  |  |  | }, | 
| 18 |  |  |  |  |  |  | class_name => { | 
| 19 |  |  |  |  |  |  | is => 'Text', | 
| 20 |  |  |  |  |  |  | shell_args_position => 2, | 
| 21 |  |  |  |  |  |  | doc => 'the command class which maps to the executable' | 
| 22 |  |  |  |  |  |  | }, | 
| 23 |  |  |  |  |  |  | targets => { | 
| 24 |  |  |  |  |  |  | is => 'Text', | 
| 25 |  |  |  |  |  |  | shell_args_position => 3, | 
| 26 |  |  |  |  |  |  | is_many => 1, | 
| 27 |  |  |  |  |  |  | doc => 'specific classes to document (documents all unless specified)', | 
| 28 |  |  |  |  |  |  | }, | 
| 29 |  |  |  |  |  |  | input_path => { | 
| 30 |  |  |  |  |  |  | is => 'Path', | 
| 31 |  |  |  |  |  |  | is_optional => 1, | 
| 32 |  |  |  |  |  |  | doc => 'optional location of the modules to document', | 
| 33 |  |  |  |  |  |  | }, | 
| 34 |  |  |  |  |  |  | output_path => { | 
| 35 |  |  |  |  |  |  | is => 'Text', | 
| 36 |  |  |  |  |  |  | is_optional => 1, | 
| 37 |  |  |  |  |  |  | doc => 'optional location to output .pod files', | 
| 38 |  |  |  |  |  |  | }, | 
| 39 |  |  |  |  |  |  | ], | 
| 40 |  |  |  |  |  |  | doc => "generate man-page-like POD for a commands" | 
| 41 |  |  |  |  |  |  | }; | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | sub help_synopsis { | 
| 44 |  |  |  |  |  |  | return <<"EOS" | 
| 45 |  |  |  |  |  |  | ur update pod -i ./lib -o ./pod ur UR::Namespace::Command | 
| 46 |  |  |  |  |  |  | EOS | 
| 47 | 0 |  |  | 0 | 0 |  | } | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | sub help_detail { | 
| 50 | 0 |  |  | 0 | 0 |  | return join("\n", | 
| 51 |  |  |  |  |  |  | 'This tool generates POD documentation for each all of the commands in a tree for a given executable.', | 
| 52 |  |  |  |  |  |  | 'This command must be run from within the namespace directory.'); | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | sub execute { | 
| 56 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 57 |  |  |  |  |  |  | #$DB::single = 1; | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 0 |  |  |  |  |  | local $ENV{ANSI_COLORS_DISABLED}    = 1; | 
| 60 | 0 |  |  |  |  |  | my $entry_point_bin     = $self->executable_name; | 
| 61 | 0 |  |  |  |  |  | my $entry_point_class   = $self->class_name; | 
| 62 |  |  |  |  |  |  |  | 
| 63 | 0 |  |  |  |  |  | my @targets = $self->targets; | 
| 64 | 0 | 0 |  |  |  |  | unless (@targets) { | 
| 65 | 0 |  |  |  |  |  | @targets = ($entry_point_class); | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 | 0 |  |  |  |  |  | local @INC = @INC; | 
| 69 | 0 | 0 |  |  |  |  | if ($self->input_path) { | 
| 70 | 0 |  |  |  |  |  | unshift @INC, $self->input_path; | 
| 71 | 0 |  |  |  |  |  | $self->status_message("using modules at " . $self->input_path); | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 0 |  |  |  |  |  | my $errors = 0; | 
| 75 | 0 |  |  |  |  |  | for my $target (@targets) { | 
| 76 | 0 |  |  |  |  |  | eval "use $target"; | 
| 77 | 0 | 0 |  |  |  |  | if ($@) { | 
| 78 | 0 |  |  |  |  |  | $self->error_message("Failed to use $target: $@"); | 
| 79 | 0 |  |  |  |  |  | $errors++; | 
| 80 |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  | } | 
| 82 | 0 | 0 |  |  |  |  | return if $errors; | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 0 |  |  |  |  |  | my @commands = map( $self->get_all_subcommands($_), @targets); | 
| 85 | 0 |  |  |  |  |  | push @commands, @targets; | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 0 | 0 |  |  |  |  | if ($self->output_path) { | 
| 88 | 0 | 0 |  |  |  |  | unless (-d $self->output_path) { | 
| 89 | 0 | 0 |  |  |  |  | if (-e $self->output_path) { | 
| 90 | 0 |  |  |  |  |  | $self->status_message("output path is not a directory!: " . $self->output_path); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | else { | 
| 93 | 0 |  |  |  |  |  | mkdir $self->output_path; | 
| 94 | 0 | 0 |  |  |  |  | if (-d $self->output_path) { | 
| 95 | 0 |  |  |  |  |  | $self->status_message("using output directory " . $self->output_path); | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  | else { | 
| 98 | 0 |  |  |  |  |  | $self->status_message("error creating directory: $! for " . $self->output_path); | 
| 99 |  |  |  |  |  |  | } | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 | 0 |  |  |  |  |  | local $Command::V1::entry_point_bin = $entry_point_bin; | 
| 105 | 0 |  |  |  |  |  | local $Command::V2::entry_point_bin = $entry_point_bin; | 
| 106 | 0 |  |  |  |  |  | local $Command::V1::entry_point_class = $entry_point_class; | 
| 107 | 0 |  |  |  |  |  | local $Command::V2::entry_point_class = $entry_point_class; | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 0 |  |  |  |  |  | for my $command (@commands) { | 
| 110 | 0 |  |  |  |  |  | my $pod; | 
| 111 | 0 |  |  |  |  |  | eval { | 
| 112 | 0 |  |  |  |  |  | $pod = $command->help_usage_command_pod(); | 
| 113 |  |  |  |  |  |  | }; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 0 | 0 |  |  |  |  | if($@) { | 
| 116 | 0 |  |  |  |  |  | $self->warning_message('Could not generate POD for ' . $command . '. ' . $@); | 
| 117 | 0 |  |  |  |  |  | next; | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 0 | 0 |  |  |  |  | unless($pod) { | 
| 121 | 0 |  |  |  |  |  | $self->warning_message('No POD generated for ' . $command); | 
| 122 | 0 |  |  |  |  |  | next; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 0 |  |  |  |  |  | my $pod_path; | 
| 126 | 0 | 0 |  |  |  |  | if (defined $self->output_path) { | 
| 127 | 0 |  |  |  |  |  | my $filename = $command->command_name . '.pod'; | 
| 128 | 0 |  |  |  |  |  | $filename =~ s/ /-/g; | 
| 129 | 0 |  |  |  |  |  | my $output_path = $self->output_path; | 
| 130 | 0 |  |  |  |  |  | $output_path =~ s|/+$||m; | 
| 131 | 0 |  |  |  |  |  | $pod_path = join('/', $output_path, $filename); | 
| 132 |  |  |  |  |  |  | } else { | 
| 133 | 0 |  |  |  |  |  | $pod_path = $command->__meta__->module_path; | 
| 134 | 0 |  |  |  |  |  | $pod_path =~ s/.pm/.pod/; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 0 |  |  |  |  |  | $self->status_message("Writing $pod_path"); | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 0 |  |  |  |  |  | my $fh; | 
| 140 | 0 |  | 0 |  |  |  | $fh = IO::File->new('>' . $pod_path) || die "Cannot create file at " . $pod_path . "\n"; | 
| 141 | 0 |  |  |  |  |  | print $fh $pod; | 
| 142 | 0 |  |  |  |  |  | close($fh); | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 0 |  |  |  |  |  | return 1; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | sub get_all_subcommands { | 
| 149 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 150 | 0 |  |  |  |  |  | my $command = shift; | 
| 151 | 0 |  |  |  |  |  | my $src = "use $command"; | 
| 152 | 0 |  |  |  |  |  | eval $src; | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 0 | 0 |  |  |  |  | if ($@) { | 
| 155 | 0 |  |  |  |  |  | $self->error_message("Failed to load class $command: $@"); | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  | else { | 
| 158 | 0 |  |  |  |  |  | my $module_name = $command; | 
| 159 | 0 |  |  |  |  |  | $module_name =~ s|::|/|g; | 
| 160 | 0 |  |  |  |  |  | $module_name .= '.pm'; | 
| 161 | 0 |  |  |  |  |  | $self->status_message("Loaded $command from $module_name at $INC{$module_name}\n"); | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 0 |  |  |  |  |  | my @subcommands; | 
| 165 | 0 |  |  |  |  |  | eval { | 
| 166 | 0 | 0 |  |  |  |  | if ($command->can('sub_command_classes')) { | 
| 167 | 0 |  |  |  |  |  | @subcommands = $command->sub_command_classes; | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  | }; | 
| 170 |  |  |  |  |  |  |  | 
| 171 | 0 | 0 |  |  |  |  | if($@) { | 
| 172 | 0 |  |  |  |  |  | $self->warning_message("Error getting subclasses for module $command: " . $@); | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 0 | 0 | 0 |  |  |  | return unless @subcommands and $subcommands[0]; #Sometimes sub_command_classes returns 0 instead of the empty list | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 0 |  |  |  |  |  | return map($self->get_all_subcommands($_), @subcommands), @subcommands; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | 1; |