示例#1
0
        private static bool FilesExistAndRecordRequestedWriteTime(ICollection <ITaskItem> files, TaskLoggingHelper log, bool getNewest, out DateTime requestedTime, out string requestedFilename)
        {
            bool allExist = true;

            requestedTime     = getNewest ? DateTime.MinValue : DateTime.MaxValue;
            requestedFilename = string.Empty;

            // No output files for the source were tracked
            // safely assume that this is because we didn't track them because they weren't compiled
            if (files == null || files.Count == 0)
            {
                allExist = false;
            }
            else
            {
                foreach (ITaskItem item in files)
                {
                    DateTime lastWriteTime = NativeMethodsShared.GetLastWriteFileUtcTime(item.ItemSpec);
                    // If the file does not exist
                    if (lastWriteTime == DateTime.MinValue)
                    {
                        FileTracker.LogMessageFromResources(log, MessageImportance.Low, "Tracking_OutputDoesNotExist", item.ItemSpec);
                        allExist = false;
                        break;
                    }

                    if (getNewest && lastWriteTime > requestedTime || !getNewest && lastWriteTime < requestedTime)
                    {
                        requestedTime     = lastWriteTime;
                        requestedFilename = item.ItemSpec;
                    }
                }
            }
            return(allExist);
        }
示例#2
0
        /// <summary>
        /// Update the current state of entry details for the dependency table
        /// </summary>
        public void UpdateFileEntryDetails()
        {
            _oldestFileName    = String.Empty;
            _oldestFileTimeUtc = DateTime.MaxValue;

            _newestFileName    = String.Empty;
            _newestFileTimeUtc = DateTime.MinValue;

            _newestTLogFileName = String.Empty;
            _newestTLogTimeUtc  = DateTime.MinValue;

            this.MissingFiles.Clear();

            // First update the details of our Tlogs
            foreach (ITaskItem tlogFileName in _tlogFiles)
            {
                DateTime tlogLastWriteTimeUtc = NativeMethodsShared.GetLastWriteFileUtcTime(tlogFileName.ItemSpec);
                if (tlogLastWriteTimeUtc > _newestTLogTimeUtc)
                {
                    _newestTLogTimeUtc  = tlogLastWriteTimeUtc;
                    _newestTLogFileName = tlogFileName.ItemSpec;
                }
            }

            // Now for each entry in the table
            foreach (string entry in this.DependencyTable.Keys)
            {
                RecordEntryDetails(entry, false);
            }
        }
        public void GetLastWriteFileUtcTimeReturnsMinValueForDirectory()
        {
            string directory = FileUtilities.GetTemporaryDirectory(createDirectory: true);

            DateTime directoryTime = NativeMethodsShared.GetLastWriteFileUtcTime(directory);

            Assert.Equal(DateTime.MinValue, directoryTime);
        }
        public void GetLastWriteFileUtcTimeReturnsMinValueForMissingFile()
        {
            string nonexistentFile = FileUtilities.GetTemporaryFile();

            // Make sure that the file does not, in fact, exist.
            File.Delete(nonexistentFile);

            DateTime nonexistentFileTime = NativeMethodsShared.GetLastWriteFileUtcTime(nonexistentFile);

            Assert.Equal(DateTime.MinValue, nonexistentFileTime);
        }
示例#5
0
        /// <summary>
        /// Returns cached value for last write time of file. Update the cache if it is the first
        /// time someone asking for that file
        /// </summary>
        public DateTime GetLastWriteTimeUtc(string file)
        {
            DateTime fileModifiedTimeUtc = DateTime.MinValue;

            if (!_lastWriteTimeUtcCache.TryGetValue(file, out fileModifiedTimeUtc))
            {
                fileModifiedTimeUtc          = NativeMethodsShared.GetLastWriteFileUtcTime(file);
                _lastWriteTimeUtcCache[file] = fileModifiedTimeUtc;
            }

            return(fileModifiedTimeUtc);
        }
示例#6
0
        public override DateTime GetLastWriteTimeUtc(string path)
        {
            var fileLastWriteTime = NativeMethodsShared.GetLastWriteFileUtcTime(path);

            if (fileLastWriteTime != DateTime.MinValue)
            {
                return(fileLastWriteTime);
            }
            else
            {
                NativeMethodsShared.GetLastWriteDirectoryUtcTime(path, out var directoryLastWriteTime);
                return(directoryLastWriteTime);
            }
        }
示例#7
0
        /// <summary>
        /// Returns true if task execution is not necessary. Executed after ValidateParameters
        /// </summary>
        protected override bool SkipTaskExecution()
        {
            if (!String.IsNullOrEmpty(OutputWindowsMetadataFile))
            {
                var outputWriteTime      = NativeMethodsShared.GetLastWriteFileUtcTime(OutputWindowsMetadataFile);
                var winMDModuleWriteTime = NativeMethodsShared.GetLastWriteFileUtcTime(WinMDModule);

                // If the last write time of the input file is less than the last write time of the output file
                // then the output is newer then the input so we do not need to re-run the tool.
                if (outputWriteTime > winMDModuleWriteTime)
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Determine if a cache entry is up to date
        /// </summary>
        /// <param name="dependencyTable">The cache entry to check</param>
        /// <returns>true if up to date</returns>
        private static bool DependencyTableIsUpToDate(DependencyTableCacheEntry dependencyTable)
        {
            DateTime tableTime = dependencyTable.TableTime;

            foreach (ITaskItem tlogFile in dependencyTable.TlogFiles)
            {
                string tlogFilename = FileUtilities.NormalizePath(tlogFile.ItemSpec);

                DateTime lastWriteTime = NativeMethodsShared.GetLastWriteFileUtcTime(tlogFilename);
                if (lastWriteTime > tableTime)
                {
                    // one of the tlog files is newer than the table, so return false
                    return(false);
                }
            }

            return(true);
        }
示例#9
0
        /// <summary>
        /// This method adds a computed output for the given source key to the dictionary specified
        /// </summary>
        /// <param name="dependencies">The dictionary to add outputs to</param>
        /// <param name="computedOutput">The computed outputs for this source key</param>
        private void AddOutput(Dictionary <string, DateTime> dependencies, string computedOutput)
        {
            string fullComputedOutput = FileUtilities.NormalizePath(computedOutput).ToUpperInvariant();

            if (!dependencies.ContainsKey(fullComputedOutput))
            {
                DateTime fileModifiedTime;
                if (FileUtilities.FileExistsNoThrow(fullComputedOutput))
                {
                    fileModifiedTime = NativeMethodsShared.GetLastWriteFileUtcTime(fullComputedOutput);
                }
                else
                {
                    fileModifiedTime = DateTime.MinValue;
                }
                dependencies.Add(fullComputedOutput, fileModifiedTime);
            }
        }
示例#10
0
        /// <summary>
        /// Construct a new entry
        /// </summary>
        /// <param name="tlogFiles">The tlog files used to build this dependency table</param>
        /// <param name="dependencyTable">The dependency table to be cached</param>
        internal DependencyTableCacheEntry(ITaskItem[] tlogFiles, IDictionary dependencyTable)
        {
            TlogFiles = new ITaskItem[tlogFiles.Length];
            TableTime = DateTime.MinValue;

            // Our cache's knowledge of the tlog items needs their full path
            for (int tlogItemCount = 0; tlogItemCount < tlogFiles.Length; tlogItemCount++)
            {
                string tlogFilename = FileUtilities.NormalizePath(tlogFiles[tlogItemCount].ItemSpec);
                TlogFiles[tlogItemCount] = new TaskItem(tlogFilename);
                // Our cache entry needs to use the last modified time of the latest tlog
                // involved so that our cache can be invalidated if any tlog is updated
                DateTime modifiedTime = NativeMethodsShared.GetLastWriteFileUtcTime(tlogFilename);
                if (modifiedTime > TableTime)
                {
                    TableTime = modifiedTime;
                }
            }

            DependencyTable = dependencyTable;
        }
示例#11
0
        /// <summary>
        /// Construct our dependency table for our source files
        /// </summary>
        private void ConstructOutputTable()
        {
            string tLogRootingMarker = null;

            try
            {
                // construct a rooting marker from the tlog files
                tLogRootingMarker = DependencyTableCache.FormatNormalizedTlogRootingMarker(_tlogFiles);
            }
            catch (ArgumentException e)
            {
                FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
                return;
            }

            // Record the current directory (which under normal circumstances will be the project directory)
            // so that we can compare tracked paths against it for inclusion in the dependency graph
            string currentProjectDirectory = FileUtilities.EnsureTrailingSlash(Directory.GetCurrentDirectory());

            if (!_tlogAvailable)
            {
                FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingLogNotAvailable");
                lock (DependencyTableCache.DependencyTable)
                {
                    // The tracking logs are not available, they may have been deleted at some point.
                    // Be safe and remove any references from the cache.
                    if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
                    {
                        DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
                    }
                }
                return;
            }

            DependencyTableCacheEntry cachedEntry = null;

            lock (DependencyTableCache.DependencyTable)
            {
                // Look in the dependency table cache to see if its available and up to date
                cachedEntry = DependencyTableCache.GetCachedEntry(tLogRootingMarker);
            }

            // We have an up to date cached entry
            if (cachedEntry != null)
            {
                _dependencyTable = (Dictionary <string, System.Collections.Generic.Dictionary <string, System.DateTime> >)cachedEntry.DependencyTable;
                // Log information about what we're using
                FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_WriteTrackingCached");
                foreach (ITaskItem tlogItem in cachedEntry.TlogFiles)
                {
                    FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogItem.ItemSpec);
                }
                return;
            }

            FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_WriteTrackingLogs");

            // Now we need to construct the rest of the table from the TLOG files
            // If there are any errors in the tlogs, we want to warn, stop parsing tlogs, and empty
            // out the dependency table, essentially forcing a rebuild.
            bool   encounteredInvalidTLogContents = false;
            bool   exceptionCaught = false;
            string invalidTLogName = null;

            foreach (ITaskItem tlogFileName in _tlogFiles)
            {
                FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogFileName.ItemSpec);

                try
                {
                    using (StreamReader tlog = File.OpenText(tlogFileName.ItemSpec))
                    {
                        string tlogEntry = tlog.ReadLine();

                        while (tlogEntry != null)
                        {
                            if (tlogEntry.Length == 0)
                            {
                                encounteredInvalidTLogContents = true;
                                invalidTLogName = tlogFileName.ItemSpec;
                                break;
                            }

                            if (tlogEntry[0] == '^') // This is a rooting record, follow the outputs for it
                            {
                                Dictionary <string, DateTime> dependencies;

                                tlogEntry = tlogEntry.Substring(1);

                                if (tlogEntry.Length == 0)
                                {
                                    encounteredInvalidTLogContents = true;
                                    invalidTLogName = tlogFileName.ItemSpec;
                                    break;
                                }

                                if (!_dependencyTable.TryGetValue(tlogEntry, out dependencies))
                                {
                                    dependencies = new Dictionary <string, DateTime>(StringComparer.OrdinalIgnoreCase);
                                    _dependencyTable.Add(tlogEntry, dependencies);
                                }

                                // Process each file encountered until we hit a rooting marker
                                do
                                {
                                    tlogEntry = tlog.ReadLine();

                                    if (tlogEntry != null)
                                    {
                                        if (tlogEntry.Length == 0)
                                        {
                                            encounteredInvalidTLogContents = true;
                                            invalidTLogName = tlogFileName.ItemSpec;
                                            break;
                                        }
                                        else if ((tlogEntry[0] != '^') && (tlogEntry[0] != '#') && (!dependencies.ContainsKey(tlogEntry)))
                                        {
                                            // Allows incremental build of projects existing under temp, only for those reads / writes that
                                            // either are not under temp, or are recursively beneath the current project directory.
                                            if (FileTracker.FileIsUnderPath(tlogEntry, currentProjectDirectory) || !FileTracker.FileIsExcludedFromDependencies(tlogEntry))
                                            {
                                                DateTime fileModifiedTime = NativeMethodsShared.GetLastWriteFileUtcTime(tlogEntry);

                                                dependencies.Add(tlogEntry, fileModifiedTime);
                                            }
                                        }
                                    }
                                } while ((tlogEntry != null) && (tlogEntry[0] != '^'));

                                if (encounteredInvalidTLogContents)
                                {
                                    break;
                                }
                            }
                            else // don't know what this entry is, so skip it
                            {
                                tlogEntry = tlog.ReadLine();
                            }
                        }
                    }
                }
                catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
                {
                    FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
                    break;
                }

                if (encounteredInvalidTLogContents)
                {
                    FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLogContents", invalidTLogName);
                    break;
                }
            }

            lock (DependencyTableCache.DependencyTable)
            {
                // There were problems with the tracking logs -- we've already warned or errored; now we want to make
                // sure that we essentially force a rebuild of this particular root.
                if (encounteredInvalidTLogContents || exceptionCaught)
                {
                    if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
                    {
                        DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
                    }

                    _dependencyTable = new Dictionary <string, Dictionary <string, DateTime> >(StringComparer.OrdinalIgnoreCase);
                }
                else
                {
                    // Record the newly built valid dependency table in the cache
                    DependencyTableCache.DependencyTable[tLogRootingMarker] = new DependencyTableCacheEntry(_tlogFiles, _dependencyTable);
                }
            }
        }
示例#12
0
        /// <summary>
        /// Construct our dependency table for our source files
        /// </summary>
        private void ConstructFileTable()
        {
            string tLogRootingMarker = null;

            try
            {
                // construct a rooting marker from the tlog files
                tLogRootingMarker = DependencyTableCache.FormatNormalizedTlogRootingMarker(_tlogFiles);
            }
            catch (ArgumentException e)
            {
                FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
                return;
            }
            if (!_tlogsAvailable)
            {
                lock (DependencyTableCache.DependencyTable)
                {
                    // The tracking logs are not available, they may have been deleted at some point.
                    // Be safe and remove any references from the cache.
                    if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
                    {
                        DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
                    }
                }
                return;
            }

            DependencyTableCacheEntry cachedEntry = null;

            lock (DependencyTableCache.DependencyTable)
            {
                // Look in the dependency table cache to see if its available and up to date
                cachedEntry = DependencyTableCache.GetCachedEntry(tLogRootingMarker);
            }

            // We have an up to date cached entry
            if (cachedEntry != null)
            {
                _dependencyTable = (IDictionary <string, DateTime>)cachedEntry.DependencyTable;

                // We may have stored the dependency table in the cache, but all the other information
                // (newest file time, number of missing files, etc.) has been reset to default.  Refresh
                // the data.
                this.UpdateFileEntryDetails();

                // Log information about what we're using
                FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingCached");
                foreach (ITaskItem tlogItem in cachedEntry.TlogFiles)
                {
                    FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogItem.ItemSpec);
                }
                return;
            }

            FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingLogs");
            // Now we need to construct the rest of the table from the TLOG files
            // If there are any errors in the tlogs, we want to warn, stop parsing tlogs, and empty
            // out the dependency table, essentially forcing a rebuild.
            bool   encounteredInvalidTLogContents = false;
            bool   exceptionCaught = false;
            string invalidTLogName = null;

            foreach (ITaskItem tlogFileName in _tlogFiles)
            {
                try
                {
                    FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogFileName.ItemSpec);

                    DateTime tlogLastWriteTimeUtc = NativeMethodsShared.GetLastWriteFileUtcTime(tlogFileName.ItemSpec);
                    if (tlogLastWriteTimeUtc > _newestTLogTimeUtc)
                    {
                        _newestTLogTimeUtc  = tlogLastWriteTimeUtc;
                        _newestTLogFileName = tlogFileName.ItemSpec;
                    }

                    using (StreamReader tlog = File.OpenText(tlogFileName.ItemSpec))
                    {
                        string tlogEntry = tlog.ReadLine();

                        while (tlogEntry != null)
                        {
                            if (tlogEntry.Length == 0) // empty lines are a sign that something has gone wrong
                            {
                                encounteredInvalidTLogContents = true;
                                invalidTLogName = tlogFileName.ItemSpec;
                                break;
                            }
                            // Preprocessing for the line entry
                            else if (tlogEntry[0] == '#') // a comment marker should be skipped
                            {
                                tlogEntry = tlog.ReadLine();
                                continue;
                            }
                            else if (tlogEntry[0] == '^' && TreatRootMarkersAsEntries && tlogEntry.IndexOf('|') < 0) // This is a rooting non composite record, and we should keep it
                            {
                                tlogEntry = tlogEntry.Substring(1);

                                if (tlogEntry.Length == 0)
                                {
                                    encounteredInvalidTLogContents = true;
                                    invalidTLogName = tlogFileName.ItemSpec;
                                    break;
                                }
                            }
                            else if (tlogEntry[0] == '^') // root marker is not being treated as an entry, skip it
                            {
                                tlogEntry = tlog.ReadLine();
                                continue;
                            }

                            // If we haven't seen this file before, then record it
                            if (!_dependencyTable.ContainsKey(tlogEntry))
                            {
                                // It may be that this is one of the locations that we should ignore
                                if (!FileTracker.FileIsExcludedFromDependencies(tlogEntry))
                                {
                                    RecordEntryDetails(tlogEntry, true);
                                }
                            }
                            tlogEntry = tlog.ReadLine();
                        }
                    }
                }
                catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
                {
                    FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
                    break;
                }

                if (encounteredInvalidTLogContents)
                {
                    FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLogContents", invalidTLogName);
                    break;
                }
            }

            lock (DependencyTableCache.DependencyTable)
            {
                // There were problems with the tracking logs -- we've already warned or errored; now we want to make
                // sure that we essentially force a rebuild of this particular root.
                if (encounteredInvalidTLogContents || exceptionCaught)
                {
                    if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
                    {
                        DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
                    }

                    _dependencyTable = new Dictionary <string, DateTime>(StringComparer.OrdinalIgnoreCase);
                }
                else
                {
                    // Record the newly built dependency table in the cache
                    DependencyTableCache.DependencyTable[tLogRootingMarker] = new DependencyTableCacheEntry(_tlogFiles, (IDictionary)_dependencyTable);
                }
            }
        }