void FileChangeNotifier::OnFileChange( const FileSystemUtils::Path& filename ) { if (m_bActive) { // Check for multiple hits on the same file in close succession // (Can be caused by NTFS system making multiple changes even though only // one actual change occurred) bool bIgnoreFileChange = (filename == m_LastFileChanged) && m_fFileChangeSpamTimeRemaining > 0.0f; m_LastFileChanged = filename; if (!bIgnoreFileChange) { FileSystemUtils::Path filePath = filename; filePath.ToOSCanonicalCase(); m_changedFileList.push_back(filePath.m_string); if (!m_bRecompilePending) { m_bRecompilePending = true; m_fTimeUntilNextAllowedRecompile = max(m_fTimeUntilNextAllowedRecompile, m_fChangeNotifyDelay); } m_fFileChangeSpamTimeRemaining = FILE_CHANGE_SPAM_TIME; TriggerNotificationIfPossible(); } } }
void FileChangeNotifier::Watch( const FileSystemUtils::Path& filename, IFileChangeListener *pListener ) { FileSystemUtils::Path fixedFilename = filename.DelimitersToOSDefault(); // Note this doesn't handle ../ fixedFilename = fixedFilename.GetCleanPath(); fixedFilename.ToOSCanonicalCase(); m_pFileMonitor->Watch(fixedFilename, this); m_fileListenerMap[fixedFilename].insert(pListener); pListener->OnRegisteredWithNotifier(this); }
FileSystemUtils::Path RuntimeObjectSystem::FindFile( const FileSystemUtils::Path& input ) { FileSystemUtils::Path requestedDirectory = input; FileSystemUtils::Path filename; FileSystemUtils::Path foundFile = input; bool bIsFile = input.HasExtension(); if( bIsFile ) { requestedDirectory = requestedDirectory.ParentPath(); filename = input.Filename(); } requestedDirectory.ToOSCanonicalCase(); filename.ToOSCanonicalCase(); foundFile.ToOSCanonicalCase(); // Step 1: Try input directory if( requestedDirectory.Exists() ) { m_FoundSourceDirectoryMappings[ requestedDirectory ] = requestedDirectory; } else { // Step 2: Attempt to find a pre-existing mapping bool bFoundMapping = false; if( m_FoundSourceDirectoryMappings.size() ) { FileSystemUtils::Path testDir = requestedDirectory; FileSystemUtils::Path foundDir; unsigned int depth = 0; bool bFound = false; while( testDir.HasParentPath() ) { TFileMapIterator itrFind = m_FoundSourceDirectoryMappings.find( testDir ); if( itrFind != m_FoundSourceDirectoryMappings.end() ) { foundDir = itrFind->second; bFound = true; break; } testDir = testDir.ParentPath(); ++depth; } if( bFound ) { if( depth ) { // not an exact match FileSystemUtils::Path directory = requestedDirectory; directory.m_string.replace( 0, testDir.m_string.length(), foundDir.m_string ); if( directory.Exists() ) { foundFile = directory / filename; if( foundFile.Exists() ) { m_FoundSourceDirectoryMappings[ requestedDirectory ] = directory; if( m_pCompilerLogger ) { m_pCompilerLogger->LogInfo( "Found Directory Mapping: %s to %s\n", requestedDirectory.c_str(), directory.c_str() ); } bFoundMapping = true; } } } else { // exact match foundFile = foundDir / filename; bFoundMapping = true; } } if( !bFoundMapping ) { // Step 3: Attempt to find a mapping from a known path TFileList requestedSubPaths; FileSystemUtils::Path requestedSubPath = requestedDirectory; while( requestedSubPath.HasParentPath() ) { requestedSubPaths.push_back( requestedSubPath ); requestedSubPath = requestedSubPath.ParentPath(); } TFileMapIterator itr = m_FoundSourceDirectoryMappings.begin(); while( ( itr != m_FoundSourceDirectoryMappings.end() ) && !bFoundMapping ) { FileSystemUtils::Path existingPath = itr->second; while( ( existingPath.HasParentPath() ) && !bFoundMapping ) { // check all potentials for( size_t i=0; i<requestedSubPaths.size(); ++i ) { FileSystemUtils::Path toCheck = existingPath / requestedSubPaths[i].Filename(); if( toCheck.Exists() ) { // potential mapping FileSystemUtils::Path directory = requestedDirectory; directory.m_string.replace( 0, requestedSubPaths[i].m_string.length(), toCheck.m_string ); if( directory.Exists() ) { foundFile = directory / filename; if( foundFile.Exists() ) { m_FoundSourceDirectoryMappings[ requestedDirectory ] = directory; if( m_pCompilerLogger ) { m_pCompilerLogger->LogInfo( "Found Directory Mapping: %s to %s\n", requestedDirectory.c_str(), directory.c_str() ); } bFoundMapping = true; break; } } } } existingPath = existingPath.ParentPath(); } ++itr; } } } } if( !foundFile.Exists() ) { if( m_pCompilerLogger ) { m_pCompilerLogger->LogWarning( "Could not find Directory Mapping for: %s\n", input.c_str() ); } ++m_NumNotFoundSourceFiles; } return foundFile; }
void RuntimeObjectSystem::SetupRuntimeFileTracking(const IAUDynArray<IObjectConstructor*>& constructors_) { #ifndef RCCPPOFF // for optimization purposes we skip some actions when running for the first time (i.e. no previous constructors) static bool bFirstTime = true; for (size_t i = 0, iMax = constructors_.Size(); i < iMax; ++i) { const char* pFilename = constructors_[i]->GetFileName(); // GetFileName returns full path including GetCompiledPath() if( !pFilename ) { continue; } Path filePath = pFilename; filePath = filePath.GetCleanPath(); filePath = FindFile( filePath ); unsigned short projectId = constructors_[ i ]->GetProjectId(); ProjectSettings& project = GetProject( projectId ); AddToRuntimeFileList( filePath.c_str( ), projectId ); if( !bFirstTime ) { //remove old include file mappings for this file TFileToFilesIterator itrCurr = project.m_RuntimeIncludeMap.begin( ); while( itrCurr != project.m_RuntimeIncludeMap.end( ) ) { if( itrCurr->second == filePath ) { TFileToFilesIterator itrErase = itrCurr; ++itrCurr; project.m_RuntimeIncludeMap.erase( itrErase ); } else { ++itrCurr; } } //remove previous link libraries for this file project.m_RuntimeLinkLibraryMap.erase( filePath ); //remove previous source dependencies project.m_RuntimeSourceDependencyMap.erase( filePath ); } //we need the compile path for some platforms where the __FILE__ path is relative to the compile path FileSystemUtils::Path compileDir = constructors_[i]->GetCompiledPath(); //add include file mappings for (size_t includeNum = 0; includeNum <= constructors_[i]->GetMaxNumIncludeFiles(); ++includeNum) { const char* pIncludeFile = constructors_[i]->GetIncludeFile(includeNum); if( pIncludeFile ) { FileSystemUtils::Path pathInc = compileDir / pIncludeFile; pathInc = FindFile( pathInc.GetCleanPath() ); TFileToFilePair includePathPair; includePathPair.first = pathInc; includePathPair.second = filePath; AddToRuntimeFileList( pathInc.c_str(), projectId ); project.m_RuntimeIncludeMap.insert( includePathPair ); } } //add link library file mappings for (size_t linklibraryNum = 0; linklibraryNum <= constructors_[i]->GetMaxNumLinkLibraries(); ++linklibraryNum) { const char* pLinkLibrary = constructors_[i]->GetLinkLibrary(linklibraryNum); if( pLinkLibrary ) { // We do not use FindFiles for Linked Libraries as these are searched for on // the library paths, which are themselves searched for. TFileToFilePair linklibraryPathPair; linklibraryPathPair.first = filePath; linklibraryPathPair.second = pLinkLibrary; project.m_RuntimeLinkLibraryMap.insert( linklibraryPathPair ); } } //add source dependency file mappings for (size_t num = 0; num <= constructors_[i]->GetMaxNumSourceDependencies(); ++num) { SourceDependencyInfo sourceDependency = constructors_[i]->GetSourceDependency(num); FileSystemUtils::Path pathInc[2]; // array of potential include files for later checks if( sourceDependency.filename ) { FileSystemUtils::Path pathSrc; if( sourceDependency.relativeToPath ) { pathSrc = sourceDependency.relativeToPath; if( pathSrc.HasExtension() ) { pathInc[1] = compileDir / pathSrc; pathSrc = compileDir / pathSrc.ParentPath() / sourceDependency.filename; } else { pathSrc = compileDir / pathSrc / sourceDependency.filename; } } else { pathSrc = compileDir / sourceDependency.filename; } pathSrc.ToOSCanonicalCase(); pathSrc = pathSrc.DelimitersToOSDefault(); pathSrc = pathSrc.GetCleanPath(); pathInc[0] = pathSrc; if( sourceDependency.extension ) { pathSrc.ReplaceExtension( sourceDependency.extension ); } pathSrc = FindFile( pathSrc.GetCleanPath() ); TFileToFilePair sourcePathPair; sourcePathPair.first = filePath; sourcePathPair.second = pathSrc; project.m_RuntimeSourceDependencyMap.insert( sourcePathPair ); // if the include file with a source dependancy is logged as an runtime include, then we mark this .cpp as compile dependencies on change for( int inc=0; inc<2; ++inc ) { TFileToFilesEqualRange range = project.m_RuntimeIncludeMap.equal_range( pathInc[inc] ); if( range.first != range.second ) { // add source file to runtime file list AddToRuntimeFileList( pathSrc.c_str(), projectId ); // also add this as a source dependency, so it gets force compiled on change of header (and not just compiled) TFileToFilePair includePathPair; includePathPair.first = pathInc[inc]; includePathPair.second = pathSrc; project.m_RuntimeIncludeMap.insert( includePathPair ); } } } } } bFirstTime = false; #endif }