webgui/lib/WGDev/Command/Edit.pm

224 lines
6.2 KiB
Perl

package WGDev::Command::Edit;
# ABSTRACT: Edits assets by URL
use strict;
use warnings;
use 5.008008;
use parent qw(WGDev::Command::Base);
use WGDev ();
sub config_options {
return qw(
command=s
tree=s@
class=s@
);
}
sub process {
my $self = shift;
my $wgd = $self->wgd;
my @files = $self->export_asset_data;
if ( !@files ) {
WGDev::X->throw('No assets to edit!');
}
## no critic (ProhibitParensWithBuiltins)
my $command = $self->option('command') || $ENV{EDITOR} || 'vi';
system join( q{ }, $command, map { $_->{filename} } @files );
my $output_format = "%-8s: %-30s (%22s) %s\n";
my $version_tag;
for my $file (@files) {
open my $fh, '<:encoding(UTF-8)', $file->{filename} or next;
my $asset_text = do { local $/; <$fh> };
close $fh or next;
unlink $file->{filename};
if ( $asset_text eq $file->{text} ) {
printf $output_format,
'Skipping', ( $file->{url} || $file->{title} ),
( $file->{asset_id} || q{} ), $file->{title};
next;
}
$version_tag ||= do {
require WebGUI::VersionTag;
my $vt = WebGUI::VersionTag->getWorking( $wgd->session );
$vt->set( { name => 'WGDev Asset Editor' } );
$vt;
};
my $asset_data = $wgd->asset->deserialize($asset_text);
my $asset;
my $parent;
if ( $asset_data->{parent} ) {
$parent = eval { $wgd->asset->find( $asset_data->{parent} ) };
}
if ( $file->{asset_id} ) {
$asset = $wgd->asset->by_id( $file->{asset_id}, undef,
$file->{revision} );
$asset = $asset->addRevision(
$asset_data,
undef,
{
skipAutoCommitWorkflows => 1,
skipNotification => 1,
} );
if ($parent) {
$asset->setParent($parent);
}
}
else {
$parent ||= $wgd->asset->import_node;
my $asset_id = $asset_data->{assetId};
$asset = $parent->addChild(
$asset_data,
$asset_id,
undef,
{
skipAutoCommitWorkflows => 1,
skipNotification => 1,
} );
}
printf $output_format, ( $file->{asset_id} ? 'Updating' : 'Adding' ),
$asset->get('url'), $asset->getId, $asset->get('title');
}
if ($version_tag) {
$version_tag->commit;
}
return 1;
}
sub export_asset_data {
my $self = shift;
my $wgd = $self->wgd;
my @files;
for my $asset_spec ( $self->arguments ) {
my $file_data = eval { $self->write_temp($asset_spec) };
if ( !$file_data ) {
warn $@;
next;
}
push @files, $file_data;
}
if ( $self->option('tree') ) {
for my $parent_spec ( @{ $self->option('tree') } ) {
my $parent = $wgd->asset->find($parent_spec) || do {
warn "$parent_spec is not a valid asset!\n";
next;
};
my $options = {};
if ( $self->option('class') ) {
my @classes = @{ $self->option('class') };
for (@classes) {
s/^(?:(?:WebGUI::Asset)?::)?/WebGUI::Asset::/msx;
}
$options->{includeOnlyClasses} = \@classes;
}
my $assets
= $parent->getLineage( [qw(self descendants)], $options );
for my $asset_id ( @{$assets} ) {
my $file_data = $self->write_temp($asset_id);
if ( !$file_data ) {
next;
}
push @files, $file_data;
}
}
}
return @files;
}
sub write_temp {
my $self = shift;
my $asset = shift;
require File::Temp;
my $wgd_asset = $self->wgd->asset;
if ( !ref $asset ) {
$asset = eval { $wgd_asset->find($asset) }
|| eval { scalar $wgd_asset->validate_class($asset) };
if ( !$asset ) {
die $@;
}
}
my $short_class = ref $asset || $asset;
$short_class =~ s/^WebGUI::Asset:://msx;
my ( $fh, $filename ) = File::Temp::tempfile();
binmode $fh, ':encoding(UTF-8)';
my $asset_text = $self->wgd->asset->serialize($asset);
print {$fh} $asset_text;
close $fh or return;
return {
filename => $filename,
text => $asset_text,
class => ref $asset || $asset,
ref $asset
? (
asset_id => $asset->getId,
url => $asset->get('url'),
title => $asset->get('title'),
)
: ( title => 'New ' . $short_class, ),
};
}
1;
=head1 SYNOPSIS
wgd edit [--command=<command>] <asset> [<asset> ...]
wgd edit --tree=<asset> [--tree=<asset> ...] [--class=<class> ...]
=head1 DESCRIPTION
Exports asset to temporary files, then opens them in your prefered editor.
If modifications are made, the assets are updated.
=head1 OPTIONS
=over 8
=item C<--command=>
Command to be executed. If not specified, uses the EDITOR environment
variable. If that is not specified, uses C<$EDITOR> or C<vi>.
=item C<< <asset> >>
Either an asset URL, ID, or class name. As many can be specified as desired.
Prepending with a slash will force it to be interpreted as a URL. Class names
specified will be opened with a skeleton for the asset type.
=item C<--tree=>
Will open specified asset and all descendants in editor. Can be specified
multiple times.
=item C<--class=>
Only used with --tree option. Limits exported assets to specified classes.
Can be specified as a full (C<WebGUI::Asset::Template>) or abbreviated
(C<Template>) class name.
=back
=method C<export_asset_data>
For each item in C<arguments>, exports the asset serialized to text to a
temporary file. Also follows the C<--tree> option. Returns an array of
hash references with information about the assets and exported files.
=method C<write_temp ( $asset_or_class )>
Accepts an asset or a class name and exports it serialized as a text file.
Returns a hash reference of information about the file ans asset.
=cut