void Globber::UpdateIndex(const vector<ohfileinfo>& files, const path& indexpath, const opParameters& p ) { bool bForce = p.Force; if( !exists(indexpath) ) bForce = true; //we need to determine if //iterate over all files bool bNewer = false; if(!bForce) { time_t indextime = last_write_time(indexpath); time_t opcpptime = opPlatform::GetOpCppTimeStamp(); for(size_t i = 0; i < files.size(); i++) { time_t ohtime = last_write_time(files[i].ohfilepath); time_t generatedtime = bheader? last_write_time(files[i].oohfilepath): last_write_time(files[i].ocppfilepath); //the index condition is the important one //the header condition is not so important - that just says that an oh file wasn't build (oops) if( indextime < opcpptime ) { if(p.Verbose) Log(opPlatform::GetOpCppExecutableName() + " newer than index, forcing glob"); bNewer = true; break; } if( generatedtime > ohtime && generatedtime > indextime) { bNewer = true; break; } } } string indexname = bheader?"oohindex":"ocppindex"; if(bNewer || bForce) { if(p.Verbose) Log(string("Globber: ") + indexname + " out of date, rebuilding..."); WriteIndex<bheader>(files,indexpath,p); } else { if(p.Verbose) Log(string("Globber: ") + indexname + " up to date, skipping..."); } }
void Rule::resolve() { if (isResolved_) return; bool outOfDate = !exists(target_); auto ts = outOfDate ? 0 : last_write_time(target_); for (auto &d: dependencies_) { d->resolve(); outOfDate = outOfDate || !exists(d->target_) || (ts < last_write_time(d->target_)); } if (outOfDate) internalResolve(); isResolved_ = true; }
// TODO: dependencies does track file paths, only names - this doesn't matter // really. bool opDriver::CheckDependencies() { const opParameters& p = opParameters::Get(); bool bResult = false; int size = p.Depend.size(); for (int i = 0; i < size; i++) { opString filestring = p.Depend[i]; path filepath = filestring.GetString(); if (exists(filepath)) { opString targetfile = filepath.leaf().c_str(); targetfile += ".target"; path targetpath = p.GeneratedDirectory.GetString() / targetfile.GetString(); // if it doesn't exist we need to create it if (!exists(targetpath)) { create_directories(p.GeneratedDirectory.GetString()); // just create a new empty target file boost::filesystem::ofstream target(targetpath); target << "target file used for opC++ -dependencies"; bResult = true; continue; } // now check for the time time_t filetime = last_write_time(filepath); time_t targettime = last_write_time(targetpath); if (filetime > targettime) { // just create a new empty target file boost::filesystem::ofstream target(targetpath); target << "target file used for opC++ -dependencies"; bResult = true; continue; } } } return bResult; }
int64_t file_mod_time(const std::string& fname) { path p(fname); if(is_regular_file(p)) { return static_cast<int64_t>(last_write_time(p)); } else { return 0; } }
void SFTWorker::finishFile() { m_hFh.close(); std::string file = m_pCurFile->getFullPath(); gcString str("{0}", m_pCurFile->getTimeStamp()); try { ptime t(from_iso_string(str)); bfs::path spath(file); tm pt_tm = to_tm(t); last_write_time(spath, mktime(&pt_tm)); } catch (...) { Warning(gcString("Failed to change {0} time stamp to {1}.\n", m_pCurFile->getName(), str)); } safe_delete(m_pBzs); std::string hash = "Failed to generate hash"; #ifdef NIX //struct stat s; bool isWinExe = false; if (file.size() > 4) { std::string lastFour(file.end() - 4, file.end()); std::transform(lastFour.begin(), lastFour.end(), lastFour.begin(), ::toupper); if (lastFour == ".EXE") isWinExe = true; } //( && stat(file.c_str(), &s) == 0) bool isExecutable = HasAnyFlags(m_pCurFile->getFlags(), MCFCore::MCFFileI::FLAG_XECUTABLE); if (isExecutable || isWinExe) chmod(file.c_str(), (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)); #endif if (m_pCurFile->isZeroSize() || m_pCurFile->hashCheckFile(&hash)) { m_pCT->endTask(m_uiId, BaseMCFThread::SF_STATUS_COMPLETE); } else { Warning(gcString("Hash check failed for file [{0}]: Cur: {1} != Should: {2}\n", m_pCurFile->getName(), hash, m_pCurFile->getCsum())); m_pCT->endTask(m_uiId, BaseMCFThread::SF_STATUS_HASHMISSMATCH); } }
bool opDriver::CodeCurrent() { // foreach dialect we have... // and all dependencies, are we up to date? // are we up to date? opSet<path>::iterator it = OhFiles.begin(); opSet<path>::iterator end = OhFiles.end(); time_t opcpptime = opPlatform::GetOpCppTimeStamp(); while (it != end) { const path& ohfilepath = *it; // get the output path opString filestring = GetOutputPath(opParameters::Get(), ohfilepath); path oohfilepath = (filestring + ".ooh").GetString(); path ocppfilepath = (filestring + ".ocpp").GetString(); if (!exists(oohfilepath)) return false; if (!exists(ocppfilepath)) return false; time_t ohtime = last_write_time(ohfilepath); time_t oohtime = last_write_time(oohfilepath); time_t ocpptime = last_write_time(ocppfilepath); if (ohtime > oohtime || ohtime > ocpptime || opcpptime > oohtime || opcpptime > ocpptime) return false; // now check dependencies FileNode file; file.LoadDependencies(filestring + ".depend"); if (file.IsDependencyNewer(oohtime)) return false; ++it; } return true; }
int chkAndResetRule( rsComm_t *rsComm ) { // char *configDir; // char rulesFileName[MAX_NAME_LEN]; int status = 0; uint mtime; // configDir = getConfigDir(); // snprintf( rulesFileName, MAX_NAME_LEN, "%s/reConfigs/core.re", // configDir ); std::string re_full_path; irods::error ret = irods::get_full_path_for_config_file( "core.re", re_full_path ); if ( !ret.ok() ) { irods::log( PASS( ret ) ); return ret.code(); } path p( re_full_path ); if ( !exists( p ) ) { status = UNIX_FILE_STAT_ERR - errno; rodsLog( LOG_ERROR, "chkAndResetRule: unable to read rule config file %s, status = %d", re_full_path.c_str(), status ); return ( status ); } mtime = ( uint ) last_write_time( p ); if ( CoreIrbTimeStamp == 0 ) { /* first time */ CoreIrbTimeStamp = mtime; return ( 0 ); } if ( mtime > CoreIrbTimeStamp ) { /* file has been changed */ rodsLog( LOG_NOTICE, "chkAndResetRule: reconf file %s has been changed. re-initializing", re_full_path.c_str() ); CoreIrbTimeStamp = mtime; clearCoreRule(); /* The shared memory cache may have already been updated, do not force reload */ status = initRuleEngine( RULE_ENGINE_TRY_CACHE, NULL, reRuleStr, reFuncMapStr, reVariableMapStr ); if ( status < 0 ) { rodsLog( LOG_ERROR, "chkAndResetRule: initRuleEngine error, status = %d", status ); } } return status; }
time_t opDriver::GetDialectTimestamp(const opParameters& p) { // find the maximum timestamp on the dialects (input dialects, since we // output every time) time_t maxtime = 0; for (int i = 0; i < p.Dialects.size(); i++) { // TODO - use generated dialects instead.. path filepath = p.Dialects[i].GetString(); // doh file exists? if (exists(filepath)) { maxtime = max(last_write_time(filepath), maxtime); } } return maxtime; }
time_t opDriver::GetGeneratedDialectTimestamp(const opParameters& p) { // find the maximum timestamp on the dialects (input dialects, since we // output every time) time_t maxtime = 0; for (int i = 0; i < p.Dialects.size(); i++) { opString filestring = GetOutputPath(p, p.Dialects[i].GetString()); path filepath = (filestring + ".ooh").GetString(); // doh file exists? if (exists(filepath)) { maxtime = max(last_write_time(filepath), maxtime); } } return maxtime; }
/** \param path the path to monitor * \param callback the callback to notify if the path changes * \param call_now will invoke the callback now */ void insert(const std::string & path, const callback_t & callback, bool call_now = false ) { boost::mutex::scoped_lock lock(m_file_mutex); m_file_callback[path] = callback; boost::filesystem::path p(path); std::time_t lw = last_write_time(p); if (lw != 0) { m_file_modified[path] = std::make_pair(lw, lw); if ( call_now ) callback(CHANGED, path); } else { m_file_modified.erase(path); if ( call_now ) callback(DELETED, path); } }
file_cache::file::file(const std::string& name, bool read_from_disk) { path p(name); if (exists(p)) { if (is_regular_file(p)) { m_size = file_size(p); m_time = last_write_time(p); if (read_from_disk) { std::ifstream is(name, std::ifstream::binary); if (is) { m_data.reserve(m_size); std::copy(std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>(), std::back_inserter(m_data)); m_good = true; } else { log_err("can't open file " << name); } } } else { log_err(name << " is no file"); } } else { log_err(name << " does not exists"); } }
int bmx_filesystem_filetime(BBString * path) { boost::filesystem::path p(bbStringToPath(path)); return last_write_time(p); }
/** * scan * * starts from the given node and iterates through all * child directories and builds vectors of all file * and directory nodes in the FS * * @param pnode pointer to DirInfo node to scan */ bool FileSystem::scan(DirInfo* pnode) { debugPrint("Scanning Node: " + pnode->getPath()); // Check if given path exists if ( !boost::filesystem::exists( pnode->getPath() ) ) { cout << pnode->getPath() << " doesn't exist" << endl; return false; } if (pnode->isHidden()) { return false; } // Create a boost directory iterator boost::filesystem::directory_iterator end_itr; try { for ( boost::filesystem::directory_iterator itr( pnode->getPath() ); itr != end_itr; ++itr ) { // Is iterated object a directory if ( is_directory(itr->status()) ) { DirInfo* dir = new DirInfo(itr->path().filename().string(), pnode); // Keeps track of node to deconstruct pointer allNodes.push_back(dir); // All directories list (for quick dir operations) allDirs.push_back(dir); // Add this node to it's parent children list pnode->addChild(dir); // Create a boost path object to extract fs info boost::filesystem::path p(dir->getPath()); dir->setModifyTime( last_write_time(p) ); dir->isDir(true); // Recursively scan dirs scan(dir); // directory size is only available after all dir and files add their // sizes to their parent dirs to be added here pnode->addSize(dir->getSize()); // If iterated object is not directory, then it must be a file } else { FileInfo* file = new FileInfo(itr->path().filename().string(), pnode); // Keeps track of node to deconstruct pointer allNodes.push_back(file); // All files list (for quick file operations) allFiles.push_back(file); // Add this node to it's parent children list pnode->addChild(file); // Create a boost path object to extract fs info boost::filesystem::path p(file->getPath()); try { file->setSize( file_size(p) ); } catch (boost::filesystem::filesystem_error err) { file->setSize( 0 ); } try { file->setModifyTime( last_write_time(p) ); } catch (boost::filesystem::filesystem_error err) { file->setModifyTime( 0 ); } // Update parent size file->getParent()->addSize(file->getSize()); } } } catch (boost::filesystem::filesystem_error) { cout << "Cannot open file: " << pnode->getPath() << ". Permission denied!" << endl; } return true; }
bool opDriver::DialectModeFile(const opParameters& p, const path& filename) { double totaltimestart = opTimer::GetTimeSeconds(); opError::Clear(); // output compiling -file- to std out if (!p.Silent) { Log(opString("Reading dialect ") + filename.string() + " ..."); } // load the oh file, it will be tracked elsewhere DialectFileNode* filenode = FileNode::Load<DialectFileNode>( filename.string(), opScanner::SM_DialectMode); // filenode should be non-null even if there were errors assert(filenode); if (opError::HasErrors()) { if (p.PrintTree) filenode->PrintTree(filename.string()); opError::Print(); return false; } // check for file not found error // if (filenode->FileNotFoundError()) // { // opError::Print(); // // //this is ambiguous doh! // //TODO: fix this to be specific // Log(opString("Cannot open input file \"") + filename.string() + // "\"!"); return false; // } // // //check for scanner error // if(filenode->ScanError()) // { // opError::Print(); // // if (p.Verbose) // { // Log("Compilation failed!"); // Log(""); // } // // return false; // } // // //check for parser errors // if(filenode->AnyErrors()) // { // //print the tree (failure) // if (p.PrintTree) // filenode->PrintTree(filename.string()); // // opError::Print(); // // if (p.Verbose) // { // Log("Compilation failed!"); // Log(""); // } // // return false; // } opString spath = GetOutputPath(p, filename); path oohpath = (spath + ".ooh").GetString(); path ocpppath = (spath + ".ocpp").GetString(); path outputpath = oohpath.branch_path(); if (!exists(outputpath)) create_directories(outputpath); // handle dialect writing // we always want to read dialects though. bool bwrite = true; if (!p.Force) { // we want to rebuild upon upgrades / new builds if (exists(oohpath) && exists(filename)) { time_t oohtime = last_write_time(oohpath); time_t opcpptime = opPlatform::GetOpCppTimeStamp(); time_t dohtime = GetDialectTimestamp(p); filenode->LoadDependencies(spath + ".depend"); bool bNewDepend = filenode->IsDependencyNewer(oohtime); if (bNewDepend) { if (p.Verbose) { Log("Included dialect newer than generated dialect file, " "forcing recompile ..."); Log(""); } } else if (oohtime < opcpptime) { if (p.Verbose) { Log(opPlatform::GetOpCppExecutableName() + " newer than generated dialect file, forcing recompile " "..."); Log(""); } } else if (oohtime <= dohtime) { if (p.Verbose) { Log("Dialect newer than generated dialect file, forcing " "recompile ..."); Log(""); } } else if (oohtime > dohtime) { if (p.Verbose) Log(filename.string() + " is up to date"); bwrite = false; } } } if (bwrite) { try { // Save dependencies file. opString dependpath = spath + ".depend"; filenode->SaveDependencies(dependpath); // open the output files for the generated code... FileWriteStream hfile(oohpath.string()); FileWriteStream sfile(ocpppath.string()); if (hfile.is_open() && sfile.is_open()) { filenode->SetFiles(oohpath.string(), ocpppath.string()); opDialectStream filestream(hfile, sfile); // add the pre-pend path (for relative #lines) filestream.SetDepths(oohpath.string()); // files are open, now print to them filenode->PrintDialectNode(filestream); filestream.Output(); } else { Log("Could not open output file(s)!"); return false; } } catch (opException::opCPP_Exception&) { } // print xml! if (p.PrintXml) { try { path xmlpath = (spath + ".xml").GetString(); // open the output files for the generated code... boost::filesystem::ofstream xfile(xmlpath); if (xfile.is_open()) { opXmlStream filestream(xfile); // files are open, now print to them filenode->PrintXml(filestream); } else { Log("Could not open output xml file!"); return false; } } catch (opException::opCPP_Exception&) { //??? ever } } } double totaltimeend = opTimer::GetTimeSeconds(); double totaltimeMs = (totaltimeend - totaltimestart) * 1000.0; // print the tree (success) if (p.PrintTree) filenode->PrintTree(filename.string()); // write the verbose compilation notice if (p.Verbose) { Log(""); Log(opString("Dialect reading successful ... took ") + totaltimeMs + " ms (" + filenode->GetScanMs() + " scan ms, " + filenode->GetParseMs() + " parse ms)"); Log(""); } return true; }
// compiles a file in normal mode bool opDriver::NormalModeFile(const opParameters& p, const path& filename) { double totaltimestart = opTimer::GetTimeSeconds(); // build the output filename strings... // fix this for ../ case (convert to string and find & replace...) opString sfile = GetOutputPath(p, filename); path oohpath = (sfile + ".ooh").GetString(); path ocpppath = (sfile + ".ocpp").GetString(); path outputpath = oohpath.branch_path(); if (!exists(outputpath)) create_directories(outputpath); // lets check the timestamp... if (!p.Force) { time_t ohtime = last_write_time(filename); // we want to rebuild upon upgrades / new builds time_t opcpptime = opPlatform::GetOpCppTimeStamp(); if (exists(oohpath) && exists(ocpppath)) { time_t oohtime = last_write_time(oohpath); time_t ocpptime = last_write_time(ocpppath); time_t dohtime = GetGeneratedDialectTimestamp(p); FileNode tempfile; tempfile.LoadDependencies(sfile + ".depend"); bool bNewDepend = tempfile.IsDependencyNewer(oohtime); if (bNewDepend) { if (p.Verbose) { Log("Included file newer than generated file, forcing " "recompile ..."); Log(""); } } // up to date if ooh newer than oh, and ooh newer than opcpp build else if (oohtime < opcpptime || ocpptime < opcpptime) { if (p.Verbose) { Log(opPlatform::GetOpCppExecutableName() + " newer than generated file, forcing recompile ..."); Log(""); } } else if (oohtime <= dohtime || ocpptime <= dohtime) { if (p.Verbose) { Log("Dialect newer than generated file, forcing recompile " "..."); Log(""); } } else if (oohtime > ohtime && ocpptime > ohtime) { if (p.Verbose) Log(filename.string() + " is up to date"); return true; } } } opError::Clear(); // output compiling -file- to std out if (!p.Silent) { Log(opString("Compiling ") + filename.string() + " ..."); } // load the oh file, it will be tracked elsewhere OPFileNode* filenode = FileNode::Load<OPFileNode>(filename.string(), opScanner::SM_NormalMode); // filenode should be non-null even if there were errors assert(filenode); if (opError::HasErrors()) { if (p.PrintTree) filenode->PrintTree(filename.string()); opError::Print(); return false; } // no errors, let's print the output files try { // Save dependencies file. opString dependpath = sfile + ".depend"; filenode->SaveDependencies(dependpath); // open the output files for the generated code... FileWriteStream hfile(oohpath.string()); FileWriteStream sfile(ocpppath.string()); if (hfile.is_open() && sfile.is_open()) { filenode->SetFiles(oohpath.string(), ocpppath.string()); opFileStream filestream(hfile, sfile); // add the pre-pend path (for relative #lines) filestream.SetDepths(oohpath.string()); // files are open, now print to them filenode->PrintNode(filestream); filestream.Output(); } else { Log("Could not open output file(s)!"); return false; } } catch (opException::opCPP_Exception&) { //??? ever } // print xml! if (p.PrintXml) { try { path xmlpath = (sfile + ".xml").GetString(); // open the output files for the generated code... boost::filesystem::ofstream xfile(xmlpath); if (xfile.is_open()) { opXmlStream filestream(xfile); // files are open, now print to them filenode->PrintXml(filestream); } else { Log("Could not open output xml file!"); return false; } } catch (opException::opCPP_Exception&) { //??? ever } } // any errors left? // shouldn't be really opError::Print(); double totaltimeend = opTimer::GetTimeSeconds(); double totaltimeMs = (totaltimeend - totaltimestart) * 1000.0; // TODO: allow PrintTree to any stream // and add support for PrintTree to file // print the AST to stdout if (p.PrintTree) filenode->PrintTree(filename.string()); // write the verbose compilation notice if (p.Verbose) { Log(""); Log(opString("Compilation successful ... took ") + totaltimeMs + " ms (" + filenode->GetScanMs() + " scan ms, " + filenode->GetParseMs() + " parse ms)"); } return true; }
int chkAndResetRule (rsComm_t *rsComm) { char *configDir; char rulesFileName[MAX_NAME_LEN]; #ifndef USE_BOOST_FS struct stat statbuf; #endif int status; ruleExecInfo_t rei; uint mtime; configDir = getConfigDir (); #ifdef RULE_ENGINE_N snprintf (rulesFileName, MAX_NAME_LEN, "%s/reConfigs/core.re", configDir); #else snprintf (rulesFileName, MAX_NAME_LEN, "%s/reConfigs/core.irb", configDir); #endif #ifdef USE_BOOST_FS path p (rulesFileName); if (!exists (p)) { #else status = stat (rulesFileName, &statbuf); if (status != 0) { #endif status = UNIX_FILE_STAT_ERR - errno; rodsLog (LOG_ERROR, "chkAndResetRule: unable to read rule config file %s, status = %d", rulesFileName, status); return (status); } #ifdef USE_BOOST_FS mtime = (uint) last_write_time (p); #else mtime = (uint) statbuf.st_mtime; #endif if (CoreIrbTimeStamp == 0) { /* first time */ CoreIrbTimeStamp = mtime; return (0); } if (mtime > CoreIrbTimeStamp) { /* file has been changed */ rodsLog (LOG_NOTICE, "chkAndResetRule: reconf file %s has been changed. re-initializing", rulesFileName); CoreIrbTimeStamp = mtime; rei.rsComm = rsComm; clearCoreRule(); #ifdef RULE_ENGINE_N /* The shared memory cache may have already been updated, do not force reload */ status = initRuleEngine(RULE_ENGINE_TRY_CACHE, NULL, reRuleStr, reFuncMapStr, reVariableMapStr); #else msiAdmClearAppRuleStruct (&rei); status = initRuleEngine(NULL, reRuleStr, reFuncMapStr, reVariableMapStr); #endif if (status < 0) { rodsLog (LOG_ERROR, "chkAndResetRule: initRuleEngine error, status = %d", status); } } return status; }
void ReflectionParser::GenerateFiles(void) { fs::path sourceRootDirectory( m_options.sourceRoot ); fs::path outputFileDirectory( m_options.outputModuleFileDirectory ); m_moduleFileHeaderTemplate = LoadTemplate( kTemplateModuleFileHeader ); if (!m_moduleFileHeaderTemplate.isValid( )) { std::stringstream error; error << "Unable to compile module file header template." << std::endl; error << m_moduleFileHeaderTemplate.errorMessage( ); throw std::exception( error.str( ).c_str( ) ); } m_moduleFileSourceTemplate = LoadTemplate( kTemplateModuleFileSource ); if (!m_moduleFileSourceTemplate.isValid( )) { std::stringstream error; error << "Unable to compile module file source template." << std::endl; error << m_moduleFileSourceTemplate.errorMessage( ); throw std::exception( error.str( ).c_str( ) ); } TemplateData moduleFilesData { TemplateData::Type::List }; fs::path metaCacheFileName = m_options.outputModuleFileDirectory; metaCacheFileName /= ".meta-cache"; auto metaCacheFileExists = exists( metaCacheFileName ); std::string moduleFileCache; for (auto &file : m_moduleFiles) { fs::path filePath( file.first ); // path relative to the source root auto relativeDir = utils::MakeRelativePath( sourceRootDirectory, filePath ) .replace_extension( "" ).string( ); if (relativeDir.find_first_of( ".." ) != std::string::npos) continue; auto outputFile = outputFileDirectory / relativeDir; auto outputFileHeader = change_extension( outputFile, "Generated.h" ); auto outputFileSource = change_extension( outputFile, "Generated.cpp" ); // module file name file.second.name = boost::regex_replace( relativeDir, kSpecialCharsRegex, "_" ); moduleFileCache += file.second.name + '\n'; TemplateData moduleFileData { TemplateData::Type::Object }; moduleFileData[ "name" ] = file.second.name; moduleFileData[ "header" ] = outputFileHeader.string( ); moduleFilesData << moduleFileData; // if the generated file header doesn't exist, we need to regenerate if (m_options.forceRebuild || !metaCacheFileExists || !exists( outputFileHeader )) { generateModuleFile( outputFileHeader, outputFileSource, file.first, file.second ); continue; } auto lastSourceWrite = last_write_time( filePath ); auto lastGeneratedWrite = last_write_time( outputFileHeader ); // if the generated file is older than the source file, we need to regenerate if (lastSourceWrite > lastGeneratedWrite) generateModuleFile( outputFileHeader, outputFileSource, file.first, file.second ); } fs::path moduleCacheFileName = m_options.outputModuleFileDirectory; moduleCacheFileName /= ".meta-cache"; if (!m_options.forceRebuild && metaCacheFileExists) { std::ifstream cacheFile( moduleCacheFileName.string( ) ); std::istreambuf_iterator<char> cacheFileBegin( cacheFile ); std::istreambuf_iterator<char> cacheFileEnd( nullptr ); // the cache is the same, so we don't need to write the source files if (utils::RangeEqual( moduleFileCache.begin( ), moduleFileCache.end( ), cacheFileBegin, cacheFileEnd )) { return; } } // update the cache utils::WriteText( moduleCacheFileName.string( ), moduleFileCache ); // module source file { auto sourceTemplate = LoadTemplate( kTemplateModuleSource ); if (!sourceTemplate.isValid( )) { std::stringstream error; error << "Unable to compile module source template." << std::endl; error << sourceTemplate.errorMessage( ); throw std::exception( error.str( ).c_str( ) ); } TemplateData sourceData { TemplateData::Type::Object }; addGlobalTemplateData( sourceData ); sourceData[ "moduleFile" ] = moduleFilesData; COMPILE_TYPE_TEMPLATES( sourceData, "external", m_externals ); fs::path sourcePath( m_options.outputModuleSource ); fs::create_directory( sourcePath.parent_path( ) ); utils::WriteText( sourcePath.string( ), sourceTemplate.render( sourceData ) ); } }
/// Entry point for the asynchronous monitor thread void run() { bool run = true; typedef std::pair< callback_t , std::pair< file_action, std::string> > notification; std::vector< notification> notifications; for (;;) { { // Lock and check m_run; if it was set to false, we must return ASAP boost::mutex::scoped_lock lock(m_run_mutex); run = m_run; if (!run) return; // We release the lock, block the thread until one second m_run_cond.timed_wait(lock, moost::thread::xtime_util::add_ms(moost::thread::xtime_util::now(), m_sleep_ms)); } // If we are not running (e.g. when the destructor woke us up), return if (!run) return; // Clear the notifications vector where we will collect the events // that will be fired notifications.clear(); { // Lock m_file_mutex while we are working on m_file_callback boost::mutex::scoped_lock lock(m_file_mutex); for (std::map<std::string, callback_t>::iterator it = m_file_callback.begin(); it != m_file_callback.end(); ++it) { boost::filesystem::path p(it->first); // Does the path exist? std::time_t lw = last_write_time(p); if (lw != 0) { // Check its last modification time and compare it with what we had earlier std::map< std::string, std::pair<time_t, time_t> >::iterator it_mod = m_file_modified.find(it->first); if (it_mod == m_file_modified.end()) { // We haven't seen this file so far, so insert it into the // map and add a creation event that will be fired m_file_modified[it->first] = std::make_pair(lw, lw); notifications.push_back(std::make_pair(it->second, std::make_pair(CREATED, it->first))); } else { // only case we consider a real modification: prev prev mod != prev mod, // but this mod == prev mod // the idea is that we want to capture a write to a file, // but only notify when the write is finished /** * \todo This could cause problems with frequent writing. * We should really use boost.interprocess file locking * instead (when we get 1.36 everywhere) */ if (lw == it_mod->second.second && it_mod->second.first != it_mod->second.second) notifications.push_back(std::make_pair(it->second, std::make_pair(CHANGED, it->first))); it_mod->second.first = it_mod->second.second; it_mod->second.second = lw; } } else { // The path does not exist. Did we have it before? If so, fire // a deletion event. std::map< std::string, std::pair<time_t, time_t> >::iterator it_mod = m_file_modified.find(it->first); if (it_mod != m_file_modified.end()) { m_file_modified.erase(it_mod); notifications.push_back(std::make_pair(it->second, std::make_pair(DELETED, it->first))); } } } } // okay! we've released our lock on m_file_callback and m_file_modified // so it's time to send off our notifications for (std::vector<notification>::iterator it = notifications.begin(); it != notifications.end(); ++it) { try { it->first(it->second.first, it->second.second); } catch (...) { // \todo can we do better here than silently ignoring the exception? } } } }