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)
     });
 }
示例#3
0
 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);
     }
 }
示例#4
0
        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());
        }
示例#8
0
        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()
            });
        }