private string[] GetDirectoriesOutsideSparse(string rootPath, SparseTable sparseTable) { HashSet <string> sparseFolders = sparseTable.GetAll(); PhysicalFileSystem fileSystem = new PhysicalFileSystem(); Queue <string> foldersToEnumerate = new Queue <string>(); foldersToEnumerate.Enqueue(rootPath); List <string> foldersOutsideSparse = new List <string>(); while (foldersToEnumerate.Count > 0) { string folderToEnumerate = foldersToEnumerate.Dequeue(); foreach (string directory in fileSystem.EnumerateDirectories(folderToEnumerate)) { string enlistmentRootRelativeFolderPath = GVFSDatabase.NormalizePath(directory.Substring(rootPath.Length)); if (!enlistmentRootRelativeFolderPath.Equals(GVFSConstants.DotGit.Root, GVFSPlatform.Instance.Constants.PathComparison)) { if (sparseFolders.Any(x => x.StartsWith(enlistmentRootRelativeFolderPath + Path.DirectorySeparatorChar, GVFSPlatform.Instance.Constants.PathComparison))) { foldersToEnumerate.Enqueue(directory); } else if (!sparseFolders.Contains(enlistmentRootRelativeFolderPath)) { foldersOutsideSparse.Add(enlistmentRootRelativeFolderPath); } } } } return(foldersOutsideSparse.ToArray()); }
private void ListSparseFolders(string enlistmentRoot) { using (GVFSDatabase database = new GVFSDatabase(new PhysicalFileSystem(), enlistmentRoot, new SqliteDatabase())) { SparseTable sparseTable = new SparseTable(database); HashSet <string> directories = sparseTable.GetAll(); if (directories.Count == 0) { this.Output.WriteLine("No folders in sparse list. When the sparse list is empty, all folders are projected."); } else { foreach (string directory in directories) { this.Output.WriteLine(directory); } } } }
protected override void Execute(GVFSEnlistment enlistment) { using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, SparseVerbName)) { tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Sparse), EventLevel.Informational, Keywords.Any); bool needToChangeProjection = false; using (GVFSDatabase database = new GVFSDatabase(new PhysicalFileSystem(), enlistment.EnlistmentRoot, new SqliteDatabase())) { SparseTable sparseTable = new SparseTable(database); HashSet <string> directories = sparseTable.GetAll(); string[] foldersToRemove = this.ParseFolderList(this.Remove); string[] foldersToAdd = this.ParseFolderList(this.Add); if (this.List || (foldersToAdd.Length == 0 && foldersToRemove.Length == 0)) { if (directories.Count == 0) { this.Output.WriteLine("No folders in sparse list. When the sparse list is empty, all folders are projected."); } else { foreach (string directory in directories) { this.Output.WriteLine(directory); } } return; } foreach (string folder in foldersToRemove) { if (directories.Contains(folder)) { needToChangeProjection = true; break; } } if (!needToChangeProjection) { foreach (string folder in foldersToAdd) { if (!directories.Contains(folder)) { needToChangeProjection = true; break; } } } if (needToChangeProjection) { // Make sure there is a clean git status before allowing sparse set to change this.CheckGitStatus(tracer, enlistment); if (!this.ShowStatusWhileRunning( () => { foreach (string directoryPath in foldersToRemove) { tracer.RelatedInfo($"Removing '{directoryPath}' from sparse folders."); sparseTable.Remove(directoryPath); } foreach (string directoryPath in foldersToAdd) { tracer.RelatedInfo($"Adding '{directoryPath}' to sparse folders."); sparseTable.Add(directoryPath); } return(true); }, "Updating sparse folder set", suppressGvfsLogMessage: true)) { this.ReportErrorAndExit(tracer, "Failed to update sparse folder set."); } } } if (needToChangeProjection) { // Force a projection update to get the current inclusion set this.ForceProjectionChange(tracer, enlistment); tracer.RelatedInfo("Projection updated after adding or removing folders."); } else { this.WriteMessage(tracer, "No folders to update in sparse set."); } } }
protected override void Execute(GVFSEnlistment enlistment) { if (this.List || ( !this.Prune && !this.Disable && string.IsNullOrEmpty(this.Add) && string.IsNullOrEmpty(this.Remove) && string.IsNullOrEmpty(this.Set) && string.IsNullOrEmpty(this.File))) { this.ListSparseFolders(enlistment.EnlistmentRoot); return; } this.CheckOptions(); using (JsonTracer tracer = new JsonTracer(GVFSConstants.GVFSEtwProviderName, SparseVerbName)) { tracer.AddLogFileEventListener( GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.Sparse), EventLevel.Informational, Keywords.Any); EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(this.Set), this.Set); metadata.Add(nameof(this.File), this.File); metadata.Add(nameof(this.Add), this.Add); metadata.Add(nameof(this.Remove), this.Remove); metadata.Add(nameof(this.Prune), this.Prune); metadata.Add(nameof(this.Disable), this.Disable); tracer.RelatedInfo(metadata, $"Running sparse"); HashSet <string> directories; bool needToChangeProjection = false; using (GVFSDatabase database = new GVFSDatabase(new PhysicalFileSystem(), enlistment.EnlistmentRoot, new SqliteDatabase())) { SparseTable sparseTable = new SparseTable(database); directories = sparseTable.GetAll(); List <string> foldersToRemove = new List <string>(); List <string> foldersToAdd = new List <string>(); if (this.Disable) { if (directories.Count > 0) { this.WriteMessage(tracer, "Removing all folders from sparse list. When the sparse list is empty, all folders are projected."); needToChangeProjection = true; foldersToRemove.AddRange(directories); directories.Clear(); } else { return; } } else if (!string.IsNullOrEmpty(this.Set) || !string.IsNullOrEmpty(this.File)) { IEnumerable <string> folders = null; if (!string.IsNullOrEmpty(this.Set)) { folders = this.ParseFolderList(this.Set); } else if (!string.IsNullOrEmpty(this.File)) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); folders = this.ParseFolderList(fileSystem.ReadAllText(this.File), folderSeparator: Environment.NewLine); } else { this.WriteMessage(tracer, "Invalid options specified."); throw new InvalidOperationException(); } foreach (string folder in folders) { if (!directories.Contains(folder)) { needToChangeProjection = true; foldersToAdd.Add(folder); } else { // Remove from directories so that the only directories left in the directories collection // will be the ones that will need to be removed from sparse set directories.Remove(folder); } } if (directories.Count > 0) { needToChangeProjection = true; foldersToRemove.AddRange(directories); directories.Clear(); } // Need to add folders that will be in the projection back into directories for the status check foreach (string folder in folders) { directories.Add(folder); } } else { // Process adds and removes foreach (string folder in this.ParseFolderList(this.Remove)) { if (directories.Contains(folder)) { needToChangeProjection = true; directories.Remove(folder); foldersToRemove.Add(folder); } } foreach (string folder in this.ParseFolderList(this.Add)) { if (!directories.Contains(folder)) { needToChangeProjection = true; directories.Add(folder); foldersToAdd.Add(folder); } } } if (needToChangeProjection || this.Prune) { if (directories.Count > 0) { // Make sure there is a clean git status before allowing sparse set to change this.CheckGitStatus(tracer, enlistment, directories); } this.UpdateSparseFolders(tracer, sparseTable, foldersToRemove, foldersToAdd); } if (needToChangeProjection) { // Force a projection update to get the current inclusion set this.ForceProjectionChange(tracer, enlistment); tracer.RelatedInfo("Projection updated after adding or removing folders."); } else { this.WriteMessage(tracer, "No folders to update in sparse set."); } if (this.Prune && directories.Count > 0) { this.PruneFoldersOutsideSparse(tracer, enlistment, sparseTable); } } } }