#!/usr/bin/perl -w # COMBUSTION SUBMIT GUI # erco@3dsite.com 05/06/05 peeled 102.416 copy of submit-shake.pl # # Rush Render Queue Software. # (C) Copyright Greg Ercolano, 2002. All rights reserved. # # This is a sample Combustion GUI submit script you can customize # for your own company's purposes. This script is called # in various ways: # # 1) User invokes gui ($ARGV[0] eq "") # 2) Gui self-invokes if user hits 'Update' ($ARGV[0] eq "-update") # 3) Gui self-invokes to submit job ($ARGV[0] eq "-submit") # 4) Job self-invokes to render frames ($ARGV[0] eq "-render") # use strict; use FindBin; $G::title = "Rush Combustion Submit"; $G::progname = "submit-combustion"; $G::logtrim_always = 0; # 1=always use logtrim (improves render times) # LOAD COMMON VARIABLES + FUNCTIONS require "$FindBin::Bin/.common.pl"; # SET THE FILE CHOOSER STYLE: # "f" -- Fltk's new chooser # "n" -- Native chooser (windows default chooser) # "o" -- Old chooser # $ENV{RUSH_FILECHOOSER} = "f"; # 'n' is recommended ############################################################### ### COMBUSTION SPECIFIC VARIABLES -- CUSTOMIZE AS NECESSARY ### ### See Discreet's documentation for more info. ### ############################################################### if ( $G::iswindows ) { # WINDOWS $ENV{PATH} = "c:/program files/discreet/combustion 4;$ENV{PATH}"; } elsif ( $G::ismac ) { # OSX $ENV{PATH} = "/Applications/Discreet/Combustion/bin:$ENV{PATH}"; } else { # LINUX $ENV{PATH} = "/usr/discreet/combustion/bin:$ENV{PATH}"; } # LOAD ALL CPU NAMES FROM 'rush -lah' sub LoadAllCpus() { my @cpus; unless ( open(RUSHPIPE, "rush -lah|") ) { push(@cpus, "open(rush -lah): $!"); return(@cpus); } while ( ) { if ( $_ =~ /^[0-9.\?]*\s+([A-za-z0-9-_]*)\s+\d+\s+(\d+).*\+any/ ) { push(@cpus, "$1=$2"); } } close(RUSHPIPE); return(@cpus); } # SAVE OUT DEFAULT FORM sub WriteDefaults($) { my $filename = $_[0]; unless ( open(DEFAULTS, ">$filename") ) { return("$filename: $!"); } # LOAD RUSH HOSTS FILE TO PRELOAD 'Cpus:' REPORT my $cpus = ""; { my @cpulist = LoadAllCpus(); foreach ( @cpulist ) { $cpus .= ($cpus ne "" ? "\n":""). " Cpus: $_"; } } print DEFAULTS <<"EOF"; JobTitle: WorkspacePath: //server/jobs/SHOW/SHOT/combustion/test.cws OutputPath: //server/jobs/SHOW/SHOT/images/out ImageFormat: cineon ImageDepth: default ImageChannels: default LogDir: Frames: 1-10 MaxTime: 00:00:00 MaxTimeState: Que Priority: 1 $cpus MaxLogSize: 0 Ram: 1 AutoDump: Off DoneMail: DumpMail: WaitFor: WaitForState: Dump CombustionFlags: NeverCpus: SubmitOptions: LogFlags: Overwrite SubmitHosts: BatchFrames: 1 ImgCommand: BatchClip: yes Retries: 1 RetryBehavior: Fail FieldDominance: default FrameReference: default FrameSize: default ImageQuality: default EOF close(DEFAULTS); return(""); } # RESET THE CURRENT FORM TO THE DEFAULTS -- HANDLES "-defaults" # Rewrite defaults, reload form. # sub MAIN_Defaults() { my $errmsg = WriteDefaults($ENV{INPUT_DBASE}); if ( $errmsg ne "" ) { ErrorWindow($errmsg); exit(1); } exit(0); } # PRESENT USER WITH INPUT FORM # Prompts the user for data. # sub MAIN_Input() { # CREATE DEFAULTS IF NONE if ( ! -e $G::lastsubmit ) { if ( CreateDotRushDir() < 0 ) { exit(1); } my $errmsg = WriteDefaults($G::lastsubmit); if ( $errmsg ne "" ) { ErrorWindow($errmsg); exit(1); } } # CREATE HISTORY FILE IF NONE open(FD, ">>${G::histfile}"); close(FD); # REPLACE LEGACY KEYWORDS WITH NEW IN HISTORY FILES. # Lets new version parse old history files. # { # Convert keynames: 102.41 -> 102.42 my $errmsg; my $regex = 's/^[\s]*ImgCommand:/ImageCommand:/; s/^[\s]*SubmitHost:/SubmitHosts:/; s/^[\s]*ImgDirectory:.*//; s/^[\s]*LogDir:/LogDirectory:/; s/^[\s]*NeverCpus:/NeverUseCpus:/;'; if ( ApplyRegexToFile($G::histfile, $regex, \$errmsg) < 0 ) { print "WARNING: Couldn't repair histfile: $errmsg\n"; } if ( ApplyRegexToFile($G::lastsubmit, $regex, \$errmsg) < 0 ) { print "WARNING: Couldn't repair lastsubmit: $errmsg\n"; } } # LOAD ALL CPUS my $allcpus = ""; { my @cpulist = LoadAllCpus(); foreach ( @cpulist ) { $allcpus .= (($allcpus ne "")?"\n":""). " option \"$_\""; } } # GET PATH TO HELP FILE my $helpfile = HelpDir("$G::progname.html"); # PRESENT INPUT FORM TO USER # Database names for each field are derived by removing # all spaces from the prompt name. Docs for each field should # be placed in examples/help. # exit(PresentInputForm(<<"EOF")); <> "Rush Combustion Submit" <<HEADING>> "Rush Combustion Submit" <<SAVE-ID>> "Combustion-Submit" <<TAB>> "Main" Job Title: ______________ ? = Workspace Path: ____________________________________________ ? Browse"*.cws" = Output Path: ____________________________________________ ? Browse = Image Format: "bmp,cineon,dpx,filmstrip,jpeg,photoshop,png,quantel,rla,sgi,softimage,targa,tiff,_" ? = Image Depth: "default,8,10,12,16,float,_" ? |= Image Channels: "default,rgba,rgb,a,_" ? Frames: ______________ ? Batch Frames: ______________ ? | Batch Clip: "yes,no" ? = Max Time: "00:00:00,00:05:00,00:10:00,00:30:00,01:00:00,01:30:00,02:00:00,02:30:00,03:00:00,_" ? = MaxTimeState: "Que,Fail,Done,Hold" ? <<RAW-INPUT>> xyinc 138 0 xysize 140 180 selectbrowser { name "Cpus:" dbname "Cpus" type multi $allcpus default "*" helpurl "$helpfile#Cpus" } xyinc +240 -181 choice { name "Priority:" dbname "Priority" option "1" option "2" option "3" option "4" option "5" option "6" option "7" option "8" option "9" option "10" default "1" xysize 60 24 helpurl "$helpfile#Priority" } xyinc -240 +160 <</RAW-INPUT>> <<SUBMITDEFAULTS>> <<ENDPAGE>> <<TAB>> "Combustion" = Combustion Flags: __________________________________________________ ? = Field Dominance: "default,none,upper,lower" ? = Frame Size: "default,normal,.50,.33,.25,.125" ? = Image Quality: "default,best,medium,draft" ? = Frame Reference: "default,frame0,frame1,timecode" ? <<TAB>> "Rush" Image Command: ___________________________________________ ? Browse Log Directory: ___________________________________________ ? Browse Log Flags: "Keep Last,Keep All,Overwrite" ? Max Log Size: ______________ ? = AutoDump: "off,fail,done,donefail" ? = Done Mail: ______________ ? = Dump Mail: ______________ ? WaitFor: ______________ ? Wait For State: "Dump,Done,DoneFail,Fail" ? = Ram: ______________ ? = Submit Hosts: __________________________________________________ ? Job Start Command: ___________________________________________ ? Browse Job Done Command: ___________________________________________ ? Browse Job Dump Command: ___________________________________________ ? Browse Never Use Cpus: __________________________________________________ ? __________________________________________________ __________________________________________________ Submit Options: __________________________________________________ ? __________________________________________________ __________________________________________________ = Start Irush: "yes,no,ask" ? |= Print Environment?: "off,on" ? = Retries: "1,2,3,4,5,_" ? |= Retry Behavior: "Fail,AddNever+Requeue" ? EOF } # SUBMIT THE JOB -- HANDLES "-submit" # Parse the user's input, and submit the job to rush. # $ARGV[1]: input filename containing key/value pairs of user's input # sub MAIN_Submit() { # LOAD INPUT FORM -> %in, SAVE HISTORY COPY my %in; my $errmsg; if ( LoadInput(\%in, $ARGV[1], \$errmsg) < 0 ) { print "$errmsg\n"; exit(1); } if ( SaveInput(\%in, ${G::lastsubmit}, \$errmsg) < 0 ) { print "$errmsg\n"; exit(1); } # PARSE STANDARD SUBMIT OPTIONS my $submitoptions = ParseStandardSubmit(\%in); my $submithost = PickOneSubmitHost($in{SubmitHosts}); # BATCH FRAMES my ($batchframes, $batchend, $newframespec) = BatchFramesSubmit(\%in); # PATH FIXUPS $in{WorkspacePath} = FixPath($in{WorkspacePath}); $in{OutputPath} = FixPath($in{OutputPath}); # WORKSPACE EXISTS? if ( ! -f $in{WorkspacePath} ) { print STDERR "*** WORKSPACE FILE NOT FOUND ***\n". "$in{WorkspacePath}: not found or inaccessable ($!)"; exit(1); } # IMAGE DIRECTORY EXISTS? { my $imagedir = $in{OutputPath}; $imagedir =~ s%[/\\][^/\\]*$%%; # /server/images/file -> /server/images if ( ! -d $imagedir ) { print STDERR "*** IMAGE DIRECTORY NOT FOUND ***\n". "$imagedir: directory not found or inaccessible ($!)\n"; exit(1); } } $in{JobTitle} =~ s/[ \t][ \t]*/_/g; # convert embedded white to underbars if ( $in{JobTitle} eq "-" || $in{JobTitle} eq "" ) { # PARSE TITLE FROM FIRST 25 CHARACTERS OF SCENE FILENAME if ( $in{WorkspacePath} =~ m%/([^./]*)\.cws%i ) { $in{JobTitle} = substr($1, 0, 25); # first 25 chars $in{JobTitle} =~ tr/[a-z]/[A-Z]/; # uppercase $in{JobTitle} =~ s/\..*//; # "foo.%04d.mi" -> "foo" } } $in{JobTitle} ||= "SUBMIT-COMBUSTION"; # LOGDIR BASED ON SCENE PATH if ( $in{LogDirectory} eq "" ) { $in{LogDirectory} = "$in{WorkspacePath}.log"; # CREATE LOGDIR ONLY IF AUTOMATICALLY GENERATED if ( ! -d $in{LogDirectory} ) { unless ( mkdir($in{LogDirectory}, 0777) ) { print STDERR "mkdir($in{LogDirectory}): $!\n" . "Can't make log directory.\n"; exit(1); } # WINDOWS: OPEN ACLS FOR THE LOG DIRECTORY if ( $G::iswindows ) { my $dirname = $in{LogDirectory}; $dirname =~ s%/%\\%g; system("cacls $dirname /e /c /g everyone:f"); } } } if ( $in{LogDirectory} ne "-" ) { $in{LogDirectory} = FixPath($in{LogDirectory}); $submitoptions .= "logdir $in{LogDirectory}\n"; } # COMBUSTION FLAGS # Some options need to be translated, because they were too cryptic # to use in the menus. # my $renderflags = ( defined($in{CombustionFlags}) ) ? $in{CombustionFlags} : ""; $renderflags .= ( $in{ImageFormat} ne "default" ) ? (" -format " . $in{ImageFormat} ) : ""; $renderflags .= ( $in{ImageDepth} ne "default" ) ? (" -depth " . $in{ImageDepth} ) : ""; $renderflags .= ( $in{ImageChannels} ne "default" ) ? (" -channels " . $in{ImageChannels} ) : ""; $renderflags .= ( $in{FieldDominance} ne "default" ) ? (" -fields " . $in{FieldDominance} ) : ""; $renderflags .= ( $in{FrameReference} ne "default" ) ? (" -frameref " . $in{FrameReference} ) : ""; # Translate values to Combustion's letter codes if ( $in{FrameSize} eq "normal" ) { $renderflags .= " -framesize Normal"; } elsif ( $in{FrameSize} eq ".50" ) { $renderflags .= " -framesize H"; } # half elsif ( $in{FrameSize} eq ".33" ) { $renderflags .= " -framesize T"; } # third elsif ( $in{FrameSize} eq ".25" ) { $renderflags .= " -framesize Q"; } # quarter elsif ( $in{FrameSize} eq ".125" ) { $renderflags .= " -framesize E"; } # eight if ( $in{ImageQuality} eq "best" ) { $renderflags .= " -quality B"; } elsif ( $in{ImageQuality} eq "medium" ) { $renderflags .= " -quality M"; } elsif ( $in{ImageQuality} eq "draft" ) { $renderflags .= " -quality D"; } my $submit = <<"EOF"; title $in{JobTitle} frames $newframespec command perl $G::self -render $in{WorkspacePath} $in{OutputPath} $batchframes $batchend $in{Retries} $in{RetryBehavior} $in{MaxLogSize} $in{PrintEnvironment} $renderflags $submitoptions priority $in{Priority} EOF # ErrorWindow("$submit\n"); # DEBUGGING exit(RushSubmit($submithost, $submit, $in{JobTitle}, $in{StartIrush})); } # RENDER THE FRAME -- HANDLES "-render" # Invoked on each machine to render the frame. # Arguments passed via rush from the MAIN_Submit() section. # sub MAIN_Render() { shift(@ARGV); my %opt; $opt{WorkspacePath} = $ARGV[0]; shift(@ARGV); $opt{OutputPath} = $ARGV[0]; shift(@ARGV); $opt{BatchFrames} = $ARGV[0]; shift(@ARGV); $opt{BatchEnd} = $ARGV[0]; shift(@ARGV); $opt{Retries} = $ARGV[0]; shift(@ARGV); $opt{RetryBehavior} = $ARGV[0]; shift(@ARGV); $opt{MaxLogSize} = $ARGV[0]; shift(@ARGV); $opt{PrintEnvironment} = $ARGV[0]; shift(@ARGV); $opt{CombustionFlags} = join(" ", @ARGV); $opt{CombustionFlags} ||= ""; # HANDLE BATCH FRAMES ($opt{sfrm}, $opt{efrm}) = BatchFramesRender($ENV{RUSH_FRAME}, $opt{BatchFrames}, $opt{BatchEnd}); # PRINT WHAT WE'RE RENDERING print STDERR " WORKSPACEPATH: $opt{WorkspacePath}\n" . " OUTPUTPATH: $opt{OutputPath}\n" . " COMBUSTIONFLAGS: $opt{CombustionFlags}\n" . " BATCHFRAMES: $opt{BatchFrames} ($opt{sfrm}-$opt{efrm})\n". " RETRIES: $opt{Retries} ". "($opt{RetryBehavior} after $opt{Retries} retries)\n". " MAXLOGSIZE: $opt{MaxLogSize}\n". " PATH: $ENV{PATH}\n"; # XXX: COMBUSTION 4 HAS BUG WITH FRONTSLASH UNC PATHS FOR -file if ( $G::iswindows && $opt{OutputPath} =~ m%^//% ) { print "\nXXXX: submit-combustion: Combustion 4 '-file' has a bug with frontslash UNC paths under Windows.\n". "XXXX: submit-combustion: Working around by converting '$opt{OutputPath}' to backslash version of same.\n"; $opt{OutputPath} =~ s%/%\\%g; # //foo/bar -> \\foo\bar } # COMBUSTION COMMAND my $command = "shellrenderer -file $opt{OutputPath} ". "-start $opt{sfrm} -end $opt{efrm} ". "-startnumber $opt{sfrm} ". "$opt{CombustionFlags} $opt{WorkspacePath}"; # HANDLE TRIMMING LOG SIZE if ( $opt{MaxLogSize} > 0 || $G::logtrim_always ) { $command = "logtrim -s $opt{MaxLogSize} -c $command"; } # PRINT ENVIRONMENT? if ( $opt{PrintEnvironment} eq "on" ) { print "\n****** ENVIRONMENT: START\n"; system( ($G::iswindows) ? "set" : "printenv|sort" ); print "****** ENVIRONMENT: END\n"; } # RETRY LOOP my ($try, $exitcode, $errmsg); for ( $try=1; $try<=$opt{Retries}; $try++ ) { if ( $try > 1 ) { print "\n--- RETRY #$try of $opt{Retries}\n"; system("rush -fu -notes $ENV{RUSH_FRAME}:". "\"retry#$try of $opt{Retries}\""); sleep(10); } print "\nExecuting: $command\n"; $exitcode = RunCommand($command, \$errmsg); if ( $exitcode == 0 ) # IT WORKED? DONE { print STDERR "--- COMBUSTION SUCCEEDS: EXITCODE=$exitcode\n"; exit(0); } elsif ( $exitcode > 0 && $exitcode < 128 ) # NON-ZERO EXIT { print STDERR "--- COMBUSTION FAILED: EXITCODE=$exitcode\n"; } else # CMDFAIL/SEGFAULT/SIGNAL { print STDERR "--- $errmsg\n"; } } if ( $opt{RetryBehavior} eq "AddNever+Requeue" ) # REQUEUE/FAIL { print "--- FAILED: [$ENV{RUSH_HOSTNAME}] AddNever+Requeue\n"; system("rush -fu -an $ENV{RUSH_HOSTNAME}"); # NEVERHOST exit(2); # REQUEUE } print "--- COMBUSTION FAILED\n"; exit(1); } ### ### MAIN ### { # Silence 'variable used once' warnings $G::progname .= ""; $G::self .= ""; $G::title .= ""; $G::iswindows = $G::iswindows; $G::ismac = $G::ismac; $G::islinux = $G::islinux; $G::isirix = $G::isirix; # PARSE COMMAND LINE if ( ! defined ( $ARGV[0] ) ) { MAIN_Input(); } elsif ( $ARGV[0] eq "-submit" ) { MAIN_Submit(); } elsif ( $ARGV[0] eq "-render" ) { MAIN_Render(); } elsif ( $ARGV[0] eq "-defaults" ) { MAIN_Defaults(); } else { ErrorWindow("'$ARGV[0]': unknown argument"); exit(1); } exit(0); # just in case }