/** Get the command-line options we want to preserve from the .condor.sub file we're overwriting, and plug them into the shallowOpts structure. Note that it's *not* an error for the .condor.sub file to not exist. @param shallowOpts: the condor_submit_dag shallow options @return 0 if successful, 1 if failed */ int getOldSubmitFlags(SubmitDagShallowOptions &shallowOpts) { // It's not an error for the submit file to not exist. if ( fileExists( shallowOpts.strSubFile ) ) { MultiLogFiles::FileReader reader; MyString error = reader.Open( shallowOpts.strSubFile ); if ( error != "" ) { fprintf( stderr, "Error reading submit file: %s\n", error.Value() ); return 1; } MyString subLine; while ( reader.NextLogicalLine( subLine ) ) { StringList tokens( subLine.Value(), " \t" ); tokens.rewind(); const char *first = tokens.next(); if ( first && !strcasecmp( first, "arguments" ) ) { if ( parseArgumentsLine( subLine, shallowOpts ) != 0 ) { return 1; } } } reader.Close(); } return 0; }
//------------------------------------------------------------------------- bool GetConfigAndAttrs( /* const */ StringList &dagFiles, bool useDagDir, MyString &configFile, StringList &attrLines, MyString &errMsg ) { bool result = true; // Note: destructor will change back to original directory. TmpDir dagDir; dagFiles.rewind(); char *dagFile; while ( (dagFile = dagFiles.next()) != NULL ) { // // Change to the DAG file's directory if necessary, and // get the filename we need to use for it from that directory. // const char * newDagFile; if ( useDagDir ) { MyString tmpErrMsg; if ( !dagDir.Cd2TmpDirFile( dagFile, tmpErrMsg ) ) { AppendError( errMsg, MyString("Unable to change to DAG directory ") + tmpErrMsg ); return false; } newDagFile = condor_basename( dagFile ); } else { newDagFile = dagFile; } StringList configFiles; // Note: destructor will close file. MultiLogFiles::FileReader reader; errMsg = reader.Open( newDagFile ); if ( errMsg != "" ) { return false; } MyString logicalLine; while ( reader.NextLogicalLine( logicalLine ) ) { if ( logicalLine != "" ) { // Note: StringList constructor removes leading // whitespace from lines. StringList tokens( logicalLine.Value(), " \t" ); tokens.rewind(); const char *firstToken = tokens.next(); if ( !strcasecmp( firstToken, "config" ) ) { // Get the value. const char *newValue = tokens.next(); if ( !newValue || !strcmp( newValue, "" ) ) { AppendError( errMsg, "Improperly-formatted " "file: value missing after keyword " "CONFIG" ); result = false; } else { // Add the value we just found to the config // files list (if it's not already in the // list -- we don't want duplicates). configFiles.rewind(); char *existingValue; bool alreadyInList = false; while ( ( existingValue = configFiles.next() ) ) { if ( !strcmp( existingValue, newValue ) ) { alreadyInList = true; } } if ( !alreadyInList ) { // Note: append copies the string here. configFiles.append( newValue ); } } //some DAG commands are needed for condor_submit_dag, too... } else if ( !strcasecmp( firstToken, "SET_JOB_ATTR" ) ) { // Strip of DAGMan-specific command name; the // rest we pass to the submit file. logicalLine.replaceString( "SET_JOB_ATTR", "" ); logicalLine.trim(); if ( logicalLine == "" ) { AppendError( errMsg, "Improperly-formatted " "file: value missing after keyword " "SET_JOB_ATTR" ); result = false; } else { attrLines.append( logicalLine.Value() ); } } } } reader.Close(); // // Check the specified config file(s) against whatever we // currently have, setting the config file if it hasn't // been set yet, flagging an error if config files conflict. // configFiles.rewind(); char * cfgFile; while ( (cfgFile = configFiles.next()) ) { MyString cfgFileMS = cfgFile; MyString tmpErrMsg; if ( MakePathAbsolute( cfgFileMS, tmpErrMsg ) ) { if ( configFile == "" ) { configFile = cfgFileMS; } else if ( configFile != cfgFileMS ) { AppendError( errMsg, MyString("Conflicting DAGMan ") + "config files specified: " + configFile + " and " + cfgFileMS ); result = false; } } else { AppendError( errMsg, tmpErrMsg ); result = false; } } // // Go back to our original directory. // MyString tmpErrMsg; if ( !dagDir.Cd2MainDir( tmpErrMsg ) ) { AppendError( errMsg, MyString("Unable to change to original directory ") + tmpErrMsg ); result = false; } } return result; }
/** Recursively call condor_submit_dag on nested DAGs. @param deepOpts: the condor_submit_dag deep options @return 0 if successful, 1 if failed */ int doRecursionNew( SubmitDagDeepOptions &deepOpts, SubmitDagShallowOptions &shallowOpts ) { int result = 0; shallowOpts.dagFiles.rewind(); // Go through all DAG files specified on the command line... StringList submitFiles; const char *dagFile; while ( (dagFile = shallowOpts.dagFiles.next()) ) { // Get logical lines from this DAG file. MultiLogFiles::FileReader reader; MyString errMsg = reader.Open( dagFile ); if ( errMsg != "" ) { fprintf( stderr, "Error reading DAG file: %s\n", errMsg.Value() ); return 1; } // Find and parse JOB and SUBDAG lines. MyString dagLine; while ( reader.NextLogicalLine( dagLine ) ) { StringList tokens( dagLine.Value(), " \t" ); tokens.rewind(); const char *first = tokens.next(); if ( first && !strcasecmp( first, "JOB" ) ) { // Get the submit file and directory from the DAG // file line. const char *subFile; const char *directory; if ( parseJobOrDagLine( dagLine.Value(), tokens, "submit", subFile, directory ) != 0 ) { return 1; } // Now figure out whether JOB line is a nested DAG. MyString submitFile( subFile ); // If submit file ends in ".condor.sub", we assume it // refers to a sub-DAG. int start = submitFile.find( DAG_SUBMIT_FILE_SUFFIX ); if ( start >= 0 && start + (int)strlen( DAG_SUBMIT_FILE_SUFFIX) == submitFile.Length() ) { // Change submit file name to DAG file name. submitFile.replaceString( DAG_SUBMIT_FILE_SUFFIX, "" ); // Now run condor_submit_dag on the DAG file. if ( runSubmitDag( deepOpts, submitFile.Value(), directory, false ) != 0 ) { result = 1; } } } else if ( first && !strcasecmp( first, "SUBDAG" ) ) { const char *inlineOrExt = tokens.next(); if ( strcasecmp( inlineOrExt, "EXTERNAL" ) ) { fprintf( stderr, "ERROR: only SUBDAG EXTERNAL is supported " "at this time (line: <%s>)\n", dagLine.Value() ); return 1; } // Get the nested DAG file and directory from the DAG // file line. const char *nestedDagFile; const char *directory; if ( parseJobOrDagLine( dagLine.Value(), tokens, "DAG", nestedDagFile, directory ) != 0 ) { return 1; } // Now run condor_submit_dag on the DAG file. if ( runSubmitDag( deepOpts, nestedDagFile, directory, false ) != 0 ) { result = 1; } } } reader.Close(); } return result; }