| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package App::Critique::Session; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 2 |  |  | 2 |  | 2044 | use strict; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 56 |  | 
| 4 | 2 |  |  | 2 |  | 7 | use warnings; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 87 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our $VERSION   = '0.03'; | 
| 7 |  |  |  |  |  |  | our $AUTHORITY = 'cpan:STEVAN'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 2 |  |  | 2 |  | 8 | use Scalar::Util        (); | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 20 |  | 
| 10 | 2 |  |  | 2 |  | 7 | use Carp                (); | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 23 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 2 |  |  | 2 |  | 5 | use Path::Tiny          (); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 23 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 2 |  |  | 2 |  | 479 | use Git::Wrapper        (); | 
|  | 2 |  |  |  |  | 23788 |  | 
|  | 2 |  |  |  |  | 29 |  | 
| 15 | 2 |  |  | 2 |  | 976 | use Perl::Critic        (); | 
|  | 2 |  |  |  |  | 1248911 |  | 
|  | 2 |  |  |  |  | 49 |  | 
| 16 | 2 |  |  | 2 |  | 13 | use Perl::Critic::Utils (); | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 30 |  | 
| 17 |  |  |  |  |  |  |  | 
| 18 | 2 |  |  | 2 |  | 8 | use App::Critique; | 
|  | 2 |  |  |  |  | 1 |  | 
|  | 2 |  |  |  |  | 26 |  | 
| 19 | 2 |  |  | 2 |  | 1258 | use App::Critique::Session::File; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 1139 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | sub new { | 
| 22 | 0 |  |  | 0 | 0 |  | my ($class, %args) = @_; | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | Carp::confess('You must specify a git_work_tree') | 
| 25 | 0 | 0 | 0 |  |  |  | unless $args{git_work_tree} && -d $args{git_work_tree}; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | # setup the perl critic instance | 
| 28 | 0 |  |  |  |  |  | my $critic = $class->_initialize_perl_critic( %args ); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | # auto-discover the current git repo and branch | 
| 31 | 0 |  |  |  |  |  | my ($git, $git_branch) = $class->_initialize_git_repo( %args ); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | # now that we have worked out all the details, | 
| 34 |  |  |  |  |  |  | # we need to determine the path to the actual | 
| 35 |  |  |  |  |  |  | # critique file. | 
| 36 | 0 |  |  |  |  |  | my $path = $class->_generate_critique_file_path( $git->dir, $git_branch ); | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | my $self = bless { | 
| 39 |  |  |  |  |  |  | # user supplied ... | 
| 40 |  |  |  |  |  |  | perl_critic_profile => $args{perl_critic_profile}, | 
| 41 |  |  |  |  |  |  | perl_critic_theme   => $args{perl_critic_theme}, | 
| 42 |  |  |  |  |  |  | perl_critic_policy  => $args{perl_critic_policy}, | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | # auto-discovered | 
| 45 | 0 |  |  |  |  |  | git_work_tree       => Path::Tiny::path( $git->dir ), | 
| 46 |  |  |  |  |  |  | git_branch          => $git_branch, | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | # local storage | 
| 49 |  |  |  |  |  |  | current_file_idx    => 0, | 
| 50 |  |  |  |  |  |  | tracked_files       => [], | 
| 51 |  |  |  |  |  |  | file_criteria       => {}, | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | # Do Not Serialize | 
| 54 |  |  |  |  |  |  | _path   => $path, | 
| 55 |  |  |  |  |  |  | _critic => $critic, | 
| 56 |  |  |  |  |  |  | _git    => $git, | 
| 57 |  |  |  |  |  |  | } => $class; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | # handle adding tracked files | 
| 60 | 0 |  |  |  |  |  | $self->set_tracked_files( @{ $args{tracked_files} } ) | 
| 61 | 0 | 0 |  |  |  |  | if exists $args{tracked_files}; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | $self->set_file_criteria( $args{file_criteria} ) | 
| 64 | 0 | 0 |  |  |  |  | if exists $args{file_criteria}; | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | $self->{current_file_idx} = $args{current_file_idx} | 
| 67 | 0 | 0 |  |  |  |  | if exists $args{current_file_idx}; | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 0 |  |  |  |  |  | return $self; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | sub locate_session_file { | 
| 73 | 0 |  |  | 0 | 0 |  | my ($class, $git_work_tree) = @_; | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 0 | 0 |  |  |  |  | Carp::confess('Cannot call locate_session_file with an instance') | 
| 76 |  |  |  |  |  |  | if Scalar::Util::blessed( $class ); | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 0 | 0 | 0 |  |  |  | Carp::confess('You must specify a git-work-tree') | 
| 79 |  |  |  |  |  |  | unless $git_work_tree && -d $git_work_tree; | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 0 |  |  |  |  |  | my ($git, $git_branch) = $class->_initialize_git_repo( git_work_tree => $git_work_tree ); | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 0 |  |  |  |  |  | my $session_file = $class->_generate_critique_file_path( | 
| 84 |  |  |  |  |  |  | Path::Tiny::path( $git->dir ), | 
| 85 |  |  |  |  |  |  | $git_branch | 
| 86 |  |  |  |  |  |  | ); | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 0 |  |  |  |  |  | return $session_file; | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | # accessors | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 0 |  |  | 0 | 0 |  | sub git_work_tree       { $_[0]->{git_work_tree}       } | 
| 94 | 0 |  |  | 0 | 0 |  | sub git_branch          { $_[0]->{git_branch}          } | 
| 95 | 0 |  |  | 0 | 0 |  | sub perl_critic_profile { $_[0]->{perl_critic_profile} } | 
| 96 | 0 |  |  | 0 | 0 |  | sub perl_critic_theme   { $_[0]->{perl_critic_theme}   } | 
| 97 | 0 |  |  | 0 | 0 |  | sub perl_critic_policy  { $_[0]->{perl_critic_policy}  } | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  | 0 | 0 |  | sub tracked_files     { @{ $_[0]->{tracked_files} } } | 
|  | 0 |  |  |  |  |  |  | 
| 100 | 0 |  |  | 0 | 0 |  | sub file_criteria     { $_[0]->{file_criteria} } | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 0 |  |  | 0 | 0 |  | sub current_file_idx { $_[0]->{current_file_idx}   } | 
| 103 | 0 |  |  | 0 | 0 |  | sub inc_file_idx     { $_[0]->{current_file_idx}++ } | 
| 104 | 0 |  |  | 0 | 0 |  | sub dec_file_idx     { $_[0]->{current_file_idx}-- } | 
| 105 | 0 |  |  | 0 | 0 |  | sub reset_file_idx   { $_[0]->{current_file_idx}=0 } | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 0 |  |  | 0 | 0 |  | sub session_file_path { $_[0]->{_path} } | 
| 108 | 0 |  |  | 0 | 0 |  | sub git_wrapper       { $_[0]->{_git}  } | 
| 109 | 0 |  |  | 0 | 0 |  | sub perl_critic       { $_[0]->{_critic} } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | # Instance Methods | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | sub session_file_exists { | 
| 114 | 0 |  |  | 0 | 0 |  | my ($self) = @_; | 
| 115 | 0 |  |  |  |  |  | return !! -e $self->{_path}; | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub set_tracked_files { | 
| 119 | 0 |  |  | 0 | 0 |  | my ($self, @files) = @_; | 
| 120 | 0 |  |  |  |  |  | @{ $self->{tracked_files} } = map { | 
| 121 | 0 | 0 | 0 |  |  |  | (Scalar::Util::blessed($_) && $_->isa('App::Critique::Session::File') | 
|  | 0 | 0 |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | ? $_ | 
| 123 |  |  |  |  |  |  | : ((ref $_ eq 'HASH') | 
| 124 |  |  |  |  |  |  | ? App::Critique::Session::File->new( %$_ ) | 
| 125 |  |  |  |  |  |  | : App::Critique::Session::File->new( path => $_ ))) | 
| 126 |  |  |  |  |  |  | } @files; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | sub set_file_criteria { | 
| 130 | 0 |  |  | 0 | 0 |  | my ($self, $filters_used) = @_; | 
| 131 |  |  |  |  |  |  | $self->{file_criteria}->{ $_ } = $filters_used->{ $_ } | 
| 132 | 0 |  |  |  |  |  | foreach keys %$filters_used; | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | # ... | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | sub pack { | 
| 138 | 0 |  |  | 0 | 0 |  | my ($self) = @_; | 
| 139 |  |  |  |  |  |  | return +{ | 
| 140 |  |  |  |  |  |  | perl_critic_profile => ($self->{perl_critic_profile} ? $self->{perl_critic_profile}->stringify : undef), | 
| 141 |  |  |  |  |  |  | perl_critic_theme   => $self->{perl_critic_theme}, | 
| 142 |  |  |  |  |  |  | perl_critic_policy  => $self->{perl_critic_policy}, | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | git_work_tree       => ($self->{git_work_tree} ? $self->{git_work_tree}->stringify : undef), | 
| 145 |  |  |  |  |  |  | git_branch          => $self->{git_branch}, | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | current_file_idx    => $self->{current_file_idx}, | 
| 148 | 0 |  |  |  |  |  | tracked_files       => [ map $_->pack, @{ $self->{tracked_files} } ], | 
| 149 |  |  |  |  |  |  | file_criteria       => $self->{file_criteria} | 
| 150 | 0 | 0 |  |  |  |  | }; | 
|  |  | 0 |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | sub unpack { | 
| 154 | 0 |  |  | 0 | 0 |  | my ($class, $data) = @_; | 
| 155 | 0 |  |  |  |  |  | return $class->new( %$data ); | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | # ... | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | sub load { | 
| 161 | 0 |  |  | 0 | 0 |  | my ($class, $path) = @_; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 | 0 | 0 |  |  |  | Carp::confess('Invalid path: ' . $path) | 
| 164 |  |  |  |  |  |  | unless $path->exists && $path->is_file; | 
| 165 |  |  |  |  |  |  |  | 
| 166 | 0 |  |  |  |  |  | my $file = Path::Tiny::path( $path ); | 
| 167 | 0 |  |  |  |  |  | my $json = $file->slurp; | 
| 168 | 0 |  |  |  |  |  | my $data = $App::Critique::JSON->decode( $json ); | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 0 |  |  |  |  |  | return $class->unpack( $data ); | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub store { | 
| 174 | 0 |  |  | 0 | 0 |  | my ($self) = @_; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 |  |  |  |  |  | my $file = $self->{_path}; | 
| 177 | 0 |  |  |  |  |  | my $data = $self->pack; | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | eval { | 
| 180 |  |  |  |  |  |  | # JSON might die here ... | 
| 181 | 0 |  |  |  |  |  | my $json = $App::Critique::JSON->encode( $data ); | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | # if the file does not exist | 
| 184 |  |  |  |  |  |  | # then we should try and make | 
| 185 |  |  |  |  |  |  | # the path, just in case ... | 
| 186 | 0 | 0 |  |  |  |  | $file->parent->mkpath unless -e $file; | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | # now try and write out the JSON | 
| 189 | 0 |  |  |  |  |  | my $fh = $file->openw; | 
| 190 | 0 |  |  |  |  |  | $fh->print( $json ); | 
| 191 | 0 |  |  |  |  |  | $fh->close; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 0 |  |  |  |  |  | 1; | 
| 194 | 0 | 0 |  |  |  |  | } or do { | 
| 195 | 0 |  |  |  |  |  | Carp::confess('Unable to store critique session file because: ' . $@); | 
| 196 |  |  |  |  |  |  | }; | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | # ... | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | sub _generate_critique_dir_path { | 
| 202 | 0 |  |  | 0 |  |  | my ($class, $git_work_tree, $git_branch) = @_; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 0 |  |  |  |  |  | my $root = Path::Tiny::path( $App::Critique::CONFIG{'HOME'} ); | 
| 205 | 0 |  |  |  |  |  | my $git  = Path::Tiny::path( $git_work_tree ); | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | # ~/.critique/<git-repo-name>/<git-branch-name>/session.json | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 0 |  |  |  |  |  | $root->child( '.critique' ) | 
| 210 |  |  |  |  |  |  | ->child( $git->basename ) | 
| 211 |  |  |  |  |  |  | ->child( $git_branch ); | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | sub _generate_critique_file_path { | 
| 215 | 0 |  |  | 0 |  |  | my ($class, $git_work_tree, $git_branch) = @_; | 
| 216 | 0 |  |  |  |  |  | $class->_generate_critique_dir_path( | 
| 217 |  |  |  |  |  |  | $git_work_tree, | 
| 218 |  |  |  |  |  |  | $git_branch | 
| 219 |  |  |  |  |  |  | )->child( | 
| 220 |  |  |  |  |  |  | 'session.json' | 
| 221 |  |  |  |  |  |  | ); | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | sub _initialize_git_repo { | 
| 225 | 0 |  |  | 0 |  |  | my ($class, %args) = @_; | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 0 |  |  |  |  |  | my $git = Git::Wrapper->new( $args{git_work_tree} ); | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | # auto-discover the current git branch | 
| 230 | 0 |  |  |  |  |  | my ($git_branch) = map /^\*\s(.*)$/, grep /^\*/, $git->branch; | 
| 231 |  |  |  |  |  |  |  | 
| 232 | 0 | 0 |  |  |  |  | Carp::confess('Unable to determine git branch, looks like your repository is bare') | 
| 233 |  |  |  |  |  |  | unless $git_branch; | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | # make sure the branch we are on is the | 
| 236 |  |  |  |  |  |  | # same one we are being asked to load, | 
| 237 |  |  |  |  |  |  | # this is very much unlikely to happen | 
| 238 |  |  |  |  |  |  | # but something we should die about none | 
| 239 |  |  |  |  |  |  | # the less. | 
| 240 |  |  |  |  |  |  | Carp::confess('Attempting to inflate session for branch ('.$args{git_branch}.') but branch ('.$git_branch.') is currently active') | 
| 241 | 0 | 0 | 0 |  |  |  | if exists $args{git_branch} && $args{git_branch} ne $git_branch; | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | # if all is well, return ... | 
| 244 | 0 |  |  |  |  |  | return ($git, $git_branch); | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | sub _initialize_perl_critic { | 
| 248 | 0 |  |  | 0 |  |  | my ($class, %args) = @_; | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 0 |  |  |  |  |  | my $critic; | 
| 251 | 0 | 0 |  |  |  |  | if ( $args{perl_critic_policy} ) { | 
| 252 | 0 |  |  |  |  |  | $critic = Perl::Critic->new( '-single-policy' => $args{perl_critic_policy} ); | 
| 253 |  |  |  |  |  |  | } | 
| 254 |  |  |  |  |  |  | else { | 
| 255 |  |  |  |  |  |  | $critic = Perl::Critic->new( | 
| 256 |  |  |  |  |  |  | ($args{perl_critic_profile} ? ('-profile' => $args{perl_critic_profile}) : ()), | 
| 257 | 0 | 0 |  |  |  |  | ($args{perl_critic_theme}   ? ('-theme'   => $args{perl_critic_theme})   : ()), | 
|  |  | 0 |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | ); | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | # inflate this as needed | 
| 261 |  |  |  |  |  |  | $args{perl_critic_profile} = Path::Tiny::path( $args{perl_critic_profile} ) | 
| 262 | 0 | 0 |  |  |  |  | if $args{perl_critic_profile}; | 
| 263 |  |  |  |  |  |  | } | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 0 |  |  |  |  |  | return $critic; | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | 1; | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | =pod | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | =head1 NAME | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | App::Critique::Session - Session interface for App::Critique | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | =head1 VERSION | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | version 0.03 | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | This is the main interace to the L<App::Critique> session file | 
| 283 |  |  |  |  |  |  | and contains no real user serviceable parts. | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | =head1 AUTHOR | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | Stevan Little <stevan@cpan.org> | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | This software is copyright (c) 2016 by Stevan Little. | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 294 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | =cut | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | __END__ | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # ABSTRACT: Session interface for App::Critique | 
| 301 |  |  |  |  |  |  |  |