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 )