App-GitGot
view release on metacpan or search on metacpan
lib/App/GitGot/Command.pm view on Meta::CPAN
package App::GitGot::Command;
our $AUTHORITY = 'cpan:GENEHACK';
$App::GitGot::Command::VERSION = '1.339';
# ABSTRACT: Base class for App::GitGot commands
use 5.014;
use App::Cmd::Setup -command;
use Cwd;
use File::HomeDir::Tiny ();
use List::Util qw/ max first /;
use Path::Tiny;
use Try::Tiny;
use Types::Standard -types;
use YAML qw/ DumpFile LoadFile /;
use App::GitGot::Repo::Git;
use App::GitGot::Repositories;
use App::GitGot::Types -all;
use Moo;
use MooX::HandlesVia;
use namespace::autoclean;
sub opt_spec {
my( $class , $app ) = @_;
return (
[ 'all|a' => 'use all available repositories' ] ,
[ 'by_path|p' => 'if set, output will be sorted by repo path (default: sort by repo name)' ] ,
[ 'color_scheme|c=s' => 'name of color scheme to use' => { default => 'dark' } ] ,
[ 'configfile|f=s' => 'path to config file' => { default => path( File::HomeDir::Tiny::home() , '.gitgot') , required => 1 } ] ,
[ 'no_color|C' => 'do not use colored output' => { default => 0 } ] ,
[ 'quiet|q' => 'keep it down' ] ,
[ 'skip_tags|T=s@' => 'select repositories not tagged with these words' ] ,
[ 'tags|t=s@' => 'select repositories tagged with these words' ] ,
[ 'verbose|v' => 'bring th\' noise'] ,
$class->options($app)
);
}
sub options {}
has active_repo_list => (
is => 'lazy',
isa => ArrayRef[GotRepo] ,
handles_via => 'Array' ,
handles => {
active_repos => 'elements' ,
} ,
);
sub _build_active_repo_list {
my ( $self ) = @_;
return $self->full_repo_list
if $self->all or ! $self->tags and ! $self->skip_tags and ! @{ $self->args };
my $list = _expand_arg_list( $self->args );
my @repos;
REPO: foreach my $repo ( $self->all_repos ) {
if ( grep { $_ eq $repo->number or $_ eq $repo->name } @$list ) {
push @repos, $repo;
next REPO;
}
if ( $self->skip_tags ) {
foreach my $tag ( @{ $self->skip_tags } ) {
next REPO if grep { $repo->tags =~ /\b$_\b/ } $tag;
}
}
if ( $self->tags ) {
foreach my $tag ( @{ $self->tags } ) {
if ( grep { $repo->tags =~ /\b$_\b/ } $tag ) {
push @repos, $repo;
next REPO;
}
}
}
push @repos, $repo unless $self->tags or @$list;
}
return \@repos;
}
has args => (
is => 'rwp' ,
isa => ArrayRef ,
);
has full_repo_list => (
is => 'lazy',
isa => ArrayRef[GotRepo] ,
writer => 'set_full_repo_list' ,
handles_via => 'Array' ,
handles => {
add_repo => 'push' ,
all_repos => 'elements' ,
} ,
);
sub _build_full_repo_list {
my $self = shift;
my $config = _read_config( $self->configfile );
my $repo_count = 1;
my $sort_key = $self->by_path ? 'path' : 'name';
my @parsed_config;
foreach my $entry ( sort { $a->{$sort_key} cmp $b->{$sort_key} } @$config ) {
# a completely empty entry is okay (this will happen when there's no
# config at all...)
keys %$entry or next;
lib/App/GitGot/Command.pm view on Meta::CPAN
# set up colored output if we page thru less
# also exit pager immediately if <1 page of output
$ENV{LESS} = 'RFX';
# don't catch any errors here; if this fails we just output stuff like
# normal and nobody is the wiser.
eval 'use IO::Page' if $self->_use_io_page;
$self->_execute($opt,$args);
}
sub local_repo {
my $self = shift;
my $dir = $self->_find_repo_root( getcwd() );
return first { $_->path eq $dir->absolute } $self->all_repos;
}
sub max_length_of_an_active_repo_label {
my( $self ) = @_;
my $sort_key = $self->by_path ? 'path' : 'name';
return max ( map { length $_->$sort_key } $self->active_repos);
}
sub prompt_yn {
my( $self , $message ) = @_;
printf '%s [y/N]: ' , $message;
chomp( my $response = <STDIN> );
return lc($response) eq 'y';
}
sub search_repos {
my $self = shift;
return App::GitGot::Repositories->new(
repos => [ $self->all_repos ]
);
}
sub write_config {
my ($self) = @_;
DumpFile(
$self->configfile,
[
sort { $a->{name} cmp $b->{name} }
map { $_->in_writable_format } $self->all_repos
] ,
);
}
sub _expand_arg_list {
my $args = shift;
## no critic
return [
map {
s!/$!!;
if (/^(\d+)-(\d+)?$/) { ( $1 .. $2 ) }
else { ($_) }
} @$args
];
## use critic
}
sub _fetch {
my( $self , @repos ) = @_;
my $max_len = $self->max_length_of_an_active_repo_label;
REPO: for my $repo ( @repos ) {
next REPO unless $repo->repo;
my $name = $repo->name;
my $msg = sprintf "%3d) %-${max_len}s : ", $repo->number, $repo->label;
my ( $status, $fxn );
my $repo_type = $repo->type;
if ( $repo_type eq 'git' ) { $fxn = '_git_fetch' }
### FIXME elsif( $repo_type eq 'svn' ) { $fxn = 'svn_update' }
else { $status = $self->error("ERROR: repo type '$_' not supported") }
$status = $self->$fxn($repo) if ($fxn);
next REPO if $self->quiet and !$status;
say "$msg$status";
}
}
sub _find_repo_root {
my( $self , $path ) = @_;
my $dir = path( $path );
# find repo root
while ( ! grep { -d and $_->basename eq '.git' } $dir->children ) {
die "$path doesn't seem to be in a git directory\n" if $dir eq $dir->parent;
$dir = $dir->parent;
}
return $dir
}
sub _git_clone_or_callback {
my( $self , $entry , $callback ) = @_
or die "Need entry and callback";
( run in 0.316 second using v1.01-cache-2.11-cpan-b85c58fdc1d )