| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package ADAMK::Release; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 788 | use 5.10.0; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 4 | 1 |  |  | 1 |  | 5 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 5 | 1 |  |  | 1 |  | 6 | use warnings; | 
|  | 1 |  |  |  |  | 10 |  | 
|  | 1 |  |  |  |  | 30 |  | 
| 6 | 1 |  |  | 1 |  | 5 | use Carp                          (); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 22 |  | 
| 7 | 1 |  |  | 1 |  | 958 | use CPAN::Uploader       0.103003 (); | 
|  | 1 |  |  |  |  | 96088 |  | 
|  | 1 |  |  |  |  | 28 |  | 
| 8 | 1 |  |  | 1 |  | 4932 | use Devel::PPPort            3.21 (); | 
|  | 1 |  |  |  |  | 541 |  | 
|  | 1 |  |  |  |  | 33 |  | 
| 9 | 1 |  |  | 1 |  | 1150 | use File::Spec::Functions    0.80 ':ALL'; | 
|  | 1 |  |  |  |  | 1090 |  | 
|  | 1 |  |  |  |  | 260 |  | 
| 10 | 1 |  |  | 1 |  | 1145 | use File::Slurp           9999.19 (); | 
|  | 1 |  |  |  |  | 5700 |  | 
|  | 1 |  |  |  |  | 29 |  | 
| 11 | 1 |  |  | 1 |  | 2061 | use File::Find::Rule         0.32 (); | 
|  | 1 |  |  |  |  | 12122 |  | 
|  | 1 |  |  |  |  | 33 |  | 
| 12 | 1 |  |  | 1 |  | 1352 | use File::Flat               1.04 (); | 
|  | 1 |  |  |  |  | 19060 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 13 | 1 |  |  | 1 |  | 968 | use File::ShareDir           1.03 (); | 
|  | 1 |  |  |  |  | 8073 |  | 
|  | 1 |  |  |  |  | 29 |  | 
| 14 | 1 |  |  | 1 |  | 905 | use File::LocalizeNewlines   1.12 (); | 
|  | 1 |  |  |  |  | 8794 |  | 
|  | 1 |  |  |  |  | 28 |  | 
| 15 | 1 |  |  | 1 |  | 569 | use GitHub::Extract          0.02 (); | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | use IO::Prompt::Tiny        0.002 (); | 
| 17 |  |  |  |  |  |  | use Module::Extract::VERSION 1.01 (); | 
| 18 |  |  |  |  |  |  | use Params::Util             1.00 ':ALL'; | 
| 19 |  |  |  |  |  |  | use Term::ReadKey            2.14 (); | 
| 20 |  |  |  |  |  |  | use YAML::Tiny               1.51 (); | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | our $VERSION = '0.02'; | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | use constant TOOLS => qw{ | 
| 25 |  |  |  |  |  |  | cat | 
| 26 |  |  |  |  |  |  | chmod | 
| 27 |  |  |  |  |  |  | make | 
| 28 |  |  |  |  |  |  | touch | 
| 29 |  |  |  |  |  |  | sudo | 
| 30 |  |  |  |  |  |  | bash | 
| 31 |  |  |  |  |  |  | }; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | use Object::Tiny 1.01 qw{ | 
| 34 |  |  |  |  |  |  | module | 
| 35 |  |  |  |  |  |  | github | 
| 36 |  |  |  |  |  |  | verbose | 
| 37 |  |  |  |  |  |  | release | 
| 38 |  |  |  |  |  |  | no_rt | 
| 39 |  |  |  |  |  |  | no_changes | 
| 40 |  |  |  |  |  |  | no_copyright | 
| 41 |  |  |  |  |  |  | no_test | 
| 42 |  |  |  |  |  |  | }, map { "bin_$_" } TOOLS; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | ###################################################################### | 
| 50 |  |  |  |  |  |  | # Constructor | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | sub new { | 
| 53 |  |  |  |  |  |  | my $self = shift->SUPER::new(@_); | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # Check module | 
| 56 |  |  |  |  |  |  | unless ( _CLASS($self->module) ) { | 
| 57 |  |  |  |  |  |  | $self->error("Missing or invalid module"); | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | # Inflate and check the github object | 
| 61 |  |  |  |  |  |  | if ( Params::Util::_HASH($self->github) ) { | 
| 62 |  |  |  |  |  |  | $self->{github} = GitHub::Extract->new( %{$self->github} ); | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  | unless ( Params::Util::_INSTANCE($self->github, 'GitHub::Extract')) { | 
| 65 |  |  |  |  |  |  | $self->error("Missing or invalid GitHub specification"); | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | # Release options | 
| 69 |  |  |  |  |  |  | $self->{release} = !!$self->{release}; | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | # Find all of the command line tools | 
| 72 |  |  |  |  |  |  | foreach my $tool ( TOOLS ) { | 
| 73 |  |  |  |  |  |  | $self->{ "bin_" . $tool } = $self->which($tool); | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | return $self; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | ###################################################################### | 
| 84 |  |  |  |  |  |  | # Command Methods | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub run { | 
| 87 |  |  |  |  |  |  | my $self = shift; | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | # Export from GitHub and change to the directory | 
| 90 |  |  |  |  |  |  | my $pushd = $self->github->pushd; | 
| 91 |  |  |  |  |  |  | unless ( $pushd ) { | 
| 92 |  |  |  |  |  |  | $self->error( | 
| 93 |  |  |  |  |  |  | "Failed to download and extract %s: %s", | 
| 94 |  |  |  |  |  |  | $self->github->url, | 
| 95 |  |  |  |  |  |  | $self->github->error, | 
| 96 |  |  |  |  |  |  | ); | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | # This is total bulldozer coding, there is no reason whatsoever why | 
| 100 |  |  |  |  |  |  | # this stuff should be in seperate methods except that it provides | 
| 101 |  |  |  |  |  |  | # a little cleaner logical breakup, and maybe I want to subclass this | 
| 102 |  |  |  |  |  |  | # someday or something. | 
| 103 |  |  |  |  |  |  | $self->validate; | 
| 104 |  |  |  |  |  |  | $self->assemble; | 
| 105 |  |  |  |  |  |  | $self->build; | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | # Release the distribution | 
| 108 |  |  |  |  |  |  | $self->upload if $self->release; | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | return; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | sub validate { | 
| 114 |  |  |  |  |  |  | my $self = shift; | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | unless ( $self->dist_version ) { | 
| 117 |  |  |  |  |  |  | $self->error("Failed to find version number in main module"); | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | unless ( $self->makefile_pl or $self->build_pl ) { | 
| 120 |  |  |  |  |  |  | $self->error("Failed to find Makefile.PL or Build.PL"); | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | return; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | sub assemble { | 
| 127 |  |  |  |  |  |  | my $self = shift; | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | # Create MANIFEST.SKIP | 
| 130 |  |  |  |  |  |  | if ( -f $self->dist_manifest_add ) { | 
| 131 |  |  |  |  |  |  | $self->shell( | 
| 132 |  |  |  |  |  |  | $self->bin_cat, | 
| 133 |  |  |  |  |  |  | $self->shared_manifest_skip, | 
| 134 |  |  |  |  |  |  | $self->dist_manifest_add, | 
| 135 |  |  |  |  |  |  | '>', | 
| 136 |  |  |  |  |  |  | $self->dist_manifest_skip, | 
| 137 |  |  |  |  |  |  | "Failed to merge common MANIFEST.SKIP with extra one", | 
| 138 |  |  |  |  |  |  | ); | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | } elsif ( not -f $self->dist_manifest ) { | 
| 141 |  |  |  |  |  |  | $self->copy( $self->shared_manifest_skip => $self->dist_manifest_skip ); | 
| 142 |  |  |  |  |  |  | } | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | # Apply a default LICENSE file | 
| 145 |  |  |  |  |  |  | unless ( -f $self->dist_license ) { | 
| 146 |  |  |  |  |  |  | $self->copy( $self->shared_license => $self->dist_license ); | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | # Add ppport.h if any XS files use it | 
| 150 |  |  |  |  |  |  | if ( $self->find_ppport->in( $self->dist_dir ) ) { | 
| 151 |  |  |  |  |  |  | Devel::PPPort::WriteFile( $self->dist_ppport ); | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | # Copy in author tests as needed | 
| 155 |  |  |  |  |  |  | unless ( -f $self->dist_99_author ) { | 
| 156 |  |  |  |  |  |  | foreach my $xt ( qw{ pod.t pmv.t } ) { | 
| 157 |  |  |  |  |  |  | next if -f catfile( $self->dist_xt, $xt ); | 
| 158 |  |  |  |  |  |  | $self->copy( | 
| 159 |  |  |  |  |  |  | catfile( $self->shared_dir, $xt ), | 
| 160 |  |  |  |  |  |  | catfile( $self->dist_xt,     $xt ), | 
| 161 |  |  |  |  |  |  | ); | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | # Create the README file | 
| 166 |  |  |  |  |  |  | unless ( -f $self->dist_readme ) { | 
| 167 |  |  |  |  |  |  | my $dist_readme = $self->dist_readme; | 
| 168 |  |  |  |  |  |  | my $module_pod = -f $self->module_pod ? $self->module_pod : $self->module_pm; | 
| 169 |  |  |  |  |  |  | $self->shell( | 
| 170 |  |  |  |  |  |  | $self->bin_cat, | 
| 171 |  |  |  |  |  |  | $module_pod, | 
| 172 |  |  |  |  |  |  | "| pod2text >", | 
| 173 |  |  |  |  |  |  | $dist_readme, | 
| 174 |  |  |  |  |  |  | "Error while generating README file '$dist_readme'", | 
| 175 |  |  |  |  |  |  | ) | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # Localise all newlines in text files | 
| 179 |  |  |  |  |  |  | $self->file_localize->localize( $self->dist_dir ); | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | # Check for various unsafe things in Makefile.PL | 
| 182 |  |  |  |  |  |  | if ( $self->makefile_pl ) { | 
| 183 |  |  |  |  |  |  | if ( $self->makefile_pl =~ /use inc::Module::Install/ ) { | 
| 184 |  |  |  |  |  |  | if ( $self->makefile_pl =~ /\bauto_install\b/ ) { | 
| 185 |  |  |  |  |  |  | $self->error("Makefile.PL contains dangerous auto_install"); | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | } else { | 
| 188 |  |  |  |  |  |  | unless ( $self->makefile_pl =~ /use strict/ ) { | 
| 189 |  |  |  |  |  |  | $self->error("Makefile.PL does not use strict"); | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  | unless ( $self->makefile_pl =~ /(?:use|require) \d/ ) { | 
| 192 |  |  |  |  |  |  | $self->error("Makefile.PL does not declare a minimum Perl version"); | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | # Check file permissions | 
| 198 |  |  |  |  |  |  | foreach my $file ( sort $self->find_0644->in( $self->dist_dir ) ) { | 
| 199 |  |  |  |  |  |  | my $mode = (stat($file))[2] & 07777; | 
| 200 |  |  |  |  |  |  | next if $mode == 0644; | 
| 201 |  |  |  |  |  |  | $self->shell( | 
| 202 |  |  |  |  |  |  | $self->bin_chmod, | 
| 203 |  |  |  |  |  |  | '0644', | 
| 204 |  |  |  |  |  |  | $file, | 
| 205 |  |  |  |  |  |  | "Error setting $file to 0644 permissions", | 
| 206 |  |  |  |  |  |  | ); | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | # Make sure exe files are marked with executable permissions | 
| 210 |  |  |  |  |  |  | if ( $self->find_executable->in( $self->dist_dir ) ) { | 
| 211 |  |  |  |  |  |  | $self->error("Found at least one .exe file without -x unix permissions"); | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | # Check the Changes file | 
| 215 |  |  |  |  |  |  | unless ( $self->no_changes ) { | 
| 216 |  |  |  |  |  |  | # Read in the Changes file | 
| 217 |  |  |  |  |  |  | unless ( -f $self->dist_changes ) { | 
| 218 |  |  |  |  |  |  | $self->error("Distribution does not have a Changes file"); | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | unless ( open( CHANGES, $self->dist_changes ) ) { | 
| 221 |  |  |  |  |  |  | $self->error("Failed to open Changes file"); | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  | my @lines = <CHANGES>; | 
| 224 |  |  |  |  |  |  | close CHANGES; | 
| 225 |  |  |  |  |  |  | unless ( @lines >= 3 ) { | 
| 226 |  |  |  |  |  |  | $self->error("Changes file is empty or too small"); | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | # The Changes version should be the first thing on the third line | 
| 230 |  |  |  |  |  |  | my $current   = $lines[2]; | 
| 231 |  |  |  |  |  |  | my ($version) = split /\s+/, $current; | 
| 232 |  |  |  |  |  |  | unless ( $version =~ /[\d\._]{3}/ ) { | 
| 233 |  |  |  |  |  |  | $self->error( | 
| 234 |  |  |  |  |  |  | "Failed to find current version, or too short, in '%2'", | 
| 235 |  |  |  |  |  |  | $current, | 
| 236 |  |  |  |  |  |  | ); | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | # Does it match the version in the main module | 
| 240 |  |  |  |  |  |  | unless ( $version eq $self->dist_version ) { | 
| 241 |  |  |  |  |  |  | $self->error( | 
| 242 |  |  |  |  |  |  | "Version in Changes file (%s) does not match module version (%s)", | 
| 243 |  |  |  |  |  |  | $version, | 
| 244 |  |  |  |  |  |  | $self->dist_version, | 
| 245 |  |  |  |  |  |  | ); | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | # Check that the main module documentation Copyright is the current year | 
| 250 |  |  |  |  |  |  | unless ( $self->no_copyright ) { | 
| 251 |  |  |  |  |  |  | # Read the file | 
| 252 |  |  |  |  |  |  | unless ( open( MODULE, $self->module_doc ) ) { | 
| 253 |  |  |  |  |  |  | $self->error( | 
| 254 |  |  |  |  |  |  | "Failed to open '%s'", | 
| 255 |  |  |  |  |  |  | $self->module_doc, | 
| 256 |  |  |  |  |  |  | ); | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  | my @lines = <MODULE>; | 
| 259 |  |  |  |  |  |  | close MODULE; | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | # Look for the current year | 
| 262 |  |  |  |  |  |  | my $year = 1900 + (localtime time)[5]; | 
| 263 |  |  |  |  |  |  | unless ( grep { /copyright/i and /$year/ } @lines ) { | 
| 264 |  |  |  |  |  |  | $self->error("Missing Copyright, or does not refer to current year"); | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | # Merge the module to a single string | 
| 268 |  |  |  |  |  |  | my $merged = join "\n", @lines; | 
| 269 |  |  |  |  |  |  | unless ( $self->no_rt ) { | 
| 270 |  |  |  |  |  |  | my $dist_name = $self->dist; | 
| 271 |  |  |  |  |  |  | unless ( $merged =~ /L\<http\:\/\/rt\.cpan\.org\/.+?=([\w-]+)\>/ ) { | 
| 272 |  |  |  |  |  |  | $self->error("Failed to find a link to the public RT queue"); | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  | unless ( $dist_name eq $1 ) { | 
| 275 |  |  |  |  |  |  | $self->error("Expected a public link to $dist_name RT queue, but found a link to the $1 queue"); | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  | } | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | # Touch all files to correct any potential time skews | 
| 281 |  |  |  |  |  |  | foreach my $file ( $self->find_files->in( $self->dist_dir ) ) { | 
| 282 |  |  |  |  |  |  | $self->shell( | 
| 283 |  |  |  |  |  |  | $self->bin_touch, | 
| 284 |  |  |  |  |  |  | $file, | 
| 285 |  |  |  |  |  |  | "Error while touching $file to prevent clock skew", | 
| 286 |  |  |  |  |  |  | ); | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | return; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | sub build { | 
| 293 |  |  |  |  |  |  | my $self = shift; | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | # Prevent environment variables from outside this script | 
| 296 |  |  |  |  |  |  | # infecting the way we build things inside here. | 
| 297 |  |  |  |  |  |  | local $ENV{AUTOMATED_TESTING} = ''; | 
| 298 |  |  |  |  |  |  | local $ENV{RELEASE_TESTING}   = ''; | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # Run either of the build protocols | 
| 301 |  |  |  |  |  |  | if ( $self->makefile_pl ) { | 
| 302 |  |  |  |  |  |  | $self->build_make; | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | } elsif ( $self->build_pl ) { | 
| 305 |  |  |  |  |  |  | $self->build_perl; | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | } else { | 
| 308 |  |  |  |  |  |  | $self->error("Module does not have a Makefile.PL or Build.PL"); | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | # Double check that the build produced a tarball where we expect it to be | 
| 312 |  |  |  |  |  |  | unless ( -f $self->dist_tardist ) { | 
| 313 |  |  |  |  |  |  | $self->error( | 
| 314 |  |  |  |  |  |  | "Failed to create tardist at '%s'", | 
| 315 |  |  |  |  |  |  | $self->dist_tardist, | 
| 316 |  |  |  |  |  |  | ); | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | return; | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | sub build_make { | 
| 323 |  |  |  |  |  |  | my $self = shift; | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | # Create the Makefile and MANIFEST | 
| 326 |  |  |  |  |  |  | $self->build_makefile; | 
| 327 |  |  |  |  |  |  | $self->build_makefile_manifest; | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | unless ( $self->no_test ) { | 
| 330 |  |  |  |  |  |  | # Test the distribution normally | 
| 331 |  |  |  |  |  |  | $self->shell( | 
| 332 |  |  |  |  |  |  | $self->bin_make, | 
| 333 |  |  |  |  |  |  | 'disttest', | 
| 334 |  |  |  |  |  |  | 'disttest failed', | 
| 335 |  |  |  |  |  |  | ); | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | # Test with AUTOMATED_TESTING on | 
| 338 |  |  |  |  |  |  | SCOPE: { | 
| 339 |  |  |  |  |  |  | local $ENV{AUTOMATED_TESTING} = 1; | 
| 340 |  |  |  |  |  |  | $self->build_makefile; | 
| 341 |  |  |  |  |  |  | $self->shell( | 
| 342 |  |  |  |  |  |  | $self->bin_make, | 
| 343 |  |  |  |  |  |  | "disttest", | 
| 344 |  |  |  |  |  |  | 'disttest failed', | 
| 345 |  |  |  |  |  |  | ); | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | # Test with RELEASE_TESTING on | 
| 349 |  |  |  |  |  |  | SCOPE: { | 
| 350 |  |  |  |  |  |  | local $ENV{RELEASE_TESTING} = 1; | 
| 351 |  |  |  |  |  |  | $self->build_makefile; | 
| 352 |  |  |  |  |  |  | $self->shell( | 
| 353 |  |  |  |  |  |  | $self->bin_make, | 
| 354 |  |  |  |  |  |  | "disttest", | 
| 355 |  |  |  |  |  |  | 'disttest failed', | 
| 356 |  |  |  |  |  |  | ); | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | # Test with RELEASE_TESTING and root permissions. | 
| 360 |  |  |  |  |  |  | # This catches bad test script assumptions in modules related | 
| 361 |  |  |  |  |  |  | # to files and permissions (File::Remove, File::Flat etc). | 
| 362 |  |  |  |  |  |  | SCOPE: { | 
| 363 |  |  |  |  |  |  | local $ENV{RELEASE_TESTING}   = 1; | 
| 364 |  |  |  |  |  |  | $self->sudo( | 
| 365 |  |  |  |  |  |  | qw{ perl Makefile.PL }, | 
| 366 |  |  |  |  |  |  | 'Error while creating Makefile', | 
| 367 |  |  |  |  |  |  | ); | 
| 368 |  |  |  |  |  |  | $self->sudo( | 
| 369 |  |  |  |  |  |  | $self->bin_make, | 
| 370 |  |  |  |  |  |  | "disttest", | 
| 371 |  |  |  |  |  |  | 'disttest failed', | 
| 372 |  |  |  |  |  |  | ); | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # Clean up leftover root files and rebuild from scratch | 
| 375 |  |  |  |  |  |  | $self->build_realclean; | 
| 376 |  |  |  |  |  |  | $self->build_makefile; | 
| 377 |  |  |  |  |  |  | $self->build_makefile_manifest; | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | # Run the test suite one last time to make sure we | 
| 380 |  |  |  |  |  |  | # didn't break anything. | 
| 381 |  |  |  |  |  |  | $self->sudo( | 
| 382 |  |  |  |  |  |  | $self->bin_make, | 
| 383 |  |  |  |  |  |  | "disttest", | 
| 384 |  |  |  |  |  |  | 'disttest failed', | 
| 385 |  |  |  |  |  |  | ); | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | # Clean up the leftover root files again | 
| 388 |  |  |  |  |  |  | $self->build_realclean; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | # Create the Makefile and MANIFEST | 
| 393 |  |  |  |  |  |  | $self->build_makefile; | 
| 394 |  |  |  |  |  |  | $self->build_makefile_manifest; | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | # Build the tardist | 
| 397 |  |  |  |  |  |  | $self->shell( | 
| 398 |  |  |  |  |  |  | $self->bin_make, | 
| 399 |  |  |  |  |  |  | "tardist", | 
| 400 |  |  |  |  |  |  | 'Error making distribution tarball', | 
| 401 |  |  |  |  |  |  | ); | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | return; | 
| 404 |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | sub build_makefile { | 
| 407 |  |  |  |  |  |  | my $self = shift; | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | # Execute Makefile.PL with the current environment's perl | 
| 410 |  |  |  |  |  |  | $self->shell( | 
| 411 |  |  |  |  |  |  | qw{ perl Makefile.PL }, | 
| 412 |  |  |  |  |  |  | 'Error while creating Makefile', | 
| 413 |  |  |  |  |  |  | ); | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | # Add the build-system-specific elements to the META.yml | 
| 416 |  |  |  |  |  |  | my $meta = YAML::Tiny->read( $self->dist_meta_yml ); | 
| 417 |  |  |  |  |  |  | return unless defined $meta; | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # Add the resources | 
| 420 |  |  |  |  |  |  | my $save = 0; | 
| 421 |  |  |  |  |  |  | unless ( $meta->[0]->{resources} ) { | 
| 422 |  |  |  |  |  |  | $meta->[0]->{resources} = {}; | 
| 423 |  |  |  |  |  |  | $save = 1; | 
| 424 |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  | unless ( $meta->[0]->{resources}->{repository} ) { | 
| 426 |  |  |  |  |  |  | $meta->[0]->{resources}->{repository} = $self->dist_resource_repository; | 
| 427 |  |  |  |  |  |  | $save = 1; | 
| 428 |  |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  | if ( $save ) { | 
| 430 |  |  |  |  |  |  | $meta->write( $self->dist_meta_yml ); | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | return; | 
| 434 |  |  |  |  |  |  | } | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | sub build_makefile_manifest { | 
| 437 |  |  |  |  |  |  | my $self = shift; | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | $self->shell( | 
| 440 |  |  |  |  |  |  | $self->bin_make, | 
| 441 |  |  |  |  |  |  | "manifest", | 
| 442 |  |  |  |  |  |  | "Error while creating the MANIFEST", | 
| 443 |  |  |  |  |  |  | ); | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | sub build_realclean { | 
| 447 |  |  |  |  |  |  | my $self = shift; | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | # Clean up the distribution (always with root) | 
| 450 |  |  |  |  |  |  | $self->sudo( | 
| 451 |  |  |  |  |  |  | $self->bin_make, | 
| 452 |  |  |  |  |  |  | "realclean", | 
| 453 |  |  |  |  |  |  | 'sudo make clean failed', | 
| 454 |  |  |  |  |  |  | ); | 
| 455 |  |  |  |  |  |  | $self->remove( $self->dist_manifest ); | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | sub build_perl { | 
| 459 |  |  |  |  |  |  | my $self = shift; | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | # Create the Build file | 
| 462 |  |  |  |  |  |  | $self->shell( | 
| 463 |  |  |  |  |  |  | qw{ perl Build.PL }, | 
| 464 |  |  |  |  |  |  | 'Error while creating Makefile', | 
| 465 |  |  |  |  |  |  | ); | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | # Create the MANIFEST file | 
| 468 |  |  |  |  |  |  | $self->shell( | 
| 469 |  |  |  |  |  |  | "./Build", | 
| 470 |  |  |  |  |  |  | "manifest", | 
| 471 |  |  |  |  |  |  | 'Error while creating the MANIFEST', | 
| 472 |  |  |  |  |  |  | ); | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | unless ( $self->no_test ) { | 
| 475 |  |  |  |  |  |  | # Test the distribution normally | 
| 476 |  |  |  |  |  |  | $self->shell( | 
| 477 |  |  |  |  |  |  | qw{ ./Build disttest }, | 
| 478 |  |  |  |  |  |  | 'disttest failed', | 
| 479 |  |  |  |  |  |  | ); | 
| 480 |  |  |  |  |  |  | } | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | # Build the tardist | 
| 483 |  |  |  |  |  |  | $self->shell( | 
| 484 |  |  |  |  |  |  | qw{ ./Build dist }, | 
| 485 |  |  |  |  |  |  | 'Error making distribution tarball', | 
| 486 |  |  |  |  |  |  | ); | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | return; | 
| 489 |  |  |  |  |  |  | } | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | sub upload { | 
| 492 |  |  |  |  |  |  | my $self = shift; | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | my $pauseid = $self->prompt("PAUSEID:"); | 
| 495 |  |  |  |  |  |  | unless (_STRING($pauseid) and $pauseid =~ /^[A-Z]{3,}$/) { | 
| 496 |  |  |  |  |  |  | $self->error("Missing or invalid PAUSEID"); | 
| 497 |  |  |  |  |  |  | } | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | my $password = $self->password("Password:"); | 
| 500 |  |  |  |  |  |  | unless (_STRING($password) and $password =~ /^\S{5,}$/) { | 
| 501 |  |  |  |  |  |  | $self->error("Missing or invalid CPAN password"); | 
| 502 |  |  |  |  |  |  | } | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | # Execute the upload to CPAN | 
| 505 |  |  |  |  |  |  | CPAN::Uploader->upload_file( $self->dist_tardist, { | 
| 506 |  |  |  |  |  |  | user     => $pauseid, | 
| 507 |  |  |  |  |  |  | password => $password, | 
| 508 |  |  |  |  |  |  | }); | 
| 509 |  |  |  |  |  |  | } | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | ###################################################################### | 
| 516 |  |  |  |  |  |  | # Content and Scanning Methods | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | # Get the main github repository url for this release | 
| 519 |  |  |  |  |  |  | sub dist_resource_repository { | 
| 520 |  |  |  |  |  |  | my $self = shift; | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | return join( '', | 
| 523 |  |  |  |  |  |  | "https://github.com/", | 
| 524 |  |  |  |  |  |  | $self->github->username, | 
| 525 |  |  |  |  |  |  | $self->github->repository, | 
| 526 |  |  |  |  |  |  | '.git', | 
| 527 |  |  |  |  |  |  | ); | 
| 528 |  |  |  |  |  |  | } | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | sub makefile_pl { | 
| 531 |  |  |  |  |  |  | my $self = shift; | 
| 532 |  |  |  |  |  |  | unless ( defined $self->{makefile_pl} ) { | 
| 533 |  |  |  |  |  |  | my $file = $self->dist_makefile_pl; | 
| 534 |  |  |  |  |  |  | return undef unless -f $file; | 
| 535 |  |  |  |  |  |  | $self->{makefile_pl} = File::Slurp::read_file($file); | 
| 536 |  |  |  |  |  |  | } | 
| 537 |  |  |  |  |  |  | return $self->{makefile_pl}; | 
| 538 |  |  |  |  |  |  | } | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | sub build_pl { | 
| 541 |  |  |  |  |  |  | my $self = shift; | 
| 542 |  |  |  |  |  |  | unless ( defined $self->{build_pl} ) { | 
| 543 |  |  |  |  |  |  | my $file = $self->dist_build_pl; | 
| 544 |  |  |  |  |  |  | return undef unless -f $file; | 
| 545 |  |  |  |  |  |  | $self->{build_pl} = File::Slurp::read_file($file); | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  | return $self->{build_pl}; | 
| 548 |  |  |  |  |  |  | } | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | sub module_doc { | 
| 551 |  |  |  |  |  |  | my $self = shift; | 
| 552 |  |  |  |  |  |  | unless ( exists $self->{module_doc} ) { | 
| 553 |  |  |  |  |  |  | if ( -f $self->module_pod ) { | 
| 554 |  |  |  |  |  |  | $self->{module_doc} = $self->module_pod; | 
| 555 |  |  |  |  |  |  | } else { | 
| 556 |  |  |  |  |  |  | $self->{module_doc} = $self->module_pm; | 
| 557 |  |  |  |  |  |  | } | 
| 558 |  |  |  |  |  |  | } | 
| 559 |  |  |  |  |  |  | return $self->{module_doc}; | 
| 560 |  |  |  |  |  |  | } | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | sub module_version { | 
| 563 |  |  |  |  |  |  | my $self = shift; | 
| 564 |  |  |  |  |  |  | unless ( $self->{module_version} ) { | 
| 565 |  |  |  |  |  |  | my $file    = $self->module_pm; | 
| 566 |  |  |  |  |  |  | my $version = Module::Extract::VERSION->parse_version_safely($file); | 
| 567 |  |  |  |  |  |  | unless ( $version and $version ne 'undef' ) { | 
| 568 |  |  |  |  |  |  | return undef; | 
| 569 |  |  |  |  |  |  | } | 
| 570 |  |  |  |  |  |  | $self->{module_version} = $version; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  | return $self->{module_version}; | 
| 573 |  |  |  |  |  |  | } | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | sub find_ppport { | 
| 576 |  |  |  |  |  |  | File::Find::Rule->name('*.xs')->file->grep(qr/\bppport\.h\b/); | 
| 577 |  |  |  |  |  |  | } | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | sub find_files { | 
| 580 |  |  |  |  |  |  | File::Find::Rule->file; | 
| 581 |  |  |  |  |  |  | } | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | sub find_0644 { | 
| 584 |  |  |  |  |  |  | File::Find::Rule->name(qw{ | 
| 585 |  |  |  |  |  |  | Changes | 
| 586 |  |  |  |  |  |  | Makefile.PL | 
| 587 |  |  |  |  |  |  | META.yml | 
| 588 |  |  |  |  |  |  | *.t | 
| 589 |  |  |  |  |  |  | *.pm | 
| 590 |  |  |  |  |  |  | *.pod | 
| 591 |  |  |  |  |  |  | } )->file; | 
| 592 |  |  |  |  |  |  | } | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | sub find_executable { | 
| 595 |  |  |  |  |  |  | File::Find::Rule->name('*.exe')->not_executable->file; | 
| 596 |  |  |  |  |  |  | } | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | sub find_localize { | 
| 599 |  |  |  |  |  |  | File::Find::Rule->file->not_binary->writable; | 
| 600 |  |  |  |  |  |  | } | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | sub file_localize { | 
| 603 |  |  |  |  |  |  | File::LocalizeNewlines->new( | 
| 604 |  |  |  |  |  |  | filter  => $_[0]->find_localize, | 
| 605 |  |  |  |  |  |  | verbose => 1, | 
| 606 |  |  |  |  |  |  | ); | 
| 607 |  |  |  |  |  |  | } | 
| 608 |  |  |  |  |  |  |  | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  |  | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | ###################################################################### | 
| 614 |  |  |  |  |  |  | # Paths and Files | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | sub dist { | 
| 617 |  |  |  |  |  |  | my $self   = shift; | 
| 618 |  |  |  |  |  |  | my $dist = $self->module; | 
| 619 |  |  |  |  |  |  | $dist =~ s/::/-/g; | 
| 620 |  |  |  |  |  |  | return $dist; | 
| 621 |  |  |  |  |  |  | } | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | sub dist_dir { | 
| 624 |  |  |  |  |  |  | curdir(); | 
| 625 |  |  |  |  |  |  | } | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | sub dist_tardist { | 
| 628 |  |  |  |  |  |  | $_[0]->dist_file; | 
| 629 |  |  |  |  |  |  | } | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  | sub dist_file { | 
| 632 |  |  |  |  |  |  | $_[0]->dist . '-' . $_[0]->dist_version . '.tar.gz'; | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | sub dist_version { | 
| 636 |  |  |  |  |  |  | $_[0]->module_version; | 
| 637 |  |  |  |  |  |  | } | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | sub dist_makefile_pl { | 
| 640 |  |  |  |  |  |  | 'Makefile.PL'; | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | sub dist_build_pl { | 
| 644 |  |  |  |  |  |  | 'Build.PL'; | 
| 645 |  |  |  |  |  |  | } | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | sub dist_changes { | 
| 648 |  |  |  |  |  |  | 'Changes'; | 
| 649 |  |  |  |  |  |  | } | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | sub dist_license { | 
| 652 |  |  |  |  |  |  | 'LICENSE'; | 
| 653 |  |  |  |  |  |  | } | 
| 654 |  |  |  |  |  |  |  | 
| 655 |  |  |  |  |  |  | sub dist_readme { | 
| 656 |  |  |  |  |  |  | 'README'; | 
| 657 |  |  |  |  |  |  | } | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | sub dist_meta_yml { | 
| 660 |  |  |  |  |  |  | 'META.yml'; | 
| 661 |  |  |  |  |  |  | } | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | sub dist_manifest { | 
| 664 |  |  |  |  |  |  | 'MANIFEST'; | 
| 665 |  |  |  |  |  |  | } | 
| 666 |  |  |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | sub dist_manifest_skip { | 
| 668 |  |  |  |  |  |  | 'MANIFEST.SKIP'; | 
| 669 |  |  |  |  |  |  | } | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | sub dist_manifest_add { | 
| 672 |  |  |  |  |  |  | 'MANIFEST.SKIP.add'; | 
| 673 |  |  |  |  |  |  | } | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | sub dist_ppport { | 
| 676 |  |  |  |  |  |  | 'ppport.h'; | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  |  | 
| 679 |  |  |  |  |  |  | sub dist_t { | 
| 680 |  |  |  |  |  |  | 't'; | 
| 681 |  |  |  |  |  |  | } | 
| 682 |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  | sub dist_data { | 
| 684 |  |  |  |  |  |  | catdir('t', 'data'); | 
| 685 |  |  |  |  |  |  | } | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | sub dist_99_author { | 
| 688 |  |  |  |  |  |  | catfile('t', '99_author.t'); | 
| 689 |  |  |  |  |  |  | } | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | sub dist_xt { | 
| 692 |  |  |  |  |  |  | 'xt'; | 
| 693 |  |  |  |  |  |  | } | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | sub module_pm { | 
| 696 |  |  |  |  |  |  | catfile( 'lib', $_[0]->module_subpath ) . '.pm'; | 
| 697 |  |  |  |  |  |  | } | 
| 698 |  |  |  |  |  |  |  | 
| 699 |  |  |  |  |  |  | sub module_pod { | 
| 700 |  |  |  |  |  |  | catfile( 'lib', $_[0]->module_subpath ) . '.pod'; | 
| 701 |  |  |  |  |  |  | } | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | sub module_subpath { | 
| 704 |  |  |  |  |  |  | catdir( split /::/, $_[0]->module ); | 
| 705 |  |  |  |  |  |  | } | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | sub shared_manifest_skip { | 
| 708 |  |  |  |  |  |  | catfile( $_[0]->shared_dir, 'MANIFEST.SKIP' ); | 
| 709 |  |  |  |  |  |  | } | 
| 710 |  |  |  |  |  |  |  | 
| 711 |  |  |  |  |  |  | sub shared_license { | 
| 712 |  |  |  |  |  |  | catfile( $_[0]->shared_dir, 'LICENSE' ); | 
| 713 |  |  |  |  |  |  | } | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | sub shared_dir { | 
| 716 |  |  |  |  |  |  | File::ShareDir::dist_dir('ADAMK-Release') | 
| 717 |  |  |  |  |  |  | or $_[0]->error("Failed to find share directory"); | 
| 718 |  |  |  |  |  |  | } | 
| 719 |  |  |  |  |  |  |  | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  |  | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | ###################################################################### | 
| 724 |  |  |  |  |  |  | # Support Methods | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | # Is a particular program installed, and where | 
| 727 |  |  |  |  |  |  | sub which { | 
| 728 |  |  |  |  |  |  | my $self    = shift; | 
| 729 |  |  |  |  |  |  | my $program = shift; | 
| 730 |  |  |  |  |  |  | my ($location) = (`which $program`); | 
| 731 |  |  |  |  |  |  | chomp $location; | 
| 732 |  |  |  |  |  |  | unless ( $location ) { | 
| 733 |  |  |  |  |  |  | $self->error("Can't find the required program '$program'. Please install it"); | 
| 734 |  |  |  |  |  |  | } | 
| 735 |  |  |  |  |  |  | unless ( -r $location and -x $location ) { | 
| 736 |  |  |  |  |  |  | $self->error("The required program '$program' is installed, but I do not have permission to read or execute it"); | 
| 737 |  |  |  |  |  |  | } | 
| 738 |  |  |  |  |  |  | return $location; | 
| 739 |  |  |  |  |  |  | } | 
| 740 |  |  |  |  |  |  |  | 
| 741 |  |  |  |  |  |  | sub copy { | 
| 742 |  |  |  |  |  |  | my $self = shift; | 
| 743 |  |  |  |  |  |  | my $from = shift; | 
| 744 |  |  |  |  |  |  | my $to   = shift; | 
| 745 |  |  |  |  |  |  | File::Flat->copy( $from => $to ) and return 1; | 
| 746 |  |  |  |  |  |  | $self->error("Failed to copy '$from' to '$to'"); | 
| 747 |  |  |  |  |  |  | } | 
| 748 |  |  |  |  |  |  |  | 
| 749 |  |  |  |  |  |  | sub move { | 
| 750 |  |  |  |  |  |  | my $self = shift; | 
| 751 |  |  |  |  |  |  | my $from = shift; | 
| 752 |  |  |  |  |  |  | my $to   = shift; | 
| 753 |  |  |  |  |  |  | File::Flat->copy( $from => $to ) and return 1; | 
| 754 |  |  |  |  |  |  | $self->error("Failed to move '$from' to '$to'"); | 
| 755 |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | sub remove { | 
| 758 |  |  |  |  |  |  | my $self = shift; | 
| 759 |  |  |  |  |  |  | my $path = shift; | 
| 760 |  |  |  |  |  |  | if ( -e $path ) { | 
| 761 |  |  |  |  |  |  | $self->sudo( | 
| 762 |  |  |  |  |  |  | "rm -rf $path", | 
| 763 |  |  |  |  |  |  | "Failed to remove '$path'" | 
| 764 |  |  |  |  |  |  | ); | 
| 765 |  |  |  |  |  |  | } | 
| 766 |  |  |  |  |  |  | return 1; | 
| 767 |  |  |  |  |  |  | } | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | sub sudo { | 
| 770 |  |  |  |  |  |  | my $self    = shift; | 
| 771 |  |  |  |  |  |  | my $message = pop @_; | 
| 772 |  |  |  |  |  |  | my $cmd     = join ' ', @_; | 
| 773 |  |  |  |  |  |  | my $env     = $self->env( | 
| 774 |  |  |  |  |  |  | ADAMK_RELEASE     => 1, | 
| 775 |  |  |  |  |  |  | RELEASE_TESTING   => $ENV{RELEASE_TESTING}   ? 1 : 0, | 
| 776 |  |  |  |  |  |  | AUTOMATED_TESTING => $ENV{AUTOMATED_TESTING} ? 1 : 0, | 
| 777 |  |  |  |  |  |  | ); | 
| 778 |  |  |  |  |  |  | print "> (sudo) $cmd\n" if $self->verbose; | 
| 779 |  |  |  |  |  |  | my $sudo = $self->bin_sudo; | 
| 780 |  |  |  |  |  |  | my $rv   = ! system( "$sudo bash -c '$env $cmd'" ); | 
| 781 |  |  |  |  |  |  | if ( $rv or ! @_ ) { | 
| 782 |  |  |  |  |  |  | return $rv; | 
| 783 |  |  |  |  |  |  | } | 
| 784 |  |  |  |  |  |  | $self->error($message); | 
| 785 |  |  |  |  |  |  | } | 
| 786 |  |  |  |  |  |  |  | 
| 787 |  |  |  |  |  |  | sub shell { | 
| 788 |  |  |  |  |  |  | my $self    = shift; | 
| 789 |  |  |  |  |  |  | my $message = pop @_; | 
| 790 |  |  |  |  |  |  | my $cmd     = join ' ', @_; | 
| 791 |  |  |  |  |  |  | my $env     = $self->env( | 
| 792 |  |  |  |  |  |  | ADAMK_RELEASE     => 1, | 
| 793 |  |  |  |  |  |  | RELEASE_TESTING   => $ENV{RELEASE_TESTING}   ? 1 : 0, | 
| 794 |  |  |  |  |  |  | AUTOMATED_TESTING => $ENV{AUTOMATED_TESTING} ? 1 : 0, | 
| 795 |  |  |  |  |  |  | ); | 
| 796 |  |  |  |  |  |  | print "> $cmd\n" if $self->verbose; | 
| 797 |  |  |  |  |  |  | my $rv = ! system( "$env $cmd" ); | 
| 798 |  |  |  |  |  |  | if ( $rv or ! @_ ) { | 
| 799 |  |  |  |  |  |  | return $rv; | 
| 800 |  |  |  |  |  |  | } | 
| 801 |  |  |  |  |  |  | $self->error($message); | 
| 802 |  |  |  |  |  |  | } | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | sub env { | 
| 805 |  |  |  |  |  |  | my $self = shift; | 
| 806 |  |  |  |  |  |  | my %env  = @_; | 
| 807 |  |  |  |  |  |  | join ' ', map { "$_=$env{$_}" } sort keys %env; | 
| 808 |  |  |  |  |  |  | } | 
| 809 |  |  |  |  |  |  |  | 
| 810 |  |  |  |  |  |  | sub error { | 
| 811 |  |  |  |  |  |  | my $self    = shift; | 
| 812 |  |  |  |  |  |  | my $message = sprintf(shift, @_); | 
| 813 |  |  |  |  |  |  | Carp::croak($message); | 
| 814 |  |  |  |  |  |  | } | 
| 815 |  |  |  |  |  |  |  | 
| 816 |  |  |  |  |  |  | sub prompt { | 
| 817 |  |  |  |  |  |  | my $self = shift; | 
| 818 |  |  |  |  |  |  | return IO::Prompt::Tiny::prompt(@_); | 
| 819 |  |  |  |  |  |  | } | 
| 820 |  |  |  |  |  |  |  | 
| 821 |  |  |  |  |  |  | sub password { | 
| 822 |  |  |  |  |  |  | my $self     = shift; | 
| 823 |  |  |  |  |  |  | my $password = undef; | 
| 824 |  |  |  |  |  |  | if ( defined $_[0] ) { | 
| 825 |  |  |  |  |  |  | print "$_[0] "; | 
| 826 |  |  |  |  |  |  | } | 
| 827 |  |  |  |  |  |  | eval { | 
| 828 |  |  |  |  |  |  | Term::ReadKey::ReadMode('noecho'); | 
| 829 |  |  |  |  |  |  | $password = <STDIN>; | 
| 830 |  |  |  |  |  |  | }; | 
| 831 |  |  |  |  |  |  | Term::ReadKey::ReadMode(0); | 
| 832 |  |  |  |  |  |  | return undef if not defined $password; | 
| 833 |  |  |  |  |  |  | chomp($password); | 
| 834 |  |  |  |  |  |  | return $password; | 
| 835 |  |  |  |  |  |  | } | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | 1; | 
| 838 |  |  |  |  |  |  |  | 
| 839 |  |  |  |  |  |  | __END__ | 
| 840 |  |  |  |  |  |  |  | 
| 841 |  |  |  |  |  |  | =head1 NAME | 
| 842 |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  | ADAMK::Release - | 
| 844 |  |  |  |  |  |  |  | 
| 845 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 846 |  |  |  |  |  |  |  | 
| 847 |  |  |  |  |  |  | C<ADAMK::Release> is the backend behind the C<adamk-release> script that | 
| 848 |  |  |  |  |  |  | is used to build distribution tarballs for modules with the minimalist | 
| 849 |  |  |  |  |  |  | repository style. | 
| 850 |  |  |  |  |  |  |  | 
| 851 |  |  |  |  |  |  | =head1 AUTHORS | 
| 852 |  |  |  |  |  |  |  | 
| 853 |  |  |  |  |  |  | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | 
| 854 |  |  |  |  |  |  |  | 
| 855 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 856 |  |  |  |  |  |  |  | 
| 857 |  |  |  |  |  |  | L<http://ali.as/> | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | Copyright 2013 Adam Kennedy. | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | This program is free software; you can redistribute | 
| 864 |  |  |  |  |  |  | it and/or modify it under the same terms as Perl itself. | 
| 865 |  |  |  |  |  |  |  | 
| 866 |  |  |  |  |  |  | The full text of the license can be found in the | 
| 867 |  |  |  |  |  |  | LICENSE file included with this module. |