App-Sqitch

 view release on metacpan or  search on metacpan

lib/App/Sqitch/Command/add.pm  view on Meta::CPAN

    },
);

has open_editor => (
    is       => 'ro',
    isa      => Bool,
    lazy     => 1,
    default  => sub {
        shift->sqitch->config->get(
            key => 'add.open_editor',
            as  => 'bool',
        ) // 0;
    },
);

sub _check_script($) {
    my $file = file shift;

    hurl add => __x(
        'Template {template} does not exist',
        template => $file,
    ) unless -e $file;

    hurl add => __x(
        'Template {template} is not a file',
        template => $file,
    ) unless -f $file;

    return $file;
}

sub _config_templates {
    my ($self, $config) = @_;
    my $tmpl = $config->get_section( section => 'add.templates' );
    $_ = _check_script $_ for values %{ $tmpl };
    return $tmpl;
}

sub all_templates {
    my ($self, $name) = @_;
    my $config = $self->sqitch->config;
    my $tmpl   = { %{ $self->templates } };

    # Read all the template directories.
    for my $dir (
        $self->template_directory,
        $config->user_dir->subdir('templates'),
        $config->system_dir->subdir('templates'),
    ) {
        next unless $dir && -d $dir;
        for my $subdir($dir->children) {
            next unless $subdir->is_dir;
            next if $tmpl->{my $script = $subdir->basename};
            my $file = $subdir->file("$name.tmpl");
            $tmpl->{$script} = $file if -f $file
        }
    }

    # Make sure we have core templates.
    my $with = $self->with_scripts;
    for my $script (qw(deploy revert verify)) {
        hurl add => __x(
            'Cannot find {script} template',
            script => $script,
        ) if !$tmpl->{$script} && ($with->{$script} || !exists $with->{$script});
    }

    return $tmpl;
}

sub options {
    return qw(
        change-name|change|c=s
        requires|r=s@
        conflicts|x=s@
        note|n|m=s@
        all|a!
        template-name|template|t=s
        template-directory=s
        with=s@
        without=s@
        use=s%
        open-editor|edit|e!
    );
}

# Override to convert multiple vars to an array.
sub _parse_opts {
    my ( $class, $args ) = @_;

    my (%opts, %vars);
    Getopt::Long::Configure(qw(bundling no_pass_through));
    Getopt::Long::GetOptionsFromArray(
        $args, \%opts,
        $class->options,
        'set|s=s%' => sub {
            my ($opt, $key, $val) = @_;
            if (exists $vars{$key}) {
                $vars{$key} = [$vars{$key}] unless ref $vars{$key};
                push @{ $vars{$key} } => $val;
            } else {
                $vars{$key} = $val;
            }
        }
    ) or $class->usage;
    $opts{set} = \%vars if %vars;

    # Convert dashes to underscores.
    for my $k (keys %opts) {
        next unless ( my $nk = $k ) =~ s/-/_/g;
        $opts{$nk} = delete $opts{$k};
    }

    # Merge with and without.
    $opts{with_scripts} = {
        ( map { $_ => 1 } qw(deploy revert verify) ),
        ( map { $_ => 1 } @{ delete $opts{with}    || [] } ),
        ( map { $_ => 0 } @{ delete $opts{without} || [] } ),
    };
    return \%opts;
}

sub configure {
    my ( $class, $config, $opt ) = @_;

    my %params = (
        requires  => $opt->{requires}  || [],
        conflicts => $opt->{conflicts} || [],
        note      => $opt->{note}      || [],
    );

    for my $key (qw(with_scripts change_name)) {
        $params{$key} = $opt->{$key} if $opt->{$key};
    }

    if (
        my $dir = $opt->{template_directory}
            || $config->get( key => 'add.template_directory' )
    ) {
        $dir = $params{template_directory} = dir $dir;
        hurl add => __x(
            'Directory "{dir}" does not exist',
            dir => $dir,
        ) unless -e $dir;

        hurl add => __x(
            '"{dir}" is not a directory',
            dir => $dir,
        ) unless -d $dir;
    }

    if (
        my $name = $opt->{template_name}
            || $config->get( key => 'add.template_name' )
    ) {
        $params{template_name} = $name;
    }

    # Merge variables.
    if ( my $vars = $opt->{set} ) {
        $params{variables} = {
            %{ $config->get_section( section => 'add.variables' ) },
            %{ $vars },
        };
    }

    # Merge template info.
    my $tmpl = $class->_config_templates($config);
    if ( my $use = delete $opt->{use} ) {
        while (my ($k, $v) = each %{ $use }) {
            $tmpl->{$k} = _check_script $v;
        }
    }
    $params{templates} = $tmpl if %{ $tmpl };

    # Copy other options.

lib/App/Sqitch/Command/add.pm  view on Meta::CPAN

    if (eval 'use Template; 1') {
        my $tt = Template->new;
        $tt->process( $self->_slurp($tmpl), $vars, $fh ) or hurl add => __x(
            'Error executing {template}: {error}',
            template => $tmpl,
            error    => $tt->error,
        );
    } else {
        eval 'use Template::Tiny 0.11; 1' or die $@;
        my $output = '';
        Template::Tiny->new->process( $self->_slurp($tmpl), $vars, \$output );
        print $fh $output;
    }

    close $fh or hurl add => __x(
        'Error closing {file}: {error}',
        file  => $file,
        error => $!
    );
    
    # Warn if the file name has a double extension
    if ($file =~ m/\.(\w+)\.\1+$/) {
        my $ext = $1;
        $self->warn(__x(
            'File {file} has a double extension of {ext}',
            file => $file,
            ext  => $ext,
        ));
    }
    
    $self->info(__x 'Created {file}', file => $file);
}

sub _slurp {
    my ( $self, $tmpl ) = @_;
    open my $fh, "<:utf8_strict", $tmpl or hurl add => __x(
        'Cannot open {file}: {error}',
        file  => $tmpl,
        error => $!
    );
    local $/;
    return \<$fh>;
}

1;

__END__

=head1 Name

App::Sqitch::Command::add - Add a new change to Sqitch plans

=head1 Synopsis

  my $cmd = App::Sqitch::Command::add->new(%params);
  $cmd->execute;

=head1 Description

Adds a new deployment change. This will result in the creation of a scripts in
the deploy, revert, and verify directories. The scripts are based on
L<Template::Tiny> templates in F<~/.sqitch/templates/> or
C<$(prefix)/etc/sqitch/templates> (call C<sqitch --etc-path> to find out
where, exactly (e.g., C<$(sqitch --etc-path)/sqitch.conf>).

=head1 Interface

=head2 Class Methods

=head3 C<options>

  my @opts = App::Sqitch::Command::add->options;

Returns a list of L<Getopt::Long> option specifications for the command-line
options for the C<add> command.

=head3 C<configure>

  my $params = App::Sqitch::Command::add->configure(
      $config,
      $options,
  );

Processes the configuration and command options and returns a hash suitable
for the constructor.

=head2 Attributes

=head3 C<change_name>

The name of the change to be added.

=head3 C<note>

Text of the change note.

=head3 C<requires>

List of required changes.

=head3 C<conflicts>

List of conflicting changes.

=head3 C<all>

Boolean indicating whether or not to run the command against all plans in the
project.

=head3 C<template_name>

The name of the templates to use when generating scripts. Defaults to the
engine for which the scripts are being generated.

=head3 C<template_directory>

Directory in which to find the change script templates.

=head3 C<with_scripts>

Hash reference indicating which scripts to create.



( run in 1.059 second using v1.01-cache-2.11-cpan-5a3173703d6 )