|
| 1 | +package WGDev::Command::Batchedit; |
| 2 | +# ABSTRACT: Edits assets by URL or asset ID with a pattern and a string |
| 3 | +# so it can be used in a shell script / batch file |
| 4 | +use strict; |
| 5 | +use warnings; |
| 6 | +use 5.008008; |
| 7 | + |
| 8 | +use parent qw(WGDev::Command::Base); |
| 9 | + |
| 10 | +use WGDev (); |
| 11 | + |
| 12 | +sub config_options { |
| 13 | + return qw( |
| 14 | + command=s |
| 15 | + tree=s@ |
| 16 | + class=s@ |
| 17 | + pattern=s |
| 18 | + string=s |
| 19 | + ); |
| 20 | +} |
| 21 | + |
| 22 | +sub process { |
| 23 | + my $self = shift; |
| 24 | + my $wgd = $self->wgd; |
| 25 | + |
| 26 | + my @assets_to_edit = $self->get_assets_data; |
| 27 | + |
| 28 | + if ( !@assets_to_edit ) { |
| 29 | + WGDev::X->throw('No assets to edit!'); |
| 30 | + } |
| 31 | + |
| 32 | + # get pattern to match |
| 33 | + my $pattern = $self->{options}->{pattern}; |
| 34 | + |
| 35 | + # get replacement string |
| 36 | + my $string = $self->{options}->{string}; |
| 37 | + |
| 38 | + my $output_format = "%-8s: %-30s (%22s) %s\n"; |
| 39 | + |
| 40 | + my $version_tag; |
| 41 | + for my $asset_to_edit (@assets_to_edit) { |
| 42 | + my $asset_text = $asset_to_edit->{text}; |
| 43 | + my $old_asset_text = $asset_text; |
| 44 | + $asset_text =~ s/$pattern/$string/xmsg; |
| 45 | + if ( $asset_text eq $old_asset_text ) { |
| 46 | + printf $output_format, |
| 47 | + 'Skipping', ( $asset_to_edit->{url} || $asset_to_edit->{title} ), |
| 48 | + ( $asset_to_edit->{asset_id} || q{} ), $asset_to_edit->{title}; |
| 49 | + next; |
| 50 | + } |
| 51 | + $version_tag ||= do { |
| 52 | + require WebGUI::VersionTag; |
| 53 | + my $vt = WebGUI::VersionTag->getWorking( $wgd->session ); |
| 54 | + $vt->set( { name => 'WGDev Asset Editor' } ); |
| 55 | + $vt; |
| 56 | + }; |
| 57 | + my $asset_data = $wgd->asset->deserialize($asset_text); |
| 58 | + my $asset; |
| 59 | + my $parent; |
| 60 | + if ( $asset_data->{parent} ) { |
| 61 | + $parent = eval { $wgd->asset->find( $asset_data->{parent} ) }; |
| 62 | + } |
| 63 | + if ( $asset_to_edit->{asset_id} ) { |
| 64 | + $asset = $wgd->asset->by_id( $asset_to_edit->{asset_id}, undef, |
| 65 | + $asset_to_edit->{revision} ); |
| 66 | + $asset = $asset->addRevision( |
| 67 | + $asset_data, |
| 68 | + undef, |
| 69 | + { |
| 70 | + skipAutoCommitWorkflows => 1, |
| 71 | + skipNotification => 1, |
| 72 | + } ); |
| 73 | + if ($parent) { |
| 74 | + $asset->setParent($parent); |
| 75 | + } |
| 76 | + } |
| 77 | + else { |
| 78 | + $parent ||= $wgd->asset->import_node; |
| 79 | + my $asset_id = $asset_data->{assetId}; |
| 80 | + $asset = $parent->addChild( |
| 81 | + $asset_data, |
| 82 | + $asset_id, |
| 83 | + undef, |
| 84 | + { |
| 85 | + skipAutoCommitWorkflows => 1, |
| 86 | + skipNotification => 1, |
| 87 | + } ); |
| 88 | + } |
| 89 | + printf $output_format, ( $asset_to_edit->{asset_id} ? 'Updating' : 'Adding' ), |
| 90 | + $asset->get('url'), $asset->getId, $asset->get('title'); |
| 91 | + } |
| 92 | + |
| 93 | + if ($version_tag) { |
| 94 | + $version_tag->commit; |
| 95 | + } |
| 96 | + return 1; |
| 97 | +} |
| 98 | + |
| 99 | +sub get_assets_data { |
| 100 | + my $self = shift; |
| 101 | + my $wgd = $self->wgd; |
| 102 | + my @assets_data; |
| 103 | + for my $asset_spec ( $self->arguments ) { |
| 104 | + my $asset_data = eval { $self->get_asset_data($asset_spec) }; |
| 105 | + if ( !$asset_data ) { |
| 106 | + warn $@; |
| 107 | + next; |
| 108 | + } |
| 109 | + push @assets_data, $asset_data; |
| 110 | + } |
| 111 | + if ( !$self->option('tree') ) { |
| 112 | + return @assets_data; |
| 113 | + } |
| 114 | + for my $parent_spec ( @{ $self->option('tree') } ) { |
| 115 | + my $parent = $wgd->asset->find($parent_spec) || do { |
| 116 | + warn "$parent_spec is not a valid asset!\n"; |
| 117 | + next; |
| 118 | + }; |
| 119 | + my $options = {}; |
| 120 | + if ( $self->option('class') ) { |
| 121 | + my @classes = @{ $self->option('class') }; |
| 122 | + for (@classes) { |
| 123 | + s/^(?:(?:WebGUI::Asset)?::)?/WebGUI::Asset::/msx; |
| 124 | + } |
| 125 | + $options->{includeOnlyClasses} = \@classes; |
| 126 | + } |
| 127 | + my $assets |
| 128 | + = $parent->getLineage( [qw(self descendants)], $options ); |
| 129 | + for my $asset_id ( @{$assets} ) { |
| 130 | + my $asset_data = $self->get_asset_data($asset_id); |
| 131 | + if ( !$asset_data ) { |
| 132 | + next; |
| 133 | + } |
| 134 | + push @assets_data, $asset_data; |
| 135 | + } |
| 136 | + } |
| 137 | + return @assets_data; |
| 138 | +} |
| 139 | + |
| 140 | +sub get_asset_data { |
| 141 | + my $self = shift; |
| 142 | + my $asset = shift; |
| 143 | + |
| 144 | + my $wgd_asset = $self->wgd->asset; |
| 145 | + if ( !ref $asset ) { |
| 146 | + $asset = eval { $wgd_asset->find($asset) }; |
| 147 | + if ( !$asset ) { |
| 148 | + die $@; |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + my $asset_text = $self->wgd->asset->serialize($asset); |
| 153 | + my $short_class = ref $asset || $asset; |
| 154 | + $short_class =~ s/^WebGUI::Asset:://msx; |
| 155 | + |
| 156 | + return { |
| 157 | + text => $asset_text, |
| 158 | + class => ref $asset || $asset, |
| 159 | + asset_id => $asset->getId, |
| 160 | + url => $asset->get('url'), |
| 161 | + title => $asset->get('title'), |
| 162 | + }; |
| 163 | +} |
| 164 | + |
| 165 | +1; |
| 166 | + |
| 167 | +=head1 SYNOPSIS |
| 168 | +
|
| 169 | + wgd batchedit --pattern=<pattern> --string=<string> <asset> [<asset> ...] |
| 170 | + wgd batchedit --tree=<asset> --pattern=<pattern> --string=<string> [--tree=<asset> ...] [--class=<class> ...] |
| 171 | +
|
| 172 | +=head1 DESCRIPTION |
| 173 | +
|
| 174 | +Edits assets in-place by replacing all matching 'pattern's with 'string'. |
| 175 | +If modifications are made, the assets are updated. |
| 176 | +
|
| 177 | +=head1 OPTIONS |
| 178 | +
|
| 179 | +=over 8 |
| 180 | +
|
| 181 | +=item C<--pattern=> |
| 182 | +
|
| 183 | +Pattern to match against for replacing. |
| 184 | +
|
| 185 | +=item C<--string=> |
| 186 | +
|
| 187 | +Replacement string for the matched pattern. |
| 188 | +
|
| 189 | +=item C<< <asset> >> |
| 190 | +
|
| 191 | +Either an asset URL or ID. As many as desired can be specified. |
| 192 | +Prepending with a slash will force it to be interpreted as a URL. |
| 193 | +
|
| 194 | +=item C<--tree=> |
| 195 | +
|
| 196 | +Will open specified asset and all descendants in editor. Can be specified |
| 197 | +multiple times. |
| 198 | +
|
| 199 | +=item C<--class=> |
| 200 | +
|
| 201 | +Only used with --tree option. Limits exported assets to specified classes. |
| 202 | +Can be specified as a full (C<WebGUI::Asset::Template>) or abbreviated |
| 203 | +(C<Template>) class name. |
| 204 | +
|
| 205 | +=back |
| 206 | +
|
| 207 | +=method C<get_assets_data> |
| 208 | +
|
| 209 | +Creates and returns an array of hash references with information about |
| 210 | +the assets and exported files. Also follows the C<--tree> option. |
| 211 | +
|
| 212 | +=method C<get_asset_data ( $asset_or_class )> |
| 213 | +
|
| 214 | +Accepts an asset, returning a hash reference of information about the |
| 215 | +asset. |
| 216 | +
|
| 217 | +=cut |
| 218 | + |
0 commit comments