]> Dogcows Code - chaz/git-codeowners/blobdiff - lib/App/Codeowners.pm
refactor formatters
[chaz/git-codeowners] / lib / App / Codeowners.pm
index c3d01d30ba4151be5ab30e6249bdf7aeb7864d99..20be9855fa51d7917a683fb6ce8c0321f7c6ff87 100644 (file)
@@ -6,8 +6,9 @@ use utf8;
 use warnings;
 use strict;
 
+use App::Codeowners::Formatter;
 use App::Codeowners::Options;
-use App::Codeowners::Util qw(find_codeowners_in_directory run_git git_ls_files git_toplevel stringf);
+use App::Codeowners::Util qw(find_codeowners_in_directory run_git git_ls_files git_toplevel);
 use Color::ANSI::Util 0.03 qw(ansifg);
 use Encode qw(encode);
 use File::Codeowners;
@@ -50,26 +51,25 @@ sub _command_show {
         or die "No CODEOWNERS file in $toplevel\n";
     my $codeowners = File::Codeowners->parse_from_filepath($codeowners_path);
 
-    my ($cdup) = run_git(qw{rev-parse --show-cdup});
+    my ($proc, $cdup) = run_git(qw{rev-parse --show-cdup});
+    $proc->wait and exit 1;
 
-    my @results;
+    my $formatter = App::Codeowners::Formatter->new(
+        format  => $opts->{format} || ' * %-50F %O',
+        handle  => *STDOUT,
+        columns => [qw(File Owner), $opts->{project} ? 'Project' : ()],
+    );
 
-    my $filepaths = git_ls_files('.', $opts->args) or die "Cannot list files\n";
-    for my $filepath (@$filepaths) {
+    $proc = git_ls_files('.', $opts->args);
+    while (my $filepath = $proc->next) {
         my $match = $codeowners->match(path($filepath)->relative($cdup));
-        push @results, [
+        $formatter->add_result([
             $filepath,
             $match->{owners},
             $opts->{project} ? $match->{project} : (),
-        ];
+        ]);
     }
-
-    _format(
-        format  => $opts->{format} || ' * %-50F %O',
-        out     => *STDOUT,
-        headers => [qw(File Owner), $opts->{project} ? 'Project' : ()],
-        rows    => \@results,
-    );
+    $proc->wait and exit 1;
 }
 
 sub _command_owners {
@@ -84,12 +84,12 @@ sub _command_owners {
 
     my $results = $codeowners->owners($opts->{pattern});
 
-    _format(
+    my $formatter = App::Codeowners::Formatter->new(
         format  => $opts->{format} || '%O',
-        out     => *STDOUT,
-        headers => [qw(Owner)],
-        rows    => [map { [$_] } @$results],
+        handle  => *STDOUT,
+        columns => [qw(Owner)],
     );
+    $formatter->add_result(map { [$_] } @$results);
 }
 
 sub _command_patterns {
@@ -104,12 +104,12 @@ sub _command_patterns {
 
     my $results = $codeowners->patterns($opts->{owner});
 
-    _format(
+    my $formatter = App::Codeowners::Formatter->new(
         format  => $opts->{format} || '%T',
-        out     => *STDOUT,
-        headers => [qw(Pattern)],
-        rows    => [map { [$_] } @$results],
+        handle  => *STDOUT,
+        columns => [qw(Pattern)],
     );
+    $formatter->add_result(map { [$_] } @$results);
 }
 
 sub _command_create { goto &_command_update }
@@ -165,166 +165,4 @@ END
     print STDERR "Wrote $path\n";
 }
 
-sub _format {
-    my %args = @_;
-
-    my $format  = $args{format}  || 'table';
-    my $fh      = $args{out}     || *STDOUT;
-    my $headers = $args{headers} || [];
-    my $rows    = $args{rows}    || [];
-
-    if ($format eq 'table') {
-        eval { require Text::Table::Any } or die "Missing dependency: Text::Table::Any\n";
-
-        my $table = Text::Table::Any::table(
-            header_row  => 1,
-            rows        => [$headers, map { [map { _stringify($_) } @$_] } @$rows],
-            backend     => $ENV{PERL_TEXT_TABLE},
-        );
-        print { $fh } encode('UTF-8', $table);
-    }
-    elsif ($format =~ /^json(:pretty)?$/) {
-        my $pretty = !!$1;
-        eval { require JSON::MaybeXS } or die "Missing dependency: JSON::MaybeXS\n";
-
-        my $json = JSON::MaybeXS->new(canonical => 1, utf8 => 1, pretty => $pretty);
-        my $data = _combine_headers_rows($headers, $rows);
-        print { $fh } $json->encode($data);
-    }
-    elsif ($format =~ /^([ct])sv$/) {
-        my $sep = $1 eq 'c' ? ',' : "\t";
-        eval { require Text::CSV } or die "Missing dependency: Text::CSV\n";
-
-        my $csv = Text::CSV->new({binary => 1, eol => $/, sep => $sep});
-        $csv->print($fh, $headers);
-        $csv->print($fh, [map { encode('UTF-8', _stringify($_)) } @$_]) for @$rows;
-    }
-    elsif ($format =~ /^ya?ml$/) {
-        eval { require YAML } or die "Missing dependency: YAML\n";
-
-        my $data = _combine_headers_rows($headers, $rows);
-        print { $fh } encode('UTF-8', YAML::Dump($data));
-    }
-    else {
-        my $data = _combine_headers_rows($headers, $rows);
-
-        # https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
-        my @contrasting_colors = qw(
-            e6194b 3cb44b ffe119 4363d8 f58231
-            911eb4 42d4f4 f032e6 bfef45 fabebe
-            469990 e6beff 9a6324 fffac8 800000
-            aaffc3 808000 ffd8b1 000075 a9a9a9
-        );
-
-        # assign a color to each owner, on demand
-        my %owner_colors;
-        my $num = -1;
-        my $owner_color = sub {
-            my $owner = shift or return;
-            $owner_colors{$owner} ||= do {
-                $num = ($num + 1) % scalar @contrasting_colors;
-                $contrasting_colors[$num];
-            };
-        };
-
-        my %filter = (
-            quote   => sub { local $_ = $_[0]; s/"/\"/s; "\"$_\"" },
-        );
-
-        my $create_filterer = sub {
-            my $value = shift || '';
-            my $color = shift || '';
-            my $gencolor = ref($color) eq 'CODE' ? $color : sub { $color };
-            return sub {
-                my $arg = shift;
-                my ($filters, $color) = _expand_filter_args($arg);
-                if (ref($value) eq 'ARRAY') {
-                    $value = join(',', map { _colored($_, $color // $gencolor->($_)) } @$value);
-                }
-                else {
-                    $value = _colored($value, $color // $gencolor->($value));
-                }
-                for my $key (@$filters) {
-                    if (my $filter = $filter{$key}) {
-                        $value = $filter->($value);
-                    }
-                    else {
-                        warn "Unknown filter: $key\n"
-                    }
-                }
-                $value || '';
-            };
-        };
-
-        for my $row (@$data) {
-            my %info = (
-                F => $create_filterer->($row->{File},    undef),
-                O => $create_filterer->($row->{Owner},   $owner_color),
-                P => $create_filterer->($row->{Project}, undef),
-                T => $create_filterer->($row->{Pattern}, undef),
-            );
-
-            my $text = stringf($format, %info);
-            print { $fh } encode('UTF-8', $text), "\n";
-        }
-    }
-}
-
-sub _expand_filter_args {
-    my $arg = shift || '';
-
-    my @filters = split(/,/, $arg);
-    my $color_override;
-
-    for (my $i = 0; $i < @filters; ++$i) {
-        my $filter = $filters[$i] or next;
-        if ($filter =~ /^(?:nocolor|color:([0-9a-fA-F]{3,6}))$/) {
-            $color_override = $1 || '';
-            splice(@filters, $i, 1);
-            redo;
-        }
-    }
-
-    return (\@filters, $color_override);
-}
-
-sub _ansi_reset { "\033[0m" }
-
-sub _colored {
-    my $text = shift;
-    my $rgb  = shift or return $text;
-
-    return $text if $ENV{NO_COLOR};
-
-    $rgb =~ s/^(.)(.)(.)$/$1$1$2$2$3$3/;
-    if ($rgb !~ m/^[0-9a-fA-F]{6}$/) {
-        warn "Color value must be in 'ffffff' or 'fff' form.\n";
-        return $text;
-    }
-
-    my ($begin, $end) = (ansifg($rgb), _ansi_reset);
-    return "${begin}${text}${end}";
-}
-
-sub _combine_headers_rows {
-    my $headers = shift;
-    my $rows    = shift;
-
-    my @new_rows;
-
-    for my $row (@$rows) {
-        push @new_rows, (my $new_row = {});
-        for (my $i = 0; $i < @$headers; ++$i) {
-            $new_row->{$headers->[$i]} = $row->[$i];
-        }
-    }
-
-    return \@new_rows;
-}
-
-sub _stringify {
-    my $item = shift;
-    return ref($item) eq 'ARRAY' ? join(',', @$item) : $item;
-}
-
 1;
This page took 0.025383 seconds and 4 git commands to generate.