App-Sqitch

 view release on metacpan or  search on metacpan

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

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

    my %params;

    if (my $dir = $opt->{dest_dir} || $config->get(key => 'bundle.dest_dir') ) {
        $params{dest_dir} = dir $dir;
    }

    # Make sure we get the --all, --from and --to options passed through.
    for my $key (qw(all from to)) {
        $params{$key} = $opt->{$key} if exists $opt->{$key};
    }

    return \%params;
}

sub execute {
    my $self = shift;
    my ($targets, $changes) = $self->parse_args(
        all  => $self->all,
        args => \@_,
    );

    # Warn if --to or --from is specified for more thane one target.
    if ( @{ $targets } > 1 && ($self->from || $self->to) ) {
        $self->sqitch->warn(__(
            "Use of --to or --from to bundle multiple targets is not recommended.\nPass them as arguments after each target argument, instead."
        ));
    }

    # Die if --to or --from and changes are specified.
    if ( @{ $changes } && ($self->from || $self->to) ) {
        hurl bundle => __(
            'Cannot specify both --from or --to and change arguments'
        );
    }

    # Time to get started!
    $self->info(__x 'Bundling into {dir}', dir => $self->dest_dir );
    $self->bundle_config;

    if (my @fromto = grep { $_ } $self->from, $self->to) {
        # One set of from/to options for all targets.
        for my $target (@{ $targets }) {
            $self->bundle_plan($target, @fromto);
            $self->bundle_scripts($target, @fromto);
        }
    } else {
        # Separate from/to options for all targets.
        for my $target (@{ $ targets }) {
            my @fromto = splice @{ $changes }, 0, 2;
            $self->bundle_plan($target, @fromto);
            $self->bundle_scripts($target, @fromto);
        }
    }

    return $self;
}

sub _copy_if_modified {
    my ( $self, $src, $dst ) = @_;

    hurl bundle => __x(
        'Cannot copy {file}: does not exist',
        file => $src,
    ) unless -e $src;

    if (-e $dst) {
        # Skip the file if it is up-to-date.
        return $self if -M $dst <= -M $src;
    } else {
        # Create the directory.
        $self->_mkpath( $dst->dir );
    }

    $self->debug('    ', __x(
        "Copying {source} -> {dest}",
        source => $src,
        dest   => $dst
    ));

    # Stringify to work around bug in File::Copy warning on 5.10.0.
    File::Copy::copy "$src", "$dst" or hurl bundle => __x(
        'Cannot copy "{source}" to "{dest}": {error}',
        source => $src,
        dest   => $dst,
        error  => $!,
    );
    return $self;
}

sub bundle_config {
    my $self = shift;
    $self->info(__ 'Writing config');
    my $file = $self->sqitch->config->local_file;
    $self->_copy_if_modified( $file, $self->dest_dir->file( $file->basename ) );
}

sub bundle_plan {
    my ($self, $target, $from, $to) = @_;

    my $dir = $self->dest_top_dir($target);

    if (!defined $from && !defined $to) {
        $self->info(__ 'Writing plan');
        my $file = $target->plan_file;
        return $self->_copy_if_modified(
            $file,
            $dir->file( $file->basename ),
        );
    }

    $self->info(__x(
        'Writing plan from {from} to {to}',
        from => $from // '@ROOT',
        to   => $to   // '@HEAD',
    ));

    $self->_mkpath( $dir );
    $target->plan->write_to(
        $dir->file( $target->plan_file->basename ),
        $from,
        $to,
    );
}

sub bundle_scripts {
    my ($self, $target, $from, $to) = @_;
    my $plan = $target->plan;

    my $from_index = $plan->index_of(
        $from // '@ROOT'
    ) // hurl bundle => __x(
        'Cannot find change {change}',
        change => $from,
    );

    my $to_index = $plan->index_of(
        $to // '@HEAD'
    ) // hurl bundle => __x(
        'Cannot find change {change}',
        change => $to,
    );

    $self->info(__ 'Writing scripts');
    $plan->position( $from_index );
    my $dir_for = $self->dest_dirs_for($target);

    while ( $plan->position <= $to_index ) {
        my $change = $plan->current // last;
        $self->info('  + ', $change->format_name_with_tags);
        my $prefix = $change->is_reworked ? 'reworked_' : '';
        my @path = $change->path_segments;
        if (-e ( my $file = $change->deploy_file )) {
            $self->_copy_if_modified(
                $file,
                $dir_for->{"${prefix}deploy"}->file(@path)
            );
        }
        if (-e ( my $file = $change->revert_file )) {
            $self->_copy_if_modified(
                $file,
                $dir_for->{"${prefix}revert"}->file(@path)
            );
        }
        if (-e ( my $file = $change->verify_file )) {
            $self->_copy_if_modified(
                $file,
                $dir_for->{"${prefix}verify"}->file(@path)
            );
        }
        $plan->next;
    }

    return $self;
}

1;

__END__

=head1 Name

App::Sqitch::Command::bundle - Bundle Sqitch changes for distribution

=head1 Synopsis

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

=head1 Description

Bundles a Sqitch project for distribution. Done by creating a new directory
and copying the configuration file, plan file, and change files into it.

=head1 Interface

=head2 Attributes

=head3 C<from>

Change from which to build the bundled plan.

=head3 C<to>

Change up to which to build the bundled plan.

=head3 C<all>

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

=head2 Instance Methods

=head3 C<execute>

  $bundle->execute($command);

Executes the C<bundle> command.

=head3 C<bundle_config>

 $bundle->bundle_config;

Copies the configuration file to the bundle directory.

=head3 C<bundle_plan>



( run in 2.222 seconds using v1.01-cache-2.11-cpan-d8267643d1d )