use strict; use warnings; use LWP::Simple; use Config; use Digest::MD5; use File::Copy; use File::Path; use Getopt::Long; use vars qw/$VERBOSE $FORCE/; sub say(@) { my $str=join "",@_; $str=~s/\n?\z/\n/; print $str if ($VERBOSE); } sub help_them(){ local $VERBOSE=1; die <<'EOFBLURB'; alien_nmake.pl Automatically download, unpack and install nmake 1.5 from microsoft. The downloaded and unpacked files will be compared with known valid checksums and if there are any mismatches the files will not be executed or installed. The install location will by default be the Perl 'bin' directory. If the script detects nmake already installed it will do nothing. Options are: --help|-h Print out this documentation --verbose Be verbose during installation process --force Download and install it regardless --path Specify the install location, if the direction does not exist it will be created. Many thanks to Microsoft for making this essential tool available to all for free. EOFBLURB } sub md5_file_check { my ($file, $expect) = @_; open my $fh,"<", $file or die "Error: Can't open '$file' for md5 check: $!"; binmode($fh); my $digest = Digest::MD5->new->addfile($fh)->hexdigest; if ($expect and $digest ne $expect) { my $msg ="Error : '$file' fails md5 check, '$expect' ne '$digest'"; if (wantarray) { warn $msg; return } else { die $msg; } } $digest; } sub run_and_check { my ($cmd,$qr) = @_; my $res = `$cmd 2>&1`; if ($res=~/$qr/) { return $res; } else { return; } } my $path = $Config{bin}; my $remove; my $url = "http://download.microsoft.com/download/vc15/patch/1.52/w95/en-us/"; my $exe = "nmake15.exe"; my $md5 = "3d0a6e5b6d49ce18df33ad5a84a4403b"; my %unpacked = qw( nmake.exe 08465a1db6aa445ddcb62d0f29e8486b nmake.err 676935b178bbe8eb3e21d41bd5666b2c readme.txt 7e3ec06f008ae3deacc73f90c7e43405 ); GetOptions ( "force|f" => \$FORCE, # numeric "verbose" => \$VERBOSE, # string "help|h" => \&help_them, "path" => \$path, "remove" => \$remove, ) or help_them; say "alien_nmake.pl starting in verbose mode.\n\n"; if ($remove) { say "Removing files\n"; for (keys %unpacked) { if (-e $_) { unlink "$path/$_" or warn "Failed to remove '$path/$_':$!"; } } exit(0); } if ( ! -d $path ) { say "Install directory '$path' does not exist, creating\n"; mkpath $path; } unlink $_ for sort keys %unpacked; if ( my $res = run_and_check('nmake /?','Microsoft') ) { my ($version)=$res=~/(Version .*)$/m; if (!$FORCE) { say "You do not need to use this tool as you have nmake $version installed.\n\n"; exit(0); } else { say "Will force install even though you have nmake $version installed.\n\n"; } } else { say "I can not detect nmake on your system, will install now into $path\n\n"; } if ( $FORCE || !-e $exe || !md5_file_check( $exe, $md5 ) ) { say "Downloading '$exe'."; getstore $url.$exe, $exe; md5_file_check( $exe, $md5 ); } else { say "Not downloading '$exe' as it is already present and has a valid checksum."; } if (!-e $exe) { die "Error : Failed to download '$exe'"; } say "\nRunning self-extracting package."; my @install = `$exe 2>&1`; say $_ for @install,""; foreach my $file (sort keys %unpacked) { md5_file_check( $file, $unpacked{$file} ); my $dest = "$path\\$file"; if ($file=~/readme/i) { say "Not copying '$file' to '$path' as it is a readme.\n"; next; } copy $file, $dest or die "Error : Failed to copy '$file' to '$dest': $!"; say "File '$file' copied to '$path' ok.\n"; } say "\nAll Done -- No errors."; exit(0);