| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | use 5.010; | 
| 3 | 50 |  |  | 50 |  | 930 | use utf8; | 
|  | 50 |  |  |  |  | 172 |  | 
| 4 | 50 |  |  | 50 |  | 251 | use namespace::autoclean; | 
|  | 50 |  |  |  |  | 96 |  | 
|  | 50 |  |  |  |  | 275 |  | 
| 5 | 50 |  |  | 50 |  | 1057 | use Encode; | 
|  | 50 |  |  |  |  | 91 |  | 
|  | 50 |  |  |  |  | 301 |  | 
| 6 | 50 |  |  | 50 |  | 3423 | use Moo; | 
|  | 50 |  |  |  |  | 105 |  | 
|  | 50 |  |  |  |  | 3860 |  | 
| 7 | 50 |  |  | 50 |  | 307 | use App::Sqitch::Types qw(Str Bool Maybe Change Tag Depend UserEmail DateTime ArrayRef); | 
|  | 50 |  |  |  |  | 125 |  | 
|  | 50 |  |  |  |  | 293 |  | 
| 8 | 50 |  |  | 50 |  | 17574 | use App::Sqitch::Plan::Depend; | 
|  | 50 |  |  |  |  | 115 |  | 
|  | 50 |  |  |  |  | 502 |  | 
| 9 | 50 |  |  | 50 |  | 89084 | use Locale::TextDomain qw(App-Sqitch); | 
|  | 50 |  |  |  |  | 146 |  | 
|  | 50 |  |  |  |  | 1680 |  | 
| 10 | 50 |  |  | 50 |  | 354 | extends 'App::Sqitch::Plan::Line'; | 
|  | 50 |  |  |  |  | 116 |  | 
|  | 50 |  |  |  |  | 380 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our $VERSION = 'v1.3.0'; # VERSION | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | has _requires => ( | 
| 15 |  |  |  |  |  |  | is       => 'ro', | 
| 16 |  |  |  |  |  |  | isa      => ArrayRef[Depend], | 
| 17 |  |  |  |  |  |  | init_arg => 'requires', | 
| 18 |  |  |  |  |  |  | default  => sub { [] }, | 
| 19 |  |  |  |  |  |  | ); | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  |  | 
| 22 | 1881 |  |  | 1881 | 1 | 7595 | has _conflicts => ( | 
|  | 1881 |  |  |  |  | 5554 |  | 
| 23 |  |  |  |  |  |  | is       => 'ro', | 
| 24 |  |  |  |  |  |  | isa      => ArrayRef[Depend], | 
| 25 |  |  |  |  |  |  | init_arg => 'conflicts', | 
| 26 |  |  |  |  |  |  | default  => sub { [] }, | 
| 27 |  |  |  |  |  |  | ); | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | has pspace => ( | 
| 31 | 1111 |  |  | 1111 | 1 | 5152 | is       => 'ro', | 
|  | 1111 |  |  |  |  | 3529 |  | 
| 32 |  |  |  |  |  |  | isa      => Str, | 
| 33 |  |  |  |  |  |  | default  => ' ', | 
| 34 |  |  |  |  |  |  | ); | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | has since_tag => ( | 
| 37 |  |  |  |  |  |  | is       => 'ro', | 
| 38 |  |  |  |  |  |  | isa      => Tag, | 
| 39 |  |  |  |  |  |  | ); | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | has parent => ( | 
| 42 |  |  |  |  |  |  | is       => 'ro', | 
| 43 |  |  |  |  |  |  | isa      => Change, | 
| 44 |  |  |  |  |  |  | ); | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | has _rework_tags => ( | 
| 47 |  |  |  |  |  |  | is       => 'ro', | 
| 48 |  |  |  |  |  |  | isa      => ArrayRef[Tag], | 
| 49 |  |  |  |  |  |  | init_arg => 'rework_tags', | 
| 50 |  |  |  |  |  |  | lazy     => 1, | 
| 51 |  |  |  |  |  |  | default  => sub { [] }, | 
| 52 |  |  |  |  |  |  | ); | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | after add_rework_tags => sub { | 
| 56 |  |  |  |  |  |  | my $self = shift; | 
| 57 | 154 |  |  | 154 | 1 | 500 | # Need to reset the file name if a new value is passed. | 
|  | 154 |  |  |  |  | 2054 |  | 
| 58 |  |  |  |  |  |  | $self->_clear_path_segments(undef); | 
| 59 | 1 |  |  | 1 | 1 | 548 | }; | 
|  | 1 |  |  |  |  | 23 |  | 
| 60 | 685 |  |  | 685 | 1 | 2505 |  | 
|  | 685 |  |  |  |  | 8845 |  | 
| 61 |  |  |  |  |  |  | has _tags => ( | 
| 62 |  |  |  |  |  |  | is         => 'ro', | 
| 63 |  |  |  |  |  |  | isa        => ArrayRef[Tag], | 
| 64 |  |  |  |  |  |  | lazy       => 1, | 
| 65 |  |  |  |  |  |  | default    => sub { [] }, | 
| 66 |  |  |  |  |  |  | ); | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | has _path_segments => ( | 
| 70 |  |  |  |  |  |  | is       => 'ro', | 
| 71 |  |  |  |  |  |  | isa      => ArrayRef[Str], | 
| 72 |  |  |  |  |  |  | lazy     => 1, | 
| 73 |  |  |  |  |  |  | clearer  => 1, # Creates _clear_path_segments(). | 
| 74 |  |  |  |  |  |  | default  => sub { | 
| 75 | 1578 |  |  | 1578 | 1 | 12512 | my $self = shift; | 
|  | 1578 |  |  |  |  | 22750 |  | 
| 76 | 575 |  |  | 575 | 1 | 10269 | my @path = split m{/} => $self->name; | 
|  | 575 |  |  |  |  | 9405 |  | 
| 77 |  |  |  |  |  |  | my $ext  = '.' . $self->target->extension; | 
| 78 |  |  |  |  |  |  | if (my @rework_tags = $self->rework_tags) { | 
| 79 |  |  |  |  |  |  | # Determine suffix based on the first one found in the deploy dir. | 
| 80 |  |  |  |  |  |  | my $dir = $self->deploy_dir; | 
| 81 |  |  |  |  |  |  | my $bn  = pop @path; | 
| 82 |  |  |  |  |  |  | my $first; | 
| 83 |  |  |  |  |  |  | for my $tag (@rework_tags) { | 
| 84 |  |  |  |  |  |  | my $fn = join '', $bn, $tag->format_name, $ext; | 
| 85 |  |  |  |  |  |  | $first //= $fn; | 
| 86 |  |  |  |  |  |  | if ( -e $dir->file(@path, $fn) ) { | 
| 87 |  |  |  |  |  |  | push @path => $fn; | 
| 88 |  |  |  |  |  |  | $first = undef; | 
| 89 |  |  |  |  |  |  | last; | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | push @path => $first if defined $first; | 
| 93 |  |  |  |  |  |  | } else { | 
| 94 |  |  |  |  |  |  | $path[-1] .= $ext; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  | return \@path; | 
| 97 |  |  |  |  |  |  | }, | 
| 98 |  |  |  |  |  |  | ); | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | has info => ( | 
| 102 |  |  |  |  |  |  | is       => 'ro', | 
| 103 |  |  |  |  |  |  | isa      => Str, | 
| 104 |  |  |  |  |  |  | lazy     => 1, | 
| 105 |  |  |  |  |  |  | default  => sub { | 
| 106 |  |  |  |  |  |  | my $self = shift; | 
| 107 |  |  |  |  |  |  | my $reqs  = join "\n  + ", map { $_->as_string } $self->requires; | 
| 108 |  |  |  |  |  |  | my $confs = join "\n  - ", map { $_->as_string } $self->conflicts; | 
| 109 | 632 |  |  | 632 | 1 | 35642 | return join "\n", ( | 
|  | 632 |  |  |  |  | 8282 |  | 
| 110 |  |  |  |  |  |  | 'project ' . $self->project, | 
| 111 |  |  |  |  |  |  | ( $self->uri ? ( 'uri ' . $self->uri->canonical ) : () ), | 
| 112 |  |  |  |  |  |  | 'change '  . $self->format_name, | 
| 113 |  |  |  |  |  |  | ( $self->parent ? ( 'parent ' . $self->parent->id ) : () ), | 
| 114 |  |  |  |  |  |  | 'planner ' . $self->format_planner, | 
| 115 |  |  |  |  |  |  | 'date '    . $self->timestamp->as_string, | 
| 116 |  |  |  |  |  |  | ( $reqs  ? "requires\n  + $reqs" : ()), | 
| 117 |  |  |  |  |  |  | ( $confs ? "conflicts\n  - $confs" : ()), | 
| 118 |  |  |  |  |  |  | ( $self->note ? ('', $self->note) : ()), | 
| 119 |  |  |  |  |  |  | ); | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  | ); | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | has id => ( | 
| 124 |  |  |  |  |  |  | is       => 'ro', | 
| 125 |  |  |  |  |  |  | isa      => Str, | 
| 126 |  |  |  |  |  |  | lazy     => 1, | 
| 127 |  |  |  |  |  |  | default  => sub { | 
| 128 |  |  |  |  |  |  | my $content = encode_utf8 shift->info; | 
| 129 |  |  |  |  |  |  | require Digest::SHA; | 
| 130 |  |  |  |  |  |  | return Digest::SHA->new(1)->add( | 
| 131 |  |  |  |  |  |  | 'change ' . length($content) . "\0" . $content | 
| 132 |  |  |  |  |  |  | )->hexdigest; | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  | ); | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | has timestamp => ( | 
| 137 |  |  |  |  |  |  | is       => 'ro', | 
| 138 |  |  |  |  |  |  | isa      => DateTime, | 
| 139 |  |  |  |  |  |  | default  => sub { require App::Sqitch::DateTime && App::Sqitch::DateTime->now }, | 
| 140 |  |  |  |  |  |  | ); | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | has planner_name => ( | 
| 143 |  |  |  |  |  |  | is       => 'ro', | 
| 144 |  |  |  |  |  |  | isa      => Str, | 
| 145 |  |  |  |  |  |  | default  => sub { shift->sqitch->user_name }, | 
| 146 |  |  |  |  |  |  | ); | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | has planner_email => ( | 
| 149 |  |  |  |  |  |  | is       => 'ro', | 
| 150 |  |  |  |  |  |  | isa      => UserEmail, | 
| 151 |  |  |  |  |  |  | default  => sub { shift->sqitch->user_email }, | 
| 152 |  |  |  |  |  |  | ); | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | has script_hash => ( | 
| 155 |  |  |  |  |  |  | is       => 'ro', | 
| 156 |  |  |  |  |  |  | isa      => Maybe[Str], | 
| 157 |  |  |  |  |  |  | lazy     => 1, | 
| 158 |  |  |  |  |  |  | builder => '_deploy_hash' | 
| 159 |  |  |  |  |  |  | ); | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | my $self = shift; | 
| 162 |  |  |  |  |  |  | return $self->requires, $self->conflicts; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | my $self = shift; | 
| 166 |  |  |  |  |  |  | my $target = $self->target; | 
| 167 |  |  |  |  |  |  | return $self->is_reworked | 
| 168 |  |  |  |  |  |  | ? $target->reworked_deploy_dir | 
| 169 |  |  |  |  |  |  | : $target->deploy_dir; | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 1 |  |  | 1 | 1 | 906 | my $self = shift; | 
| 173 | 1 |  |  |  |  | 4 | $self->deploy_dir->file( $self->path_segments ); | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | my $path = shift->deploy_file; | 
| 177 | 255 |  |  | 255 | 1 | 2508 | return undef unless -f $path; | 
| 178 | 255 |  |  |  |  | 3935 | require Digest::SHA; | 
| 179 | 255 | 100 |  |  |  | 5812 | my $sha = Digest::SHA->new(1); | 
| 180 |  |  |  |  |  |  | $sha->add( $path->slurp(iomode => '<:raw') ); | 
| 181 |  |  |  |  |  |  | return $sha->hexdigest; | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | my $self = shift; | 
| 185 | 221 |  |  | 221 | 1 | 20014 | my $target = $self->target; | 
| 186 | 221 |  |  |  |  | 491 | return $self->is_reworked | 
| 187 |  |  |  |  |  |  | ? $target->reworked_revert_dir | 
| 188 |  |  |  |  |  |  | : $target->revert_dir; | 
| 189 |  |  |  |  |  |  | } | 
| 190 | 3 |  |  | 3 |  | 822 |  | 
| 191 | 3 | 100 |  |  |  | 260 | my $self = shift; | 
| 192 | 2 |  |  |  |  | 109 | $self->revert_dir->file( $self->path_segments ); | 
| 193 | 2 |  |  |  |  | 19 | } | 
| 194 | 2 |  |  |  |  | 45 |  | 
| 195 | 2 |  |  |  |  | 477 | my $self = shift; | 
| 196 |  |  |  |  |  |  | my $target = $self->target; | 
| 197 |  |  |  |  |  |  | return $self->is_reworked | 
| 198 |  |  |  |  |  |  | ? $target->reworked_verify_dir | 
| 199 | 207 |  |  | 207 | 1 | 1898 | : $target->verify_dir; | 
| 200 | 207 |  |  |  |  | 3658 | } | 
| 201 | 207 | 100 |  |  |  | 4856 |  | 
| 202 |  |  |  |  |  |  | my $self = shift; | 
| 203 |  |  |  |  |  |  | $self->verify_dir->file( $self->path_segments ); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | my ($self, $name) = @_; | 
| 207 | 205 |  |  | 205 | 1 | 10224 | if ( my $meth = $self->can("$name\_file") ) { | 
| 208 | 205 |  |  |  |  | 430 | return $self->$meth; | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  | return $self->target->top_dir->subdir($name)->cleanup->file( | 
| 211 |  |  |  |  |  |  | $self->path_segments | 
| 212 | 145 |  |  | 145 | 1 | 1790 | ); | 
| 213 | 145 |  |  |  |  | 2717 | } | 
| 214 | 145 | 100 |  |  |  | 3414 |  | 
| 215 |  |  |  |  |  |  | shift->operator eq '-'; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | shift->operator ne '-'; | 
| 219 |  |  |  |  |  |  | } | 
| 220 | 143 |  |  | 143 | 1 | 34702 |  | 
| 221 | 143 |  |  |  |  | 294 | shift->is_deploy ? 'deploy' : 'revert'; | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | my $self = shift; | 
| 225 | 42 |  |  | 42 | 1 | 364 | return join ' ', $self->format_name, map { $_->format_name } $self->tags; | 
| 226 | 42 | 100 |  |  |  | 265 | } | 
| 227 | 40 |  |  |  |  | 117 |  | 
| 228 |  |  |  |  |  |  | my $self = shift; | 
| 229 | 2 |  |  |  |  | 40 | my ($tag) = $self->tags; | 
| 230 |  |  |  |  |  |  | unless ($tag) { | 
| 231 |  |  |  |  |  |  | ($tag) = $self->rework_tags or return $self->format_name . '@HEAD'; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  | return join '', $self->format_name, $tag->format_name; | 
| 234 |  |  |  |  |  |  | } | 
| 235 | 10 |  |  | 10 | 1 | 36 |  | 
| 236 |  |  |  |  |  |  | my $self = shift; | 
| 237 |  |  |  |  |  |  | my $deps = join( | 
| 238 |  |  |  |  |  |  | ' ', | 
| 239 | 32 |  |  | 32 | 1 | 6370 | map { $_->as_plan_string } $self->requires, $self->conflicts | 
| 240 |  |  |  |  |  |  | ) or return ''; | 
| 241 |  |  |  |  |  |  | return "[$deps]"; | 
| 242 |  |  |  |  |  |  | } | 
| 243 | 2 | 100 |  | 2 | 1 | 6 |  | 
| 244 |  |  |  |  |  |  | my $self = shift; | 
| 245 |  |  |  |  |  |  | my $dep = $self->format_dependencies or return $self->format_name; | 
| 246 |  |  |  |  |  |  | return $self->format_name . $self->pspace . $dep; | 
| 247 | 353 |  |  | 353 | 1 | 60131 | } | 
| 248 | 353 |  |  |  |  | 823 |  | 
|  | 168 |  |  |  |  | 1233 |  | 
| 249 |  |  |  |  |  |  | my $self = shift; | 
| 250 |  |  |  |  |  |  | return $self->format_operator . $self->format_name_with_dependencies; | 
| 251 |  |  |  |  |  |  | } | 
| 252 | 12 |  |  | 12 | 1 | 1225 |  | 
| 253 | 12 |  |  |  |  | 33 | my $self = shift; | 
| 254 | 12 | 100 |  |  |  | 121 | return join ' ', $self->planner_name, '<' . $self->planner_email . '>'; | 
| 255 | 6 | 100 |  |  |  | 23 | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 | 7 |  |  |  |  | 86 | my $self = shift; | 
| 258 |  |  |  |  |  |  | $self->plan->open_script($self->deploy_file); | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 | 179 |  |  | 179 | 1 | 249 | my $self = shift; | 
| 262 |  |  |  |  |  |  | $self->plan->open_script($self->revert_file); | 
| 263 |  |  |  |  |  |  | } | 
| 264 | 179 | 100 |  |  |  | 411 |  | 
|  | 102 |  |  |  |  | 294 |  | 
| 265 |  |  |  |  |  |  | my $self = shift; | 
| 266 | 63 |  |  |  |  | 343 | $self->plan->open_script($self->verify_file); | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | my $self = shift; | 
| 270 | 33 |  |  | 33 | 1 | 61 | return $self->SUPER::format_content . $self->pspace . join ( | 
| 271 | 33 | 100 |  |  |  | 77 | ' ', | 
| 272 | 15 |  |  |  |  | 61 | ($self->format_dependencies || ()), | 
| 273 |  |  |  |  |  |  | $self->timestamp->as_string, | 
| 274 |  |  |  |  |  |  | $self->format_planner | 
| 275 |  |  |  |  |  |  | ); | 
| 276 | 31 |  |  | 31 | 1 | 701 | } | 
| 277 | 31 |  |  |  |  | 102 |  | 
| 278 |  |  |  |  |  |  | my $self = shift; | 
| 279 |  |  |  |  |  |  | my $plan = $self->plan; | 
| 280 |  |  |  |  |  |  | return map { $plan->find( $_->key_name ) } $self->requires; | 
| 281 | 1014 |  |  | 1014 | 1 | 9221 | } | 
| 282 | 1014 |  |  |  |  | 6772 |  | 
| 283 |  |  |  |  |  |  | my $self = shift; | 
| 284 |  |  |  |  |  |  | my $plan = $self->plan; | 
| 285 |  |  |  |  |  |  | return map { $plan->find( $_->key_name ) } $self->conflicts; | 
| 286 | 1 |  |  | 1 | 1 | 536 | } | 
| 287 | 1 |  |  |  |  | 9 |  | 
| 288 |  |  |  |  |  |  | my ( $self, %p ) = @_; | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | return join( | 
| 291 | 1 |  |  | 1 | 1 | 307 | '', | 
| 292 | 1 |  |  |  |  | 5 | __x( | 
| 293 |  |  |  |  |  |  | "Please enter a note for your change. Lines starting with '#' will\n" . | 
| 294 |  |  |  |  |  |  | "be ignored, and an empty message aborts the {command}.", | 
| 295 |  |  |  |  |  |  | command => $p{for}, | 
| 296 | 1 |  |  | 1 | 1 | 293 | ), | 
| 297 | 1 |  |  |  |  | 8 | "\n", | 
| 298 |  |  |  |  |  |  | __x('Change to {command}:', command => $p{for}), | 
| 299 |  |  |  |  |  |  | "\n\n", | 
| 300 |  |  |  |  |  |  | '  ', $self->format_op_name_dependencies, | 
| 301 | 144 |  |  | 144 | 1 | 203 | join "\n    ", '', @{ $p{scripts} }, | 
| 302 | 144 |  | 66 |  |  | 337 | "\n", | 
| 303 |  |  |  |  |  |  | ); | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | 1; | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | =head1 Name | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 1 |  |  | 1 | 1 | 1493 | App::Sqitch::Plan::Change - Sqitch deployment plan tag | 
| 312 | 1 |  |  |  |  | 4 |  | 
| 313 | 1 |  |  |  |  | 3 | =head1 Synopsis | 
|  | 2 |  |  |  |  | 8 |  | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | my $plan = App::Sqitch::Plan->new( sqitch => $sqitch ); | 
| 316 |  |  |  |  |  |  | for my $line ($plan->lines) { | 
| 317 | 1 |  |  | 1 | 1 | 3 | say $line->as_string; | 
| 318 | 1 |  |  |  |  | 3 | } | 
| 319 | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 320 |  |  |  |  |  |  | =head1 Description | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | A App::Sqitch::Plan::Change represents a change as parsed from a plan file. In | 
| 323 | 2 |  |  | 2 | 1 | 129 | addition to the interface inherited from L<App::Sqitch::Plan::Line>, it offers | 
| 324 |  |  |  |  |  |  | interfaces for parsing dependencies from the deploy script, as well as for | 
| 325 |  |  |  |  |  |  | opening the deploy, revert, and verify scripts. | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | =head1 Interface | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | See L<App::Sqitch::Plan::Line> for the basics. | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | =head2 Accessors | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | =head3 C<since_tag> | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | An L<App::Sqitch::Plan::Tag> object representing the last tag to appear in the | 
| 336 | 2 |  |  |  |  | 22 | plan B<before> the change. May be C<undef>. | 
|  | 2 |  |  |  |  | 8 |  | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | =head3 C<pspace> | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | Blank space separating the change name from the dependencies, timestamp, and | 
| 341 |  |  |  |  |  |  | planner in the file. | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | =head3 C<is_reworked> | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | Boolean indicting whether or not the change has been reworked. | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | =head3 C<info> | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | Information about the change, returned as a string. Includes the change ID, | 
| 350 |  |  |  |  |  |  | the name and email address of the user who added the change to the plan, and | 
| 351 |  |  |  |  |  |  | the timestamp for when the change was added to the plan. | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | =head3 C<id> | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | A SHA1 hash of the data returned by C<info()>, which can be used as a | 
| 356 |  |  |  |  |  |  | globally-unique identifier for the change. | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | =head3 C<timestamp> | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | Returns the an L<App::Sqitch::DateTime> object representing the time at which | 
| 361 |  |  |  |  |  |  | the change was added to the plan. | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | =head3 C<planner_name> | 
| 364 |  |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  | Returns the name of the user who added the change to the plan. | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | =head3 C<planner_email> | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | Returns the email address of the user who added the change to the plan. | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | =head3 C<parent> | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | Parent change object. | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | =head3 C<tags> | 
| 376 |  |  |  |  |  |  |  | 
| 377 |  |  |  |  |  |  | A list of tag objects associated with the change. | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | =head2 Instance Methods | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | =head3 C<path_segments> | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | my @segments = $change->path_segments; | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | Returns the path segment for the change. For example, if the change is named | 
| 386 |  |  |  |  |  |  | "foo", C<('foo.sql')> is returned. If the change is named "functions/bar> | 
| 387 |  |  |  |  |  |  | C<('functions', 'bar.sql')> is returned. Internally, this data is used to | 
| 388 |  |  |  |  |  |  | create the deploy, revert, and verify file names. | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | =head3 C<deploy_dir> | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | my $file = $change->deploy_dir; | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | Returns the path to the deploy directory for the change. | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | =head3 C<deploy_file> | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | my $file = $change->deploy_file; | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | Returns the path to the deploy script file for the change. | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =head3 C<revert_dir> | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | my $file = $change->revert_dir; | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | Returns the path to the revert directory for the change. | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | =head3 C<revert_file> | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | my $file = $change->revert_file; | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | Returns the path to the revert script file for the change. | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | =head3 C<verify_dir> | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | my $file = $change->verify_dir; | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | Returns the path to the verify directory for the change. | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | =head3 C<verify_file> | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | my $file = $change->verify_file; | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | Returns the path to the verify script file for the change. | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | =head3 C<script_file> | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | my $file = $sqitch->script_file($script_name); | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | Returns the path to a script, for the change. | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | =head3 C<script_hash> | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | my $hash = $change->script_hash; | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | Returns the hex digest of the SHA-1 hash for the deploy script. | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | =head3 C<rework_tags> | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | my @tags = $change->rework_tags; | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | Returns a list of tags that occur between a change and its next reworking. | 
| 443 |  |  |  |  |  |  | Returns an empty list if the change is not reworked. | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | =head3 C<add_tag> | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | $change->add_tag($tag); | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | Adds a tag object to the change. | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | =head3 C<add_rework_tags> | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | $change->add_rework_tags(@tags); | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | Adds tags to the list of rework tags. | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | =head3 C<clear_rework_tags> | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | $change->clear_rework_tags(@tags); | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | Clears the list of rework tags. | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | =head3 C<requires> | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | my @requires = $change->requires; | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | Returns a list of L<App::Sqitch::Plan::Depend> objects representing changes | 
| 468 |  |  |  |  |  |  | required by this change. | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | =head3 C<requires_changes> | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | my @requires_changes = $change->requires_changes; | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | Returns a list of the C<App::Sqitch::Plan::Change> objects representing | 
| 475 |  |  |  |  |  |  | changes required by this change. | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | =head3 C<conflicts> | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | my @conflicts = $change->conflicts; | 
| 480 |  |  |  |  |  |  |  | 
| 481 |  |  |  |  |  |  | Returns a list of L<App::Sqitch::Plan::Depend> objects representing changes | 
| 482 |  |  |  |  |  |  | with which this change conflicts. | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | =head3 C<conflicts_changes> | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | my @conflicts_changes = $change->conflicts_changes; | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | Returns a list of the C<App::Sqitch::Plan::Change> objects representing | 
| 489 |  |  |  |  |  |  | changes with which this change conflicts. | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | =head3 C<dependencies> | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | my @dependencies = $change->dependencies; | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | Returns a list of L<App::Sqitch::Plan::Depend> objects representing all | 
| 496 |  |  |  |  |  |  | dependencies, required and conflicting. | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | =head3 C<is_deploy> | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | Returns true if the change is intended to be deployed, and false if it should be | 
| 501 |  |  |  |  |  |  | reverted. | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | =head3 C<is_revert> | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | Returns true if the change is intended to be reverted, and false if it should be | 
| 506 |  |  |  |  |  |  | deployed. | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | =head3 C<action> | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | Returns "deploy" if the change should be deployed, or "revert" if it should be | 
| 511 |  |  |  |  |  |  | reverted. | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | =head3 C<format_tag_qualified_name> | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | my $tag_qualified_name = $change->format_tag_qualified_name; | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | Returns a string with the change name followed by the next tag in the plan. | 
| 518 |  |  |  |  |  |  | Useful for displaying unambiguous change specifications for reworked changes. | 
| 519 |  |  |  |  |  |  | If there is no tag appearing in the file after the change, the C<@HEAD> will | 
| 520 |  |  |  |  |  |  | be used. | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | =head3 C<format_name_with_tags> | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | my $name_with_tags = $change->format_name_with_tags; | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | Returns a string formatted with the change name followed by the list of tags, if | 
| 527 |  |  |  |  |  |  | any, associated with the change. Used to display a change as it is deployed. | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | =head3 C<format_dependencies> | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | my $dependencies = $change->format_dependencies; | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | Returns a string containing a bracketed list of dependencies. If there are no | 
| 534 |  |  |  |  |  |  | dependencies, an empty string will be returned. | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | =head3 C<format_name_with_dependencies> | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | my $name_with_dependencies = $change->format_name_with_dependencies; | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | Returns a string formatted with the change name followed by a bracketed list | 
| 541 |  |  |  |  |  |  | of dependencies, if any, associated with the change. Used to display a change | 
| 542 |  |  |  |  |  |  | when added to a plan. | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | =head3 C<format_op_name_dependencies> | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | my $op_name_dependencies = $change->format_op_name_dependencies; | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | Like C<format_name_with_dependencies>, but includes the operator, if present. | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | =head3 C<format_planner> | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | my $planner = $change->format_planner; | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | Returns a string formatted with the name and email address of the user who | 
| 555 |  |  |  |  |  |  | added the change to the plan. | 
| 556 |  |  |  |  |  |  |  | 
| 557 |  |  |  |  |  |  | =head3 C<deploy_handle> | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | my $fh = $change->deploy_handle; | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  | Returns an L<IO::File> file handle, opened for reading, for the deploy script | 
| 562 |  |  |  |  |  |  | for the change. | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | =head3 C<revert_handle> | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | my $fh = $change->revert_handle; | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | Returns an L<IO::File> file handle, opened for reading, for the revert script | 
| 569 |  |  |  |  |  |  | for the change. | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | =head3 C<verify_handle> | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | my $fh = $change->verify_handle; | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | Returns an L<IO::File> file handle, opened for reading, for the verify script | 
| 576 |  |  |  |  |  |  | for the change. | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | =head3 C<note_prompt> | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | my $prompt = $change->note_prompt( | 
| 581 |  |  |  |  |  |  | for     => 'rework', | 
| 582 |  |  |  |  |  |  | scripts => [$change->deploy_file, $change->revert_file], | 
| 583 |  |  |  |  |  |  | ); | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | Overrides the implementation from C<App::Sqitch::Plan::Line> to add the | 
| 586 |  |  |  |  |  |  | C<files> parameter. This is a list of the files to be created for the command. | 
| 587 |  |  |  |  |  |  | These will usually be the deploy, revert, and verify files, but the caller | 
| 588 |  |  |  |  |  |  | might not be creating all of them, so it needs to pass the list. | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | =head1 See Also | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | =over | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | =item L<App::Sqitch::Plan> | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | Class representing a plan. | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | =item L<App::Sqitch::Plan::Line> | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | Base class from which App::Sqitch::Plan::Change inherits. | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | =item L<sqitch> | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | The Sqitch command-line client. | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | =back | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | =head1 Author | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | David E. Wheeler <david@justatheory.com> | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | =head1 License | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | Copyright (c) 2012-2022 iovation Inc., David E. Wheeler | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | Permission is hereby granted, free of charge, to any person obtaining a copy | 
| 617 |  |  |  |  |  |  | of this software and associated documentation files (the "Software"), to deal | 
| 618 |  |  |  |  |  |  | in the Software without restriction, including without limitation the rights | 
| 619 |  |  |  |  |  |  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
| 620 |  |  |  |  |  |  | copies of the Software, and to permit persons to whom the Software is | 
| 621 |  |  |  |  |  |  | furnished to do so, subject to the following conditions: | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | The above copyright notice and this permission notice shall be included in all | 
| 624 |  |  |  |  |  |  | copies or substantial portions of the Software. | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
| 627 |  |  |  |  |  |  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
| 628 |  |  |  |  |  |  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
| 629 |  |  |  |  |  |  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
| 630 |  |  |  |  |  |  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
| 631 |  |  |  |  |  |  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
| 632 |  |  |  |  |  |  | SOFTWARE. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | =cut |