http://qs321.pair.com?node_id=11100287

rje has asked for the wisdom of the Perl Monks concerning the following question:

Good morning fellow monks.

On purpose, I volunteered to update a deploy script. The current script is a Perl 4 stand-alone script that copies files into their proper deployment locations.

How you would do this?

I sold my boss on moving common code into a package, because it would (1) hide and reuse duplicated code, (2) shorten new typical deploy scripts dramatically; (3) potentially reduce accidental errors, (4) introduce such innovations as use strict; and use warnings; and (5) give the systems team a tiny bit of control over code maintainability, as opposed to 'no control' today.

CONSTRAINT: I'm limited to the standard distribution for v5.10.1. I can't install packages.

I'm thinking of a package that minimizes the "visual change" of the existing way, but adds a healthy dose of SAFER.

Here's a very typical example. Note the lack of safe practices.

THE WAY IT IS NOW

#!/usr/bin/perl #--------------------------------------------------------------------- +------------- # Filename: my_filename_goes_here.pl # # This script is executed by the deploy tool as part of the standard # deploy process. This script moves batch SE work flow batch scripts +to the correct # locations where <<we>> expect to find them within the local filesyst +em. # # Date Developer Comment # ---------- ---------------- ------------------------------- +------------- # 02-06-2019 R. Eaglestone Initial creation #--------------------------------------------------------------------- +------------- use File::Copy; # Define script-global variables. $outputDir = "/whatever/data/output"; $executionDir = "/whatever/jobs"; $installDir = "/www/apps/install/path/for/my/process/scripts"; %dirsToDeploy = ( "$outputDir/boo" => 0777, "$outputDir/boo/jum" => 0777, "$executionDir/boo" => 0777, "$executionDir/boo/jum" => 0777, ); %pathsToDeploy = ( "MY_LAUNCHER_11023200099.sh" => '/fancy/deploy/path', "fileSanity.pl" => '/fancy/deploy/path', "transferFile.sh" => '/fancy/deploy/path', ); %filesToDeploy = ( "MY_LAUNCHER_11023200099.sh" => 0775, "fileSanity.pl" => 0775, "transferFile.sh" => 0775, ); @filesToConvert = ( "MY_LAUNCHER_11023200099.sh", "fileSanity.pl", "transferFile.sh", ); # This subroutine ensures that all files are present. sub checkDeployValidity () { # First, check that the install directory exists. if ( !(-d $installDir) ) { return "install directory $installDir was not deployed."; } # Then, check that the base execution directory exists. if ( ! (-d $executionDir) ) { return "execution directory $executionDir does not exist."; } # Next, set permissions on the installation directory. if ( ! chmod(0775, $installDir) ) { return "Setting permissions on directory $installDir failed."; } # Now, check that all files were deployed. my @scriptFileNames = sort(keys(%filesToDeploy)); foreach $fileName (@scriptFileNames) { $currentFile = "$installDir/$fileName"; if ( !(-f $currentFile) ) { return "file $currentFile was not deployed."; } } # Finally, if all files are present, then return success. return ""; } # This subroutine builds any missing directories. sub setUpDirectoryStructure () { # Build any subdirectories, if necessary. my @directoryNames = sort(keys(%dirsToDeploy)); foreach $dirName (@directoryNames) { # Check whether the directory exists... if ( -d $dirName ) { # If so, then set its permissions appropriately. if ( ! chmod($dirsToDeploy{$dirName}, $dirName) ) { print "\tunable to do 'chmod $dirsToDeploy{$dirName} $dirName' +.\n"; } } elsif ( ! mkdir($dirName, $dirsToDeploy{$dirName}) ) { print "\tunable to create directory '$dirName'.\n"; } } # Finally, return success once all directories exist with proper per +missions. return ""; } # This subroutine removes carriage return characters from specific fil +es. sub dosToUnix () { foreach $fileName (@filesToConvert) { my $file = "$installDir/$fileName"; my $tempFile = "$file.tmp_dos2Unix"; open(DOS_FILE, "< $file") || return "cannot open $file for re +ad: $!"; open(UNIX_FILE, "> $tempFile") || return "cannot open $tempFile fo +r write: $!"; # Remove all carriage return ('\r') characters. while (<DOS_FILE>) { s/\r//g; print UNIX_FILE || return "cannot write to $tempFile: $!"; } close(UNIX_FILE) || return "cannot close $tempFile: $!"; close(DOS_FILE) || return "cannot close $file: $!"; rename($file, "$file.orig") || return "cannot rename $file to $fil +e.orig: $!"; rename($tempFile, $file) || return "cannot rename $tempFile to +$file: $!"; unlink("$file.orig") || return "cannot delete $file.orig: +$!"; } return ""; } # This subroutine copies files from the install dir to the execution d +ir. sub copyFilesToTarget () { my @fileNames = sort(keys(%filesToDeploy)); foreach $fileName (@fileNames) { my $source = "$installDir/$fileName"; my $path = $pathsToDeploy{$fileName}; my $target = "$path/$fileName"; if ( -f $target) { chmod(0777, $target) || return "chmod 777 for existing file '$ta +rget' failed."; } copy($source, $target) || return "file copy to '$target' failed."; chmod($filesToDeploy{$fileName}, $target) || return "chmod for '$t +arget' failed."; } return ""; } # This subroutine orchestrates the deploy process. sub main () { # Start by setting umask to 0 to simplify mkdir commands. my $oldUMask = umask(0000); # Next, check that all of the files exist. my $errorMessage = &checkDeployValidity(); if ( $errorMessage ) { umask($oldUMask); die("$0: ERROR - $errorMessage"); } # Then, set up the execution directory structure. $errorMessage = &setUpDirectoryStructure(); if ( $errorMessage ) { umask($oldUMask); die("$0: ERROR - $errorMessage"); } # Convert files from DOS format to Unix format. $errorMessage = &dosToUnix(); if ( $errorMessage ) { umask($oldUMask); die("$0: ERROR - $errorMessage"); } # Now, copy the files over. $errorMessage = &copyFilesToTarget(); if ( $errorMessage ) { umask($oldUMask); die("$0: ERROR - $errorMessage"); } # Finally, restore the old umask value (in case this process is reus +ed). umask($oldUMask); print "Copy succeeded. Job finished successfully.\n"; exit(0); } &main ();

THE WAY I'M THINKING IT COULD BE, my knee-jerk gut reaction:

#!/usr/bin/perl #--------------------------------------------------------------------- +-------------- # Filename: my_filename_goes_here.pl # # This script is executed by the deploy tool as part of the standard # deploy process. This script moves batch SE work flow batch scripts +to the correct # locations where <<we>> expect to find them within the local filesyst +em. # # Date Developer Comment # ---------- ---------------- ------------------------------- +-------------- # 02-06-2019 R. Eaglestone Initial creation #--------------------------------------------------------------------- +-------------- use DEPLOYER; use File::Copy; # Define script-global variables. DEPLOYER::outputDir("/whatever/data/output"); DEPLOYER::executionDir("/whatever/jobs"); DEPLOYER::installDir("/www/apps/install/path/for/my/process/scripts"); DEPLOYER::dirsToDeploy ( "$outputDir/boo" => 0777, "$outputDir/boo/jum" => 0777, "$executionDir/boo" => 0777, "$executionDir/boo/jum" => 0777, ); DEPLOYER::pathsToDeploy ( "MY_LAUNCHER_11023200099.sh" => '/fancy/deploy/path', "fileSanity.pl" => '/fancy/deploy/path', "transferFile.sh" => '/fancy/deploy/path', ); DEPLOYER::filesToDeploy ( "MY_LAUNCHER_11023200099.sh" => 0775, "fileSanity.pl" => 0775, "transferFile.sh" => 0775, ); DEPLOYER::filesToConvert ( "MY_LAUNCHER_11023200099.sh", "fileSanity.pl", "transferFile.sh", ); DEPLOYER::deploy();

Thus, DEPLOYER would use strict and warnings, have all the deployment guts in it, in a common module managed by the systems team, as opposed to the current chaos.

As I said, this is my gut reaction. Before I rush ahead with this, would you guys have any suggestions for me to consider?