Code-TidyAll

 view release on metacpan or  search on metacpan

lib/Code/TidyAll/SVN/Precommit.pm  view on Meta::CPAN

package Code::TidyAll::SVN::Precommit;

use strict;
use warnings;

use Capture::Tiny       qw(capture_stdout capture_stderr);
use Code::TidyAll::Util qw(tempdir_simple);
use Code::TidyAll;
use Log::Any   qw($log);
use Path::Tiny qw(path);
use SVN::Look;
use Try::Tiny;

use Moo;

our $VERSION = '0.85';

# Public
has conf_name                => ( is => 'ro' );
has emergency_comment_prefix => ( is => 'ro', default => 'NO TIDYALL' );
has extra_conf_files         => ( is => 'ro', default => sub { [] } );
has reject_on_error          => ( is => 'ro' );
has repos                    => ( is => 'ro', default => sub { $ARGV[0] } );
has tidyall_class            => ( is => 'ro', default => 'Code::TidyAll' );
has tidyall_options          => ( is => 'ro', default => sub { {} } );
has txn                      => ( is => 'ro', default => sub { $ARGV[1] } );

# Private
has cat_file_cache => ( init_arg => undef, is => 'ro', default => sub { {} } );
has revlook        => ( init_arg => undef, is => 'lazy' );

sub _build_revlook {
    my $self = shift;
    return SVN::Look->new( $self->repos, '-t' => $self->txn );
}

sub check {
    my ( $class, %params ) = @_;

    my $fail_msg;

    try {
        my $self    = $class->new(%params);
        my $revlook = $self->revlook;

        # Skip if emergency comment prefix is present
        #
        if ( my $prefix = $self->emergency_comment_prefix ) {
            if ( index( $revlook->log_msg, $prefix ) == 0 ) {
                return;
            }
        }

        my @files = ( $self->revlook->added(), $self->revlook->updated() );
        $log->info('----------------------------');
        $log->infof(
            '%s [%s] repos = %s; txn = %s',
            scalar(localtime), $$, scalar( getpwuid($<) ),
            $self->repos,      $self->txn
        );
        $log->infof( 'looking at files: %s', join( ', ', @files ) );

        my %conf_files;
        foreach my $file (@files) {
            if ( my $conf_file = $self->find_conf_for_file($file) ) {
                my $root     = $conf_file->parent;
                my $rel_file = substr( $file, length($root) + 1 );
                $conf_files{$conf_file}->{$rel_file}++;
            }
            else {
                my $msg = sprintf( q{** could not find conf file upwards from '%s'}, $file );
                $log->error($msg);
                die $msg if $self->reject_on_error;
            }
        }

        my @results;
        for my $conf_file ( map { path($_) } keys %conf_files ) {
            my $file_map = $conf_files{$conf_file};

            my $root      = $conf_file->parent;
            my $conf_name = $conf_file->basename;
            $log->error("$root, $conf_file");
            my $tempdir = tempdir_simple();
            my @files   = keys(%$file_map);
            foreach my $rel_file ( $conf_name, @{ $self->extra_conf_files }, @files ) {

                # TODO: what if cat fails
                my $contents  = $self->cat_file( $root->child($rel_file) );
                my $full_path = $tempdir->child($rel_file);
                $full_path->parent->mkpath( { mode => 0755 } );
                $full_path->spew_raw($contents);
            }
            my $tidyall = $self->tidyall_class->new_from_conf_file(
                $tempdir->child($conf_name),
                no_cache   => 1,
                check_only => 1,
                mode       => 'commit',
                %{ $self->tidyall_options },
            );
            my $stdout = capture_stdout {
                push( @results, $tidyall->process_paths( map { $tempdir->child($_) } @files ) );
            };
            if ($stdout) {
                chomp($stdout);
                $log->info($stdout);
            }
        }

        if ( my @error_results = grep { $_->error } @results ) {
            my $error_count = scalar(@error_results);
            $fail_msg = join(
                "\n",
                sprintf(
                    '%d file%s did not pass tidyall check',
                    $error_count, $error_count > 1 ? 's' : q{}
                ),
                map { join( ': ', $_->path, $_->error ) } @error_results



( run in 1.558 second using v1.01-cache-2.11-cpan-39bf76dae61 )