Permalink
Browse files

Add support for generating arbitrary scripts from templates.

Closes #111. This change required pretty substantial changes to the
way the `add` command is configured and operates, but all for the good,
I think.

* Replace the `with_$script` and `$script_template` attributes with
  `with_scripts` and `templates`, which return hash references mapping scripts
  to template files.
* Add the `--with` option to name a script to generate. Repeplaces the
  `--deploy`, `--revert`, and `--verify` options.
* Add the `--without` option to name a script *not* to generate. Replaces the
  `--no-deploy`, `--no-revert`, and `--no-verify` options.
* Add the `--use` option. Pass in one or more key/value pairs to map script
  names to their templates.
* Replace the `add.deploy_template`, `add.revert_template`, and
  `add.verify_template` config variables with a section, `add.templates`.
* Determine the list of templates by listing the subdirectories of all three
  template directories, `--template-directory` (or `add.template_directory`),
  `~/.sqitch/templates`, and `$etc/sqitch/templates`. Any subdirectory of
  these directories that has a valid template will result in a script being
  generated in a directory with the same name, unless `--without` excludes it.
* Add the `script_file` method to App::Sqitch::Plan::Change, so that we have a
  uniform way of getting the path to any script file, not just the core three.
  The core three sill respect `--deploy-dir`, `--revert-dir`, and
  `--verify-dir`, but any custom scripts have no such luxury
  • Loading branch information...
theory committed Jan 3, 2014
1 parent ab1c230 commit 12468f6945e4b8e666c12c54e3f30f8ad06ff69a
Showing with 531 additions and 262 deletions.
  1. +21 −1 Changes
  2. +119 −64 lib/App/Sqitch/Command/add.pm
  3. +16 −0 lib/App/Sqitch/Plan/Change.pm
  4. +3 −9 lib/sqitch-add-usage.pod
  5. +111 −83 lib/sqitch-add.pod
  6. +235 −98 t/add.t
  7. +10 −5 t/command.t
  8. +1 −2 t/rework.t
  9. +15 −0 t/templates.conf
22 Changes
@@ -57,7 +57,27 @@ Revision history for Perl extension App::Sqitch
command.
- Documented that reworked changes do not have their verify tests run by
the `verify` command.
- Removed the undocumented `--test` option to `add
- Removed the undocumented `--test` option to the `add` command.
- Added support for the generation of arbitrary scripts from templates to
the `add` command. Just add template files to subdirectories of the
`templates` directory, and scripts will be created in a directory of
the same name based on those templates.
- Deprecated the `--deploy-template`, `--revert-template`, and
`--verify-template` options to the `add` command. They are replaced
with a single option, `--use` which takes a key/value pair for the
script name and template path. This makes it useful for arbitrary
script generation, as well.
- Deprecated the `--deploy`, `--revert`, and `--verify` options to the
`add` command, as well as their `--no-*` variants. They are replaced
with two new options, `--with` and `--without`, to which a script name
is passed. These are useful for arbitrary script generation, as well.
- Deprecated the `add.deploy_template`, `add.revert_template`, and
`add.verify_template` configuration settings. They have been replaced
with a section, `add.templates`, which is more general, and supports
arbitrary script generation, as well.
- Removed the documentation for the `add.with_deploy`, `add.with_revert`,
and `add.with_verify` configuration variables, which were never
implemented.

0.983 2013-11-21T21:50:12Z
- Fixed "Use of uninitialized value" in the MySQL engine. Thanks to
@@ -62,26 +62,23 @@ has template_name => (
default => sub { shift->sqitch->_engine },
);

for my $script (qw(deploy revert verify)) {
has "with_$script" => (
is => 'ro',
isa => 'Bool',
lazy => 1,
default => sub {
shift->sqitch->config->get(
key => "add.with_$script",
as => 'bool',
) // 1;
}
);
has with_scripts => (
is => 'ro',
isa => 'HashRef',
required => 1,
default => sub { {} },
);

has "$script\_template" => (
is => 'ro',
isa => 'Path::Class::File',
lazy => 1,
default => sub { shift->_find($script) },
);
}
has templates => (
is => 'ro',
isa => 'HashRef',
required => 1,
lazy => 1,
default => sub {
my $self = shift;
$self->_config_templates($self->sqitch->config);
},
);

has open_editor => (
is => 'ro',
@@ -95,25 +92,68 @@ has open_editor => (
},
);

sub _find {
my ( $self, $script ) = @_;
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 };

# Get legacy config.
for my $script (qw(deploy revert verify)) {
next if $tmpl->{$script};
if (my $file = $config->get( key => "add.$script\_template")) {
$tmpl->{$script} = _check_script $file;
}
}
return $tmpl;
}

sub all_templates {
my $self = shift;
my $config = $self->sqitch->config;
my $name = $self->template_name;
$config->get( key => "add.$script\_template" ) || do {
for my $dir (
$self->template_directory,
$config->user_dir->subdir('templates'),
$config->system_dir->subdir('templates'),
) {
next unless $dir;
my $tmpl = $dir->file($script, "$name.tmpl");
return $tmpl if -f $tmpl;
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 {
@@ -123,14 +163,19 @@ sub options {
note|n|m=s@
template-name|template|t=s
template-directory=s
with=s@
without=s@
use=s%
open-editor|edit|e!
deploy-template=s
revert-template=s
verify-template=s
deploy!
revert!
verify!
open-editor|edit|e!
);
# Those last six are deprecated.
}

# Override to convert multiple vars to an array.
@@ -153,14 +198,28 @@ sub _parse_opts {
}
}
) 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};
}

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

# Merge deprecated use options.
for my $script (qw(deploy revert verify)) {
next unless exists $opts{"$script\_template"};
$opts{use} ||= {};
$opts{use}{$script} = delete $opts{"$script\_template"}
}

return \%opts;
}

@@ -173,6 +232,8 @@ sub configure {
note => $opt->{note} || [],
);

$params{with_scripts} = $opt->{with_scripts} if $opt->{with_scripts};

if (
my $dir = $opt->{template_directory}
|| $config->get( key => 'add.template_directory' )
@@ -187,7 +248,6 @@ sub configure {
'"{dir}" is not a directory',
dir => $dir,
) unless -d $dir;

}

if (
@@ -197,20 +257,23 @@ sub configure {
$params{template_name} = $name;
}

for my $attr (qw(deploy revert verify)) {
$params{"with_$attr"} = $opt->{$attr} if exists $opt->{$attr};
my $t = "$attr\_template";
$params{$t} = file $opt->{$t} if $opt->{$t};
}

# Merge variables.
if ( my $vars = $opt->{set} ) {
# Merge with config.
$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 };

$params{open_editor} = $opt->{open_editor} if exists $opt->{open_editor};

return \%params;
@@ -221,42 +284,29 @@ sub execute {
$self->usage unless defined $name;
my $sqitch = $self->sqitch;
my $plan = $sqitch->plan;
my $with = $self->with_scripts;
my $tmpl = $self->all_templates;
my $change = $plan->add(
name => $name,
requires => $self->requires,
conflicts => $self->conflicts,
note => join "\n\n" => @{ $self->note },
);

my @files = (
($self->with_deploy ? $change->deploy_file : ()),
($self->with_revert ? $change->revert_file : ()),
($self->with_verify ? $change->verify_file : ()),
);
my @scripts = grep {
!exists $with->{$_} || $with->{$_}
} sort keys %{ $tmpl };
my @files = map { $change->script_file($_ ) } @scripts;

# Make sure we have a note.
$change->request_note(
for => __ 'add',
scripts => \@files,
);

$self->_add(
$name,
$change->deploy_file,
$self->deploy_template,
) if $self->with_deploy;

$self->_add(
$name,
$change->revert_file,
$self->revert_template,
) if $self->with_revert;

$self->_add(
$name,
$change->verify_file,
$self->verify_template,
) if $self->with_verify;
# Add the scripts.
my $i = 0;
$self->_add( $name, $files[$i++], $tmpl->{$_} ) for @scripts;

# We good, write the plan file back out.
$plan->write_to( $sqitch->plan_file );
@@ -391,6 +441,11 @@ for the constructor.
Executes the C<add> command.
=head2 C<all_templates>
Returns a hash reference of script names mapped to template files for all
scripts that should be generated for the new change.
=head1 See Also
=over
@@ -226,6 +226,16 @@ sub verify_file {
$self->sqitch->verify_dir->file( $self->path_segments );
}

sub script_file {
my ($self, $name) = @_;
if ( my $meth = $self->can("$name\_file") ) {
return $self->$meth;
}
return $self->sqitch->top_dir->subdir($name)->cleanup->file(
$self->path_segments
);
}

sub is_revert {
shift->operator eq '-';
}
@@ -420,6 +430,12 @@ Returns the path to the revert script file for the change.
Returns the path to the verify script file for the change.
=head3 C<script_file>
my $file = $sqitch->script_file($script_name);
Returns the path to a script, for the change.
=head3 C<rework_tags>
my @tags = $change->rework_tags;
@@ -15,14 +15,8 @@ sqitch-add-usage - Sqitch add usage statement

-t --template name of the templates to use
--template-directory path to directory containing templates
--deploy-template path to deploy template
--revert-template path to revert template
--verify-template path to verify template
--use [template=path] path to named template

--no-deploy do not create deploy script
--no-revert do not create revert script
--no-verify do not create verify script
--deploy create deploy script
--revert create revert script
--verify create verify script
--with [script] create named script
--without [script] do not create named script
-e --edit, --open-editor open change scripts in an editor
Oops, something went wrong.

0 comments on commit 12468f6

Please sign in to comment.