private static List <FileSystemEntry> BuildEntries(DirectorySnapshot directoryEntry) { return(directoryEntry.ChildDirectories .Select(x => BuildDirectoryEntry(x)) .Concat(directoryEntry.ChildFiles.Select(x => BuildFileEntry(x))) .ToList()); }
private static DirectoryEntry BuildDirectoryEntry(DirectorySnapshot directoryEntry) { return(new DirectoryEntry { Name = (directoryEntry.DirectoryName.IsAbsoluteName ? directoryEntry.DirectoryName.FullPath.Value : directoryEntry.DirectoryName.Name), Data = null, Entries = BuildEntries(directoryEntry) }); }
private static void VisitDirectory(IProject project, DirectorySnapshot directory, Action <IProject, DirectorySnapshot> callback) { callback(project, directory); foreach (var child in directory.ChildDirectories.ToForeachEnum()) { VisitDirectory(project, child, callback); } }
private static List <FileSystemEntry> BuildEntries(DirectorySnapshot entry) { var d = entry.ChildDirectories.Select(x => new DirectoryEntry { Name = x.DirectoryName.Name }).Cast <FileSystemEntry>(); var f = entry.ChildFiles.Select(x => new FileEntry { Name = x.Name }); return(d.Concat(f).ToList()); }
private DirectorySnapshot CreateDirectorySnapshot(DirectoryName directory, bool isSymLink) { _cancellationToken.ThrowIfCancellationRequested(); var directoriesWithFiles = TraverseFileSystem(directory, isSymLink).ToList(); // We sort entries by directory name *descending* to make sure we process // directories bottom up, so that we know // 1) it is safe to skip DirectoryEntry instances where "Entries.Count" == 0, // 2) we create instances of child directories before their parent. _progress.DisplayProgress((i, n) => $"Sorting files of directory {directory.FullPath}"); directoriesWithFiles.Sort((x, y) => - x.DirectoryData.DirectoryName.CompareTo(y.DirectoryData.DirectoryName)); // Build map from parent directory -> list of child directories var directoriesToChildDirectories = new Dictionary <DirectoryName, List <DirectoryName> >(); directoriesWithFiles.ForAll(x => { _cancellationToken.ThrowIfCancellationRequested(); var directoryName = x.DirectoryData.DirectoryName; // Ignore root project directory name if (directoryName.IsAbsoluteName) { return; } GetOrCreateList(directoriesToChildDirectories, directoryName.Parent) .Add(directoryName); }); // Build directory snapshots for each directory entry, using an // intermediate map to enable connecting snapshots to their parent. var directoriesToSnapshot = new Dictionary <DirectoryName, DirectorySnapshot>(); var directorySnapshots = directoriesWithFiles.Select(entry => { _cancellationToken.ThrowIfCancellationRequested(); if (_progress.Step()) { _progress.DisplayProgress((i, n) => $"Processing files and directories of directory {_project.RootPath.Value}"); } var directoryData = entry.DirectoryData; var childFileNames = entry.FileNames; var childDirectories = GetOrEmptyList(directoriesToChildDirectories, directoryData.DirectoryName) .Select(x => directoriesToSnapshot[x]) .OrderBy(x => x.DirectoryName.Name) .ToReadOnlyList(); // TODO(rpaquay): Not clear the lines below are a perf win, even though // they do not hurt correctness. // Remove children since we processed them //GetOrEmptyList(directoriesToChildDirectories, directoryName) // .ForAll(x => directoriesToSnapshot.Remove(x)); var result = new DirectorySnapshot(directoryData, childDirectories, childFileNames); directoriesToSnapshot.Add(directoryData.DirectoryName, result); return(result); }) .ToList(); // Since we sort directories by name descending, the last entry is always the // entry correcsponding to the project root. Invariants.Assert(directorySnapshots.Count >= 1); Invariants.Assert(directorySnapshots.Last().DirectoryName.Equals(directory)); return(directorySnapshots.Last()); }
private DirectorySnapshot ApplyDirectorySnapshotDelta(DirectorySnapshot oldDirectory) { var oldDirectoryPath = oldDirectory.DirectoryName.RelativePath; // Create lists of created dirs and files. We have to access the file system to know // if each path is a file or a directory. List <IFileInfoSnapshot> createDirs = null; List <IFileInfoSnapshot> createdFiles = null; foreach (var path in _pathChanges.GetCreatedEntries(oldDirectoryPath).ToForeachEnum()) { _cancellationToken.ThrowIfCancellationRequested(); // cancellation var info = _fileSystem.GetFileInfoSnapshot(_project.RootPath.Combine(path)); if (info.IsDirectory) { if (createDirs == null) { createDirs = new List <IFileInfoSnapshot>(); } createDirs.Add(info); } else if (info.IsFile) { if (createdFiles == null) { createdFiles = new List <IFileInfoSnapshot>(); } createdFiles.Add(info); } } // Recursively create new directory entires for previous (non deleted) // entries. var childDirectories = oldDirectory.ChildDirectories .Where(dir => !_pathChanges.IsDeleted(dir.DirectoryName.RelativePath)) .Select(dir => ApplyDirectorySnapshotDelta(dir)) .ToList(); // Add created directories if (createDirs != null) { foreach (var info in createDirs.ToForeachEnum()) { _cancellationToken.ThrowIfCancellationRequested(); // cancellation var createdDirectoryName = _fileSystemNameFactory.CreateDirectoryName(oldDirectory.DirectoryName, info.Path.FileName); var childSnapshot = CreateDirectorySnapshot(createdDirectoryName, info.IsSymLink); // Note: File system change notifications are not always 100% // reliable. We may get a "create" event for directory we already know // about. var index = childDirectories.FindIndex(x => SystemPathComparer.EqualsNames(x.DirectoryName.Name, createdDirectoryName.Name)); if (index >= 0) { childDirectories.RemoveAt(index); } childDirectories.Add(childSnapshot); } // We need to re-sort the array since we added new entries childDirectories.Sort((x, y) => SystemPathComparer.Compare(x.DirectoryName.Name, y.DirectoryName.Name)); } // Match non deleted files // Sepcial case: if no file deleted or created, just re-use the list. IList <FileName> newFileList; if (_pathChanges.GetDeletedEntries(oldDirectoryPath).Count == 0 && createdFiles == null) { newFileList = oldDirectory.ChildFiles; } else { // Copy the list of previous children, minus deleted files. var newFileListTemp = oldDirectory.ChildFiles .Where(x => !_pathChanges.IsDeleted(x.RelativePath)) .ToList(); // Add created files if (createdFiles != null) { foreach (var info in createdFiles.ToForeachEnum()) { var name = _fileSystemNameFactory.CreateFileName(oldDirectory.DirectoryName, info.Path.FileName); newFileListTemp.Add(name); } // We need to re-sort the array since we added new entries newFileListTemp.Sort((x, y) => SystemPathComparer.Compare(x.Name, y.Name)); // Note: File system change notifications are not always 100% // reliable. We may get a "create" event for files we already know // about. ArrayUtilities.RemoveDuplicates(newFileListTemp, (x, y) => SystemPathComparer.EqualsNames(x.Name, y.Name)); } newFileList = newFileListTemp; } var newData = new DirectoryData(oldDirectory.DirectoryName, oldDirectory.IsSymLink); return(new DirectorySnapshot( newData, childDirectories.ToReadOnlyList(), newFileList.ToReadOnlyList())); }
private DirectorySnapshot CreateDirectorySnapshot(DirectoryName directory, bool isSymLink) { // Create list of pairs (DirectoryName, List[FileNames]) var directoriesWithFiles = TraverseFileSystem(directory, isSymLink) .AsParallel() .WithExecutionMode(ParallelExecutionMode.ForceParallelism) .Select(traversedDirectoryEntry => { var directoryName = traversedDirectoryEntry.DirectoryData.DirectoryName; if (_progress.Step()) { _progress.DisplayProgress((i, n) => string.Format("Traversing directory: {0}\\{1}", _project.RootPath.Value, directoryName.RelativePath.Value)); } var fileNames = traversedDirectoryEntry.ChildFileNames .Where(childFilename => _project.FileFilter.Include(childFilename.RelativePath)) .OrderBy(x => x.RelativePath) .ToReadOnlyCollection(); return(KeyValuePair.Create(traversedDirectoryEntry.DirectoryData, fileNames)); }) .ToList(); // We sort entries by directory name *descending* to make sure we process // directories bottom up, so that we know // 1) it is safe to skip DirectoryEntry instances where "Entries.Count" == 0, // 2) we create instances of child directories before their parent. directoriesWithFiles.Sort((x, y) => - x.Key.DirectoryName.RelativePath.CompareTo(y.Key.DirectoryName.RelativePath)); // Build map from parent directory -> list of child directories var directoriesToChildDirectories = new Dictionary <DirectoryName, List <DirectoryName> >(); directoriesWithFiles.ForAll(x => { var directoryName = x.Key; // Ignore root project directory name if (directoryName.DirectoryName.IsAbsoluteName) { return; } GetOrCreateList(directoriesToChildDirectories, directoryName.DirectoryName.Parent).Add(directoryName.DirectoryName); }); // Build directory snapshots for each directory entry, using an // intermediate map to enable connecting snapshots to their parent. var directoriesToSnapshot = new Dictionary <DirectoryName, DirectorySnapshot>(); var directorySnapshots = directoriesWithFiles.Select(entry => { var directoryElement = entry.Key; var childFilenames = entry.Value; var childDirectories = GetOrEmptyList(directoriesToChildDirectories, directoryElement.DirectoryName) .Select(x => directoriesToSnapshot[x]) .OrderBy(x => x.DirectoryName.RelativePath) .ToReadOnlyCollection(); // TODO(rpaquay): Not clear the lines below are a perf win, even though // they do not hurt correctness. // Remove children since we processed them //GetOrEmptyList(directoriesToChildDirectories, directoryName) // .ForAll(x => directoriesToSnapshot.Remove(x)); var result = new DirectorySnapshot(directoryElement, childDirectories, childFilenames); directoriesToSnapshot.Add(directoryElement.DirectoryName, result); return(result); }) .ToList(); // Since we sort directories by name descending, the last entry is always the // entry correcsponding to the project root. Debug.Assert(directorySnapshots.Count >= 1); Debug.Assert(directorySnapshots.Last().DirectoryName.Equals(directory)); return(directorySnapshots.Last()); }
public static DirectoryDetails CreateDirectoryDetails(IFileDatabaseSnapshot database, ProjectRootSnapshot projectSnapshot, DirectorySnapshot baseDirectory, int maxFilesByExtensionDetailsCount, int maxLargeFilesDetailsCount) { var directoryPath = baseDirectory.DirectoryName.FullPath; var fileDatabse = (FileDatabaseSnapshot)database; var directoryFileNames = fileDatabse.FileNames .Where(x => directoryPath.ContainsPath(x.FullPath)) .ToHashSet(); var directoryFiles = fileDatabse.Files.Values .Where(x => directoryFileNames.Contains(x.FileName)) .ToList(); var searchableFiles = directoryFiles .Where(x => x.HasContents()) .ToList(); var binaryFiles = directoryFiles .Where(x => (x.Contents is BinaryFileContents) && (((BinaryFileContents)x.Contents).BinaryFileSize > 0)) .ToList(); return(new DirectoryDetails { Path = directoryPath.Value, DirectoryCount = FileSystemSnapshotManager.CountDirectoryEntries(baseDirectory), FileCount = FileSystemSnapshotManager.CountFileEntries(baseDirectory), SearchableFilesCount = searchableFiles.Count, SearchableFilesByteLength = searchableFiles.Aggregate(0L, (acc, x) => acc + x.Contents.ByteLength), BinaryFilesCount = binaryFiles.Count, BinaryFilesByteLength = binaryFiles.Aggregate(0L, (acc, x) => acc + ((BinaryFileContents)x.Contents).BinaryFileSize), SearchableFilesByExtensionDetails = searchableFiles .GroupBy(x => GetFileExtension(x.FileName)) .Select(g => new FileByExtensionDetails { FileExtension = g.Key, FileCount = g.Count(), FilesByteLength = g.Aggregate(0L, (acc, x) => acc + x.Contents.ByteLength) }) .OrderByDescendingThenTake(maxFilesByExtensionDetailsCount, x => x.FilesByteLength) .ToList(), LargeSearchableFilesDetails = searchableFiles .OrderByDescendingThenTake(maxLargeFilesDetailsCount, x => x.Contents.ByteLength) .Select(x => new LargeFileDetails { RelativePath = GetRelativePath(directoryPath, x.FileName.FullPath), ByteLength = x.Contents.ByteLength }) .ToList(), BinaryFilesByExtensionDetails = binaryFiles .GroupBy(x => GetFileExtension(x.FileName)) .Select(g => new FileByExtensionDetails { FileExtension = g.Key, FileCount = g.Count(), FilesByteLength = g.Aggregate(0L, (acc, x) => acc + ((BinaryFileContents)x.Contents).BinaryFileSize) }) .OrderByDescendingThenTake(maxFilesByExtensionDetailsCount, x => x.FilesByteLength) .ToList(), LargeBinaryFilesDetails = binaryFiles .OrderByDescendingThenTake(maxLargeFilesDetailsCount, x => ((BinaryFileContents)x.Contents).BinaryFileSize) .Select(x => new LargeFileDetails { RelativePath = GetRelativePath(directoryPath, x.FileName.FullPath), ByteLength = ((BinaryFileContents)x.Contents).BinaryFileSize }) .ToList() }); }