#!/usr/local/bin/perl -w #updbyobjects.pl #Update inventory files direct from object entries with input from user. #A record of what is updated is made in the update log file updbyobjects.log # maintained in the data directory. #Assumptions # Object directories are only two levels deep # Structure of .remoteobjects file = 3 lines per entry # rcg July 2, 1997 # Modified September 19, 1997 Allow change in instrument for each # cruise within an object rcg # Modified October 23, 1997. Fix double prompt and poor error message # when no entry exits # Modified November 13, 1997. Fix double prompt for insturment between # collected and on-line status entries. rcg # Add status value for level 2 record exists so can continue processing rest of # level 2 entries. Improve lookup for si name. rcg # 12/29/1997 rcg Correct code to extract object name and location # to look for first = and to use correct form of object string # in listvar. Add nd as option to verification of instrument # to allow one to skip this cruise. # Edited March 17 1998 Change /data to /data5 rcg # June 22, 1999. V1.70 Replace listgb with list. rcg $version="V1.7 - June 22, 1999"; use subs qw(print); $debug ="no"; if ($debug eq "no") { #this is the real data $datadir="/data/rgroman/Inventory"; $scriptsdir="/data/rgroman/Inventory/scripts"; } elsif ($debug eq "yes") { #use for debugging $datadir="/data/rgroman/Inventory/debug"; $scriptsdir="/data/rgroman/Inventory/scripts/debug"; } else { print STDOUT ("\nHey, can't you spell yes or no correctly in $0"); } $bindir="/data5/globec/bin"; $listvar=$bindir . "/listvar"; $list=$bindir . "/list -c -n -b "; # Define constants $entry_exist_status = -99; $logfile = ">>" . $datadir . "/updbyobjects.log"; open LOG, $logfile or die "Could not append to log file $logfile, error=$!"; print STDOUT "\nAdding data to inventory direct from objects - $version"; $date = scalar (localtime); print STDOUT ("\n\tRun date: ", $date); print LOG ("#\nProgram=$0\nVersion=$version\nRun_date=", $date, "\n#\n"); $objdiskroot="/data5/globec/"; $objdirroot="OBJDIR"; $specific_objroot=$ENV{$objdirroot}; if ( ! defined $specific_objroot or $specific_objroot eq "" ) { $specific_objroot = "globec/gb"; } $objectdir=$objdiskroot . "objects/" . $specific_objroot; #print "\n**debug, objectdir=$objectdir"; print STDOUT "\n\nUpdating inventory data from $datadir\n"; #get legal science investigator names $sinamesfile="/data/rgroman/Inventory/sinames"; print STDOUT "\n\n%%Informational, reading in valid si names .... "; open (SINAMES, $sinamesfile) or die "Could not open sinamesfile=$sinamesfile"; @names=; chomp (@names); close SINAMES; print STDOUT "Done\n"; #get legal instrument names print STDOUT ("\n\n%%Informational, preparing valid instrument ", "list for reading.\n"); @args=$scriptsdir . "/listvalidinst"; system (@args) == 0 or die "system @args failed, error=$?"; open (INSTRUMENTS, "/tmp/instruments") or die "Cannot open instruments file, /tmp/instrumetns, error=$!"; @instruments = ; chomp (@instruments); close INSTRUMENTS; if ( (index $instruments[0], "#") == 0 ) { shift @instruments ;} chdir($datadir) or die "Cannot change to datadir=$datadir directory"; #Get object to work on. opendir OBJDIR, $objectdir or die "Could not open object directory $objectdir, error=$!"; @objdirectories=grep -d, map "$objectdir/$_", readdir OBJDIR; #print "**debug, objdirectories=, @objdirectories"; closedir OBJDIR; $k=0; $alldirectories[$k]=$objectdir; print STDOUT "\n\t$k = $alldirectories[$k]"; for ($i=1; $i<=$#objdirectories; $i=$i+1) { # print "\n**debug, objdirectories[$i]=$objdirectories[$i]"; if ( index ($objdirectories[$i], "/.") >= 0 ) {next;} $k++; $alldirectories[$k]=$objdirectories[$i]; opendir OBJDIR1, $objdirectories[$i] or die "Could not open object directory=$objdirectories[$i]"; @objdirectories1=grep -d, map "$objdirectories[$i]/$_", readdir OBJDIR1; closedir OBJDIR1; print STDOUT "\n\t$k = $alldirectories[$k]"; for ($j=1; $j<=$#objdirectories1; $j++) { if ( index ($objdirectories1[$j], "/..") >= 0) {next;} $k++; $alldirectories[$k]=$objdirectories1[$j]; print STDOUT "\n\t\t$k = $alldirectories[$k]"; } } REDO: print STDOUT ("\n\nWhat object directory do you want to work on", " (0 - $#alldirectories): "); $ans = ; chomp($ans); if ($ans < 0 || $ans > $#alldirectories) { print STDOUT "\n\nNumber out of range, please try again"; goto REDO; } $objectfile=$alldirectories[$ans] . "/.remoteobjects"; #print "\n**debug objectfile = $objectfile\n"; open OBJECTFILE, $objectfile or die "Could not open objectfile=$objectfile"; &readobjectfile; #Process athe objecct entries &processobjects; exit 0; #---------------------------------------------------------------- sub readobjectfile { #Reads objectfile already opened using filehandle OBJECTFILE #Stores # object names in @objname # locations in @objloc # dot object locations in @dotobjectloc # contributor in @objcontrib # description in @objdesc my ( $i, $object_separator, $pos, $record, $z ); $object_separator = "="; #print "\n**debug, in subroutine readobjectfile\n"; $i=0; while ($record = ) { chomp $record; # print ("\n**debug, in readobjectfile, name, loc=", # $objname[$i], $objloc[$i],"\n\trecord=$record"); if ( ! defined $record or $record eq "" or $record eq " ") { if ($i == 0) { print STDOUT "There are no entries to work on here."; } last; } $pos = index $record, $object_separator; if ($pos < 0 ) { print STDOUT ("%%Error in $1/readobjectfile, could not decode", "\n\tobject entry=$record\n\n"); return 1 } $objname[$i] = substr $record, 0, ($pos); $objloc[$i] = substr $record, ($pos+1); $dotobjectloc[$i] = &getdotobjectloc($objloc[$i]); # print "\n**debug, in readobjectfile, name, loc=$objname[$i], $objloc[$i]"; $objcontrib[$i]= ; if ( ! defined $objcontrib[$i] ) { $objcontrib[$i]="nd"; $objdesc[$i]="nd"; last; } chomp ($objcontrib[$i]); $objcontrib[$i]=~ s/^- //; $objdesc[$i]= ; if ( ! defined $objdesc[$i] ) { $objdesc[$i]="nd"; last; } chomp ($objdesc[$i]); $objdesc[$i]=~ s/^- //; # print "\n**debug, $objname[$i] \n\t\t$objcontrib[$i] \n\t\t$objdesc[$i]"; $i++; } #print ("\n**debug, read ", $i, " object names"); #print "\n\tFirst entry: $objname[0] \n\t\t$objcontrib[0] \n\t\t$objdesc[0]"; $z=$#objname; #print "\n\tLast index of objname=$z"; #print "\n\tLast entry: $objname[$z] \n\t\t$objcontrib[$z] \n\t\t$objdesc[$z]"; return 0; } #------------------------------------------------------------------------- sub processobjects { #Process object entries my ( $cruiseid, $desc, $i, $instrument, $invstatus, $j, $object, $siname,); #print "\n**debug in processobjects, last index of objname=$#objname"; if ($#objname < 0 ) {print STDOUT "\n\nThere are no objects to process.\n\n";} for ($i=0; $i <=$#objname; $i=$i+1) { print STDOUT ("\nFor object: $objname[$i]...\n"); &selectsinamefromlist ($objcontrib[$i]); #make si name valid # print ("\n**debug in processobjects ", "alldirectories[$ans]=", # $alldirectories[$ans], "\n\t objname[$i]=", $objname[$i]); $object=$alldirectories[$ans] . "/" . $objname[$i]; $object=~s!^.*objects!!; if (&getvarlist ($dotobjectloc[$i]) != 0 ) {next; } if ( ! defined $bestvar ) {next;} if (&getcruiseids ($dotobjectloc[$i], $bestvar, $bestvarlevel) != 0) {next;} &geturls ($object, $bestvar, $bestvarlevel); $instrument=&getinstrument ($objname[$i], $objloc[$i], $objcontrib[$i], $objdesc[$i] ); if ( $instrument eq "nd" ) { next; } #skip this object print LOG ("Object=",$object,"\nInstrument=",$instrument, "\nContributor=",$objcontrib[$i],"\n#\n"); for ($j=0; $j <= $#cruiseid; $j++) { #assumes need a status=collected line to be added too $desc="Entered by updbyobjects.pl (" . $version . ")"; if (&updateexitinv ($datadir, $cruiseid[$j], $instrument, $objcontrib[$i], "collected", $desc, $i ) == 0 ) { $desc="on-line"; &updateexitinv ($datadir, $cruiseid[$j], $instrument, $objcontrib[$i], "on-line", $desc, $i); } } } return 0; } #--------------------------------------------------------------------- sub selectsinamefromlist { #Convert the passed name $_[0] to a valid name using names from the #array @names #print "\n**debug, in selectsinamefromlist, passed value=$_[0]"; my ($ans, $i, $listed_name, $passed_name); #print ("\n**debug (from selectsinamefromlist), passed value=", $_[0], "\n"); $_[0] =~ s/ /_/g; $_[0] =~ s/\t/ /g; TRY_AGAIN: if ( $_[0] eq "nd") {return $_[0];} #not necessary to match to na for ($i=0; $i < $#names; $i=$i+1) { $listed_name=$names[$i]; $listed_name=~ s/^.*\.(.*)/$1/; $listed_name=~ s/_//; $passed_name= $_[0]; $passed_name=~ s/^.*\.(.*)/$1/; $passed_name=~ s/_//; if (index (lc ($listed_name), lc ($passed_name) ) != -1 ) { $_[0] = $names[$i]; print STDOUT ("\n\n%%Informational, si name to be used ", "is $_[0]\n", " \tIs this okay (y or enter new name)? "); $ans=; chomp $ans; if (lc $ans eq "y" ) {return $_[0];} $_[0]=$ans; goto TRY_AGAIN; } } print STDOUT ("\n\nCould not find valid si name given $_[0].\n\t", "Please guess last name or enter nd [nd]: "); $_[0]=; chomp $_[0]; if ($_[0] eq "" or $_[0] eq " " or $_[0] eq "nd" ) { $_[0]="nd"; } goto TRY_AGAIN; } #------------------------------------------------------------------------- sub getvarlist { #Gets the variable name list for the object specified as $_[0] #determines best variable to use, and saves this variable name #in $bestvar, and saves its "level" in $bestvarlevel. If they #don't exit, these variables are returned as undefined and status #is set to 1. Status is return as 0 if processing went without #errors, 1 otherwise. my ($record, $variable); #print ("\n**debug in getvarlist, passed parameters=", @_); undef $bestvar; undef $bestvarlevel; open (VARLIST, "$listvar $_[0]|") or die "Could not get variable names via listvar for $_[0], error=$!"; while ($record=) { chomp ($record); # print "\n**debug in getvarlist, record=$record"; if ( index ($record, "&x") >= 0 ) { print STDOUT ("\n\n%%Error in getvarlist, could not ", "get variables", " using \n\t$listvar $_[0]\n"); print LOG ("No_update=Error in getvarlist, could not ", "get variables\nCode=$listvar\nObject=$_[0]\n#\n"); return 1; } $variable=$record; $variable=~s/ //g; if (index ($variable, "cruise") ge 0 ) { #found it! $bestvar=$variable; $bestvarlevel=int ((index $record, $variable) / 2); # print ("\n**debug, bestvar=$bestvar, bestlevel=$bestvarlevel"); return 0; } } print STDOUT ("\n%%Warning, no useful field name (e.g. cruise_id) could ", "be found in object\n\t", @_, "\n\tThis object could not be processed.\n\n"); return 1; } #------------------------------------------------------------------------- sub getcruiseids { #For the object $_[0], given the best field name $_[1], and the #field name level $_[2] for this variable name, #return the list #of cruiseids in @cruiseid for which there are data. #Note: the field name level is not needed now, but included for #possible use later. my ($i, $level, $object, $record ); #print ("\n**debug in getcruiseids, passed parameters=", @_); undef @cruiseid; $level=$_[2]; $object=$_[0] . "\\(" . $_[1] . "\\)"; #print "\n**debug, getcruiseids, object=$object"; open (LISTGB, "$list $object|") or die "Cannot get data via list for\n\tobject=$object, error=$!"; $i=-1; while ($record = ) { chomp ($record); if ( index ($record, "&x") < 0 ) { $i++; $record =~ s/^ *//; $cruiseid[$i]=$record; # print "\n**debug, getcruiseids, cruiseid[$i]=$cruiseid[$i]"; } else { #list found error print STDOUT ("\n\n%%Error in getting cruise id's for ", "object=$_[0]", "\n\tfield name=$_[1] and field name level=$_[2]\n", "\tError message is:\n\t$record\n\n"); next; } } #print "\n**debug, getcruiseids, cruiseid=@cruiseid"; if ($i >= 0) { return 0; } else { return 1; } } #------------------------------------------------------------------------- sub geturls { #For the object $_[0], field name $_[1], level # in $_[2] and the cruiseid's #in @cruiseid, construct and return the URL's for each cruiseid in @url. #The passed object is of the form /object/dir/tree/remoteobjectname my ($i); for ($i=0; $i<=$#cruiseid; $i=$i+1) { $url[$i] = "http://globec.whoi.edu/jg/makeinvlink?" . $_[0] . "/" . $_[1] . "/" . $cruiseid[$i] . "/" . $_[2]; # print ("\n**debug, geturls, url for ", $cruiseid[$i] , # "=", $url[$i]); } } #------------------------------------------------------------------------- sub getinstrument { #For the object $_[0], location $_[1], contributor $_[2] and #description $_[3], ask the user what the instrument is given the #list of choices in predefined array @instruments. Return the #selected instrument text in the function name. my ($ans, @args, $command, $i, $instrument, $j); #print ("\n**debug in getinstrument, passed parameters=\n\t",@_); for ($i=0; $i <= $#instruments; $i++ ) { print STDOUT "\n\t($i) - $instruments[$i]"; } print STDOUT ("\n\nFor object $_[0] \n\t$_[1],", " \n\t$_[2],\n\t$_[3]\n"); REDO1: ; print STDOUT ( "\nWhat is the instrument corresponding to these data", " (0 - $#instruments, or nd): "); $ans = ; chomp($ans); if ($ans eq "nd" ) { return $ans; } elsif ($ans < 0 || $ans > $#instruments) { print STDOUT "\n\nNumber out of range, please try again"; goto REDO1; } else { $instrument=$instruments[$ans]; chomp $instrument; return $instrument; } } #------------------------------------------------------------------------- sub updateexitinv { #Update an existing entry in the inventory for # datadirectory = $_[0] # cruiseid =$_[1] # instrument = $_[2] # siname = $_[3], # statusinfo = $_[4] # description = $_[5] # obj_pointer = $_[6] #If there is no entry in the inventory for this cruiseid, issue a #warning message and do nothing. # User is queried to see if instrument is valid for this particular cruiseid # when $statusinfo="collected" only so query is not asked twice for the same # cruise. my ($ans, @comments, $cruiseid, $datadir, $desc, $file1, $file2, $instrument, @level1, @level2, $obj_pointer, $siname, $status, $statusinfo); chomp @a; #print ("\n**debug in updateexitinv, passed parameters=\n\t",@_); ($datadir, $cruiseid, $instrument, $siname, $statusinfo, $desc, $obj_pointer) = @_; if ($statusinfo eq "collected") { print STDOUT (" \nIs the instrument $instrument correct for ", uc $cruiseid, " (y, n, or ", "nd (to skip))", "? "); $ans=; chomp $ans; if ( $ans eq "nd" ) {return 1;} unless (lc $ans eq "y" ) { $instrument=&getinstrument ($objname[$obj_pointer], $objloc[$obj_pointer], $objcontrib[$obj_pointer], $objdesc[$obj_pointer] ); if ( $instrument eq "nd" ) { return 1; } else { $_[2]=$instrument; } } } $status = &updateinvlevel1 ($datadir, $cruiseid, $instrument, $siname); if ($status == 0) { $status = &updateinvlevel2 ($datadir, $cruiseid, $instrument, $statusinfo, $desc); if ($status == 0) { print LOG ("Action=updateexitinv\n", "Project_or_cruiseid=$cruiseid\n", "Instrument=$instrument\n", "SI_name=$siname\n", "Status=$statusinfo\n", "Description=$desc\n#\n"); } elsif ($status == $entry_exist_status) { #okay to continue processing $status = 0; } } return $status; } #--------------------------------------------------------------------- sub updateinvlevel1 { #Update inventory level 1 file where # datadir = $_[0] # cruiseid = $_[1] # instrument = $_[2] # siname = $_[3] #Return 1 if cannot do update because, e.g. there is no exiting # entry for project (cruiseid). Log entry is made when failure # occurs. my (@comments, $cruiseid, $datadir, $file1, @firstpart, $instrument, @level1, $numb_comments, $siname, @sorted); #print ("\n**debug in updateinvlevel1, passed parameters=\n\t",@_); #Currently, this routine insists that the file already exists. #$oldumask=umask 002; #set priv. to ensure group write access #print "\n**debug in updateinvlevel1, oldumask=$oldumask"; ($datadir, $cruiseid, $instrument, $siname) = @_; $file1 = $datadir . "/" . uc ($cruiseid) . ".dat"; #print "\n**debug in updateinvlevel1, file1=$file1"; if ( ! -e $file1 or ! -w $file1 ) { print STDOUT ("\n\n%%Warning: cannot write to level 1 data file\n\t", $file1, "\n\tfor project=$cruiseid", " and instrument=$instrument.\n", "\tThis could be because there is no entry for ", "this project yet."); print STDOUT "\n\tCannot do this update.\n"; print LOG ("No_update=No level 1\nproject=",$cruiseid,"\nInstrument=", $instrument,"\n#\n"); return 1; } open LEVEL1, $file1 or die "Could not open file=$file1, error=$!"; @level1 = ; close LEVEL1; $found = grep /^$instrument/, @level1; #print ("\n**debug in updateinvlevel1, found=$found for instrument=$instrument", # "\n\tin file=$file1"); if ($found == 0) { $level1[$#level1 + 1]=$instrument . "\tnd" . "\tnd" . "\tnd" . "\tnd" . "\tnd" . "\tnd\t" . $siname . "\t" . uc ($cruiseid) . "-" . $instrument . ".dat\n"; @firstpart = grep /^#/, @level1; #get comment lines $numb_comments=$#firstpart; #save two line field names $firstpart[$#firstpart +1] = $level1[$numb_comments+1]; $firstpart[$#firstpart +1] = $level1[$numb_comments+2]; for ($i=0; $i <= $numb_comments + 2; $i=$i+1) {shift @level1;} @sorted = sort @level1; open LEVEL1, ">$file1" or die "Could not open $file1 for writing, error=$!"; print LEVEL1 @firstpart; print LEVEL1 @sorted; close LEVEL1; print STDOUT ("\n%%Informational, level 1 file $file1", "\n\thas been updated ", "for cruise=$cruiseid and instrument=$instrument.\n"); } return 0; } #--------------------------------------------------------------------- sub updateinvlevel2 { #Update inventory level 2 file where # datadir = $_[0] # cruiseid = $_[1] # instrument = $_[2] # statusinfo = $_[3] # description = $_[4] #Notes: # 1. If statusinfo = on-line or collected and such a # record exists in the file, no update is made. # A warning message is issued, and returned status is # 1. my ($cruiseid, $datadir, $date, $desc, @dummy, $exitingstatus,$file2, @firstpart, $i, $instrument, @level2, @month, $numb_comments, $oldumask, $ori_numb_comments, $statusinfo ); $month{"Jan"}=1;$month{"Feb"}=2;$month{"Mar"}=3;$month{"Apr"}=4; $month{"May"}=5;$month{"Jun"}=6;$month{"Jul"}=7;$month{"Aug"}=8; $month{"Sep"}=9;$month{"Oct"}=10;$month{"Nov"}=11;$month{"Dec"}=12; #print ("\n**debug in updateinvlevel2, passed parameters=\n\t",@_); ($datadir, $cruiseid, $instrument, $statusinfo, $desc) = @_; $file2 = $datadir . "/" . uc ($cruiseid) . "-" . $instrument . ".dat"; #print "\n**debug in updateinvlevel2, file2=$file2"; $oldumask=umask 002; #set priv. to ensure group write access #print "\n**debug in updateinvlevel2, oldumask=$oldumask"; @date= split /\s+/, scalar (localtime); if (! -e $file2) { open LEVEL2, ">$file2" or die "\nCould not create level 2 file $file2, error=$!"; print LEVEL2 "#\n#Last updated: @date\n"; print LEVEL2 "status\tyear\tmonth\tday\tdescription\n"; print LEVEL2 "$statusinfo\t$date[4]\t$month{$date[1]}\t$date[2]\t$desc\n"; print STDOUT ("\n%%Informational, level 2 file $file2", "\n\thas been updated ", "for \n\tcruise=$cruiseid, instrument=$instrument,", " and \n\tstatus=$statusinfo\n"); return 0; } open LEVEL2, $file2 or die "Could not open level 2 file file=$file2, error=$!"; @level2 = ; close LEVEL2; #Test for existing on-line or collected record for ( $i=0; $i<=$#level2; $i++ ) { ($exitingstatus, @dummy) = split /\t/, $level2[$i]; if ($statusinfo eq $exitingstatus and ( $statusinfo eq "on-line" or $statusinfo eq "collected")) { print STDOUT ("\n%%Informational: for project or cruise=$cruiseid, ", " instrument=",$instrument, "\n\t", $statusinfo, " record already exists.", " No update made.\n"); return $entry_exist_status; } } $level2[$#level2 + 1] = $statusinfo . "\t" . $date[4] . "\t". $month{$date[1]} . "\t" . $date[2] . "\t" . $desc . "\n"; @firstpart = grep /^#/, @level2; #get comment lines $ori_numb_comments=$#firstpart; $numb_comments=$ori_numb_comments; for ( $i=0; $i <= $ori_numb_comments; $i++ ) { if ( index ($firstpart[$i], "Last updated") >= 1 ) { $firstpart[$i]= "#Last updated: " . $date[4] . $date[1] . $date[2] . $date[3] . "\n"; last; } elsif ($i == $ori_numb_comments) { $numb_comments++; $firstpart[$numb_comments] = "#Last updated: " . $date[4] . $date[1] . $date[2] . $date[3] . "\n"; } } #save one line of field names $firstpart[$#firstpart +1] = $level2[$ori_numb_comments+1]; for ($i=0; $i <= $ori_numb_comments + 1; $i=$i+1) { #remove comments and variable line shift @level2; } open LEVEL2, ">$file2" or die "Could not open $file2 for writing, error=$!"; print LEVEL2 @firstpart; print LEVEL2 @level2; close LEVEL2; print STDOUT ("\n%%Informational, level 2 file $file2\n\thas been updated ", "for cruise=$cruiseid, instrument=$instrument,\n\t", "and \status=$statusinfo\n"); return 0; } #--------------------------------------------------------------------------- sub getdotobjectloc { #Determines actual "dot object" string given the right hand side of the #.remoteobject entry in $_[1]. Value returned is the routines best guess #at the object to be used, e.g. by the listvar routine. my $loc; #print STDOUT ("\n**debug getdotobjectloc, _[0]=$_[0]\n"); $loc = $_[0]; $loc =~ s/^http:(.*)/$1/; $loc =~ s!^(.*)\.html.*!$1!; $loc =~ s!^(.*)/jg/serv(.*)!$1$2!; #print STDOUT ("\n**debug getdotobjectloc, loc=$loc\n"); return $loc; }