App-TimeTracker

 view release on metacpan or  search on metacpan

lib/App/TimeTracker/Proto.pm  view on Meta::CPAN

package App::TimeTracker::Proto;

# ABSTRACT: App::TimeTracker Proto Class
our $VERSION = '3.010'; # VERSION

use strict;
use warnings;
use 5.010;

use App::TimeTracker::Utils qw(error_message);
use Moose;
use MooseX::Types::Path::Class;
use File::HomeDir ();
use Path::Class;
use Hash::Merge qw(merge);
use JSON::XS;
use Carp;
use Try::Tiny;
use App::TimeTracker::Data::Task;
use App::TimeTracker::Constants qw(MISSING_PROJECT_HELP_MSG);

has 'home' => (
    is         => 'ro',
    isa        => 'Path::Class::Dir',
    lazy_build => 1,
);

sub _build_home {
    my ( $self, $home ) = @_;

    $home ||=
        Path::Class::Dir->new( $ENV{TRACKER_HOME} || (File::HomeDir->my_home, '.TimeTracker' ));
    unless (-d $home) {
        $home->mkpath;
        $self->_write_config_file_locations( {} );
        my $fh = $self->global_config_file->openw;
        print $fh $self->json_decoder->encode( {} );
        close $fh;
    }
    return $home;
}

has 'global_config_file' => (
    is         => 'ro',
    isa        => 'Path::Class::File',
    lazy_build => 1,
);

sub _build_global_config_file {
    my $self = shift;
    return $self->home->file('tracker.json');
}

has 'config_file_locations' => (
    is         => 'ro',
    isa        => 'HashRef',
    lazy_build => 1,
);

sub _build_config_file_locations {
    my $self = shift;
    my $file = $self->home->file('projects.json');
    if ( -e $file && -s $file ) {
        my $decoded_json;
        try {
            $decoded_json = decode_json( $file->slurp );
        }
        catch {
            error_message( "Could not json decode '%s'.\nError: '%s'", $file, $_ );
            exit 1;
        };
        return $decoded_json;
    }
    else {
        return {};
    }
}

has 'project' => ( is => 'rw', isa => 'Str', predicate => 'has_project' );

has 'json_decoder' => ( is => 'ro', isa => 'JSON::XS', lazy_build => 1 );

sub _build_json_decoder {
    my $self = shift;
    return JSON::XS->new->utf8->pretty->canonical->relaxed;
}

sub run {
    my $self = shift;

    try {
        my $config = $self->load_config;
        my $class  = $self->setup_class($config);
        $class->name->new_with_options( {
                home   => $self->home,
                config => $config,
                (   $self->has_project
                    ? ( _current_project => $self->project )
                    : ()
                ),
            } )->run;
    }
    catch {
        my $e = $_;
        if ( blessed $e && $e->can('message') ) {
            warn $e->message, "\n";
        }
        else {
            warn "$e\n";
        }
    }
}

sub setup_class {
    my ( $self, $config, $command ) = @_;

    # unique plugins
    $config->{plugins} ||= [];
    my %plugins_unique = map { $_ => 1 } @{ $config->{plugins} };
    $config->{plugins} = [ keys %plugins_unique ];

    my $class = Moose::Meta::Class->create_anon_class(
        superclasses => ['App::TimeTracker'],
        roles        => [
            map { 'App::TimeTracker::Command::' . $_ } 'Core',
            @{ $config->{plugins} }
        ],
    );

    my %commands;
    foreach my $method ( $class->get_all_method_names ) {
        next unless $method =~ /^cmd_/;
        $method =~ s/^cmd_//;
        $commands{$method} = 1;
    }

    my $load_attribs_for_command;
    foreach my $cmd ( $command ? $command : @ARGV) {
        if ( defined $commands{$cmd} ) {
            $load_attribs_for_command = '_load_attribs_' . $cmd;

            if ($cmd eq 'start' && !$self->has_project) {
                error_message( MISSING_PROJECT_HELP_MSG );
                exit;
            }



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