// Task.cxx #include "dial_task/Task.h" #include #include #include #include #include "dataset_util/mkdir.h" #include "dataset_util/getcwd.h" #include "dataset_util/FileName.h" #include "dataset_util/FileDirectory.h" #include "dataset_util/WorkingDirectory.h" #include "dataset_util/XmlElement.h" #include "dataset_util/DtdRegistry.h" #include "dataset_id/SimpleUniqueIdGenerator.h" #include "dataset_credential/GssCredentialManager.h" using std::string; using std::vector; using std::ostream; using std::cout; using std::cerr; using std::endl; using std::auto_ptr; using dset::GssCredentialManager; using dial::TaskId; using dial::Task; typedef Task::Name Name; typedef Task::NameList NameList; typedef Task::Time Time; typedef vector DirectoryList; typedef FileDirectory::FileList FileList; //********************************************************************** // Local definitions. //********************************************************************** namespace { // Register the DTD. DtdRegistry::Status ISTAT = DtdRegistry::register_dtd("dial"); // Include dataset DTD in dial DTD. DtdRegistry::Status ISREG = DtdRegistry::instance("dial").add_dtd("dataset"); //********************************************************************** // Fetch all regular files in a directory tree. int treefiles(string dir, NameList& names, bool allow_unreadable =false, bool allow_irregular =false) { // Loop over files. DirectoryList dirs; dirs.push_back(FileDirectory(dir)); for ( DirectoryList::size_type idir=0; idir!=dirs.size(); ++idir ) { const FileDirectory& dir = dirs[idir]; const FileList& dirfiles = dir.files(); // Loop over files. for ( FileList::const_iterator ifil=dirfiles.begin(); ifil!=dirfiles.end(); ++ifil ) { const FileStatus fstat = *ifil; if ( ! fstat.is_directory() ) { if ( !fstat.is_regular() && !allow_irregular) { cerr << "Found irregular file:" << endl; cerr << " " << fstat.name(); return 2; } if ( !fstat.is_readable() && !allow_unreadable ) { cerr << "Found unreadable file:" << endl; cerr << " " << fstat.name(); return 3; } string name = fstat.name(); if ( name.substr(0,2) == "./" ) { name = name.substr(2); } names.push_back(name); } } // Append subdirectories to directory list. dirs.insert(dirs.end(), dir.subdirs().begin(), dir.subdirs().end()); } return 0; } //********************************************************************** } // end unnamed namespace //********************************************************************** // Member functions. //********************************************************************** // DTD. // // Items flagged 1.20-1.30 were added between versions 1.20 and 1.30 // and are temporarily left IMPLIED to allow backward compatibility. const Text& Task::dtd() { static Text txt; if ( txt.size() == 0 ) { txt.append(""); txt.append(""); } return txt; } //********************************************************************** // Return the ID generator. UniqueIdGenerator& Task::generator() { static UniqueIdGenerator* pgen = 0; if ( pgen == 0 ) { pgen = UniqueIdGenerator::find_generator(Task::id_context()); if ( pgen == 0 ) { pgen = new SimpleUniqueIdGenerator; } } assert( pgen != 0 ); return *pgen; } //********************************************************************** // Test instance. const Task& Task::test_instance() { static bool first = true; static Task testtsk; if ( first ) { TextList txts; Text tpar("myparams.dat"); tpar.append("# Runtime parameters"); tpar.append("pTmin = 0.40"); tpar.append("etamax = 3.50"); txts.push_back(tpar); Text tcod("mycode.cxx"); tcod.append("// mycode.cxx"); tcod.append(""); tcod.append("int main() {"); tcod.append(" return 123;"); tcod.append("}"); txts.push_back(tcod); testtsk = Task(txts); first = false; } return testtsk; } //********************************************************************** // Constructors, assignment and destructor. //********************************************************************** // Default constructor. Task::Task() : m_create_time(time(0)) { } //********************************************************************** // Constructor from filenames. Task::Task(const NameList& innames, Name dir) : m_status(0), m_id(generator().next()), m_owner(GssCredentialManager::owner()), m_create_time(time(0)) { // Invalidate if ID generation failed. if ( ! m_id.is_valid() ) { m_status = 10; m_id = TaskId(); m_emsg = "ID generation failed"; return; } // Check current directory. WorkingDirectory wd; if ( ! wd.is_valid() ) { m_status = 17; m_emsg = "Unable to access working directory"; return; } // Change to the specified directory. if ( dir.size() ) { wd.cd(dir); if ( wd.size() != 2 ) { m_status = 18; m_emsg = "Unable to change to requested directory " + dir; return; } } // Loop over filenames and create text objects. for ( NameList::const_iterator inam=innames.begin(); inam!=innames.end(); ++inam ) { Text::Name name = *inam; // Make sure name is not already used. if ( find(files().begin(), files().end(), name) != files().end() ) { m_status = 11; m_emsg = "Duplicate file name: " + name; break; } // Make sure the filename is relative. if ( ! FileName(name).is_relative() ) { m_status = 12; m_emsg = "File name is not relative: " + name; break; } // Create text. Text txt(name); // Make sure text is not empty. if ( txt.size() == 0 ) { m_status = 13; m_emsg = "File is empty: " + txt.name(); break; } assert( txt.name() == name ); m_names.push_back(name); m_texts.push_back(txt); } // Return to the original working directory. } //********************************************************************** // Constructor from filename string. Task::Task(string innames, Name dir) : m_status(0), m_id(generator().next()), m_owner(GssCredentialManager::owner()), m_create_time(time(0)) { // Invalidate if ID generation failed. if ( ! m_id.is_valid() ) { m_status = 10; m_id = TaskId(); m_emsg = "ID generation failed"; return; } // Check current directory. WorkingDirectory wd; if ( ! wd.is_valid() ) { m_status = 17; m_emsg = "Unable to access working directory"; return; } // Change to the specified directory. if ( dir.size() ) { wd.cd(dir); if ( wd.size() != 2 ) { m_emsg = "Unable to change to requested directory " + dir; m_status = 18; return; } } // Loop over filenames and create text objects. NameList names; if ( innames == "*" ) { int nstat = treefiles(".", names); if ( nstat != 0 ) { m_status = 50 + nstat; m_emsg = "Unable to extract files from directory " + getcwd(); return; } sort(names.begin(), names.end()); } else { names = Text::split(innames); } for ( NameList::const_iterator inam=names.begin(); inam!=names.end(); ++inam ) { Text::Name name = *inam; // Make sure name is not already used. if ( find(files().begin(), files().end(), name) != files().end() ) { m_status = 11; m_emsg = "Duplicate file name: " + name; break; } // Make sure the filename is relative. if ( ! FileName(name).is_relative() ) { m_status = 12; m_emsg = "File name is not relative: " + name; break; } // Create text. Text txt(name); // Make sure text is not empty. if ( txt.size() == 0 ) { m_status = 13; m_emsg = "File is empty: " + txt.name(); break; } assert( txt.name() == name ); m_names.push_back(name); m_texts.push_back(txt); } // Return to the original working directory. } //********************************************************************** // Constructor from text objects. Task::Task(const TextList& intexts) : m_status(0), m_id(generator().next()), m_owner(GssCredentialManager::owner()), m_create_time(time(0)) { // Invalidate if ID generation failed. if ( ! m_id.is_valid() ) { m_id = TaskId(); m_emsg = "ID generation failed"; return; } // Loop over text objects. for ( TextList::const_iterator itxt=intexts.begin(); itxt!=intexts.end(); ++itxt ) { const Text& txt = *itxt; Text::Name name = txt.name(); // Make sure name is not blank. if ( name.size() == 0 ) { m_status = 21; m_emsg = "File name is missing"; break; } // Make sure name is not already used. if ( find(m_names.begin(), m_names.end(), name) != m_names.end() ) { m_status = 22; m_emsg = "Duplicate file name: " + name; break; } // Make sure the filename is relative. if ( ! FileName(name).is_relative() ) { m_emsg = "File name is not relative: " + name; m_status = 23; break; } // Make sure text is not empty. if ( txt.size() == 0 ) { m_status = 24; m_emsg = "File is empty: " + txt.name(); break; } assert( txt.name() == name ); m_names.push_back(name); m_texts.push_back(txt); } } //********************************************************************** // XML constructor. Task::Task(const XmlElement& ele) : m_status(0), m_create_time(0) { // Check the input. if ( ele.name() != xml_name() ) { m_emsg = "XML name mismatch: " + ele.name() + " " + xml_name(); return; } // Check XML for ID. if ( ! ele.has_attribute("id") ) { m_emsg = "XML attribute id is missing"; return; } // Fetch XML for text objexts. const XmlElement::ElementList& xtxts = ele.children(Text::xml_name()); for ( XmlElement::ElementList::const_iterator iele=xtxts.begin(); iele!=xtxts.end(); ++iele ) { Text txt(**iele); m_names.push_back(txt.name()); m_texts.push_back(txt); } // Fill the data. m_id = TaskId(ele.attribute("id")); if ( ele.has_attribute("owner") ) { m_owner = ele.attribute("owner"); } else { m_owner = "unknown"; } m_create_time = ele.attribute_as_int("create_time"); // Check this. if ( ! is_valid() ) { m_id = TaskId(); } } //********************************************************************** // Copy constructor. Task::Task(const Task& rhs) : m_status(rhs.m_status), m_id(rhs.m_id), m_owner(rhs.m_owner), m_create_time(rhs.m_create_time), m_names(rhs.m_names), m_texts(rhs.m_texts), m_emsg(rhs.m_emsg) { } //********************************************************************** // Assignment. Task& Task::operator=(const Task& rhs) { if ( &rhs == this ) return *this; m_status = rhs.m_status; m_id = rhs.m_id; m_owner = rhs.m_owner; m_create_time = rhs.m_create_time; m_names = rhs.m_names; m_texts = rhs.m_texts; m_emsg = rhs.m_emsg; return *this; } //********************************************************************** // Destructor. Task::~Task() { } //********************************************************************** // Other member functions. //********************************************************************** // Validity. bool Task::is_valid() const { m_emsg = ""; return status()==0 && id().is_valid(); } //********************************************************************** // Identifier. TaskId Task::id() const { m_emsg = ""; return m_id; } //********************************************************************** // Owner. Name Task::owner() const { m_emsg = ""; return m_owner; } //********************************************************************** // Return the create time. Time Task::create_time() const { m_emsg = ""; return m_create_time; } //********************************************************************** // File string. string Task::file_string() const { m_emsg = ""; if ( ! is_valid() ) { m_emsg = "Invalid task"; return ""; } string snames; for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { const Text& txt = *itxt; Name fname = txt.name(); if ( itxt != texts().begin() ) { snames += " "; } snames += fname; } return snames; } //********************************************************************** // Has. bool Task::has(Name name) const { for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { const Text& txt = *itxt; if ( txt.name() == name ) return true; } return false; } //********************************************************************** // Return a text. const Text& Task::text(Name name) const { m_emsg = ""; for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { const Text& txt = *itxt; if ( txt.name() == name ) { return txt; } } static Text empty; m_emsg = ""; return empty; } //********************************************************************** // Write files. int Task::write_files(Name indir, bool create, bool overwrite) const { m_emsg = ""; m_odir = ""; // Check current directory. WorkingDirectory wd; if ( ! wd.is_valid() ) { m_emsg = "Unable to access current working directory"; return 1; } // Create directory name. string dir = indir; if ( ! dir.size() ) { dir = "task_"; dir += id().to_string(); } // If create is set, create new directory. FileStatus dstat(dir); if ( create ) { if ( dstat.exists() ) { m_emsg = "New directory already exists: " + dir; return 2; } int mstat = mkfulldir(dir); if ( mstat != 0 ) { m_emsg = "Unable to create new directory: " + dir; return 3; } dstat.update(); } // Change directory. int cstat = wd.cd(dir); if ( cstat != 0 ) { m_emsg = "Unable to change to directory: " + dir; return 4; } // Check if any files are existing. for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { const Text& txt = *itxt; Name fname = txt.name(); FileStatus fstat(fname); if ( fstat.exists() ) { if ( overwrite ) { unlink(fname.c_str()); } fstat.update(); if ( fstat.exists() ) { m_emsg = "File already exists: " + fstat.name(); return 5; } } } // Write files. int stat = 0; for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { stat += itxt->write(); } if ( stat != 0 ) { m_emsg = "Unable to write file"; return 100 + stat; } m_odir = dir; return 0; } //********************************************************************** // Help. int Task::help() const { Text treadme = text("readme.txt"); if ( treadme.size() == 0 ) return 1; std::cout << treadme << endl; return 0; } //********************************************************************** // Write to XML. const XmlElement* Task::xml(bool global_id) const { m_emsg = ""; // Check validity. if ( ! is_valid() ) return 0; // Check ID. if ( global_id && ! id().is_global() ) { cerr << "Task::xml: ID is not global" << endl; m_emsg = "ID is not global"; return 0; } // Require owner. if ( owner().size() == 0 ) { cerr << "Task::xml: Owner is not defined" << endl; m_emsg = "Owner is not defined"; return 0; } // Require create time unless owner is unknown. if ( create_time() == 0 && owner() != "unknown" ) { cerr << "Task::xml: Create time is not defined" << endl; m_emsg = "Create time is not defined"; return 0; } // Create top XML elment. auto_ptr pele(new XmlElement(xml_name())); // Add ID. pele->add_attribute("id", id().to_string()); // Add owner. pele->add_attribute("owner", owner()); // Add create time. pele->add_attribute_as_int("create_time", create_time()); // Add text files. for ( TextList::const_iterator itxt=texts().begin(); itxt!=texts().end(); ++itxt ) { XmlElement* pele_txt = itxt->xml(); if ( pele_txt == 0 ) { cerr << "Task::xml: Unable to write extract file: " << itxt->name(); m_emsg = "Unable to write extract file: " + itxt->name(); return 0; } pele->add_child(pele_txt); } // Return the XML. return pele.release(); } //********************************************************************** // Display. void Task::display() const { m_emsg = ""; std::cout << *this << std::endl; } //********************************************************************** // Error message. string Task::error_message() const { return m_emsg; } //********************************************************************** // Output directory. string Task::output_directory() const { return m_odir; } //********************************************************************** // Web page. Text Task::web_page(string baseurl, string entry) const { Text wp; wp.append(""); // Display task. if ( entry == "" ) { string header = "Task " + id().to_string(); wp.append("" + header + ""); wp.append("

" + header + "

"); wp.append("Owner: " + owner()); time_t time = create_time(); string stime = asctime(gmtime(&time)); wp.append("
Created: " + stime + " UTC"); wp.append("

Description:"); Text trm = text("readme.txt"); if ( trm.size() ) { wp.append("
");
      wp.append(trm);
      wp.append("
"); } else { wp.append("Task does not have readme.txt"); wp.append("

"); } wp.append("Files:"); string hpref = "
  " + *inam + ""); } // Display a file. } else if ( entry.size()>5 && entry.substr(0,5) == "file=" ) { string file = entry.substr(5); string header = "Task " + id().to_string() + " file " + file; wp.append("" + header + ""); //return text(file); wp.append("

");
    wp.append(text(file));
    wp.append("
"); } else { wp.append("Task::web_page: Invalid entry " + entry); } wp.append(""); return wp; } //********************************************************************** //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const Task& rhs) { if ( ! rhs.is_valid() ) { lhs << "invalid task"; return lhs; } lhs << "Task "; lhs << rhs.id().to_string(); if ( rhs.owner().size() ) { lhs << "\n Owner: " << rhs.owner(); } Time tim = rhs.create_time(); if ( tim > 0 ) { char ctim[256]; const char* fmt = "%Y %B %d %X"; strftime(ctim, 256, fmt, localtime(&tim)); lhs << "\n Create time: " << ctim; } if ( rhs.files().size() == 1 ) { lhs << "\n Holds has 1 file: " << rhs.files().front(); } else { lhs << "\n Holds " << rhs.files().size() << " files"; if ( rhs.files().size() != 0 ) lhs << ":"; for ( NameList::const_iterator inam=rhs.files().begin(); inam!=rhs.files().end(); ++inam ) { lhs << "\n " << *inam; } } return lhs; } //**********************************************************************