private static void TestAddingPath(string pathToAdd, string pathInList, bool isFolder = false)
        {
            ModifiedPathsDatabase modifiedPathsDatabase = CreateModifiedPathsDatabase(initialContents: $"A {DefaultEntry}\r\n");
            bool isRetryable;

            modifiedPathsDatabase.TryAdd(pathToAdd, isFolder, out isRetryable);
            modifiedPathsDatabase.Count.ShouldEqual(2);
            modifiedPathsDatabase.Contains(pathInList, isFolder).ShouldBeTrue();
            modifiedPathsDatabase.Contains(ToGitPathSeparators(pathInList), isFolder).ShouldBeTrue();
            modifiedPathsDatabase.GetAllModifiedPaths().ShouldContainSingle(x => string.Compare(x, ToGitPathSeparators(pathInList), GVFSPlatform.Instance.Constants.PathComparison) == 0);
        }
        private static void TestAddingPath(string pathToAdd, string pathInList, bool isFolder = false)
        {
            ModifiedPathsDatabase mpd = CreateModifiedPathsDatabase(initialContents: $"A {DefaultEntry}\r\n");
            bool isRetryable;

            mpd.TryAdd(pathToAdd, isFolder, out isRetryable);
            mpd.Count.ShouldEqual(2);
            mpd.Contains(pathInList, isFolder).ShouldBeTrue();
            mpd.Contains(ToGitPathSeparators(pathInList), isFolder).ShouldBeTrue();
            mpd.GetAllModifiedPaths().ShouldContainSingle(x => string.Compare(x, ToGitPathSeparators(pathInList), StringComparison.OrdinalIgnoreCase) == 0);
        }
        public void EntryNotAddedIfParentDirectoryExists()
        {
            ModifiedPathsDatabase modifiedPathsDatabase = CreateModifiedPathsDatabase(initialContents: "A dir/\r\n");

            modifiedPathsDatabase.Count.ShouldEqual(1);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();

            // Try adding a file for the directory that is in the modified paths
            modifiedPathsDatabase.TryAdd("dir/file.txt", isFolder: false, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(1);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();

            // Try adding a directory for the directory that is in the modified paths
            modifiedPathsDatabase.TryAdd("dir/dir2", isFolder: true, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(1);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();

            // Try adding a file for a directory that is not in the modified paths
            modifiedPathsDatabase.TryAdd("dir2/file.txt", isFolder: false, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(2);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/file.txt", isFolder: false).ShouldBeTrue();

            // Try adding a directory for a the directory that is not in the modified paths
            modifiedPathsDatabase.TryAdd("dir2/dir", isFolder: true, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(3);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/file.txt", isFolder: false).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/dir", isFolder: true).ShouldBeTrue();

            // Try adding a file in a subdirectory that is in the modified paths
            modifiedPathsDatabase.TryAdd("dir2/dir/file.txt", isFolder: false, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(3);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/file.txt", isFolder: false).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/dir", isFolder: true).ShouldBeTrue();

            // Try adding a directory for a subdirectory that is in the modified paths
            modifiedPathsDatabase.TryAdd("dir2/dir/dir3", isFolder: true, isRetryable: out _);
            modifiedPathsDatabase.Count.ShouldEqual(3);
            modifiedPathsDatabase.Contains("dir", isFolder: true).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/file.txt", isFolder: false).ShouldBeTrue();
            modifiedPathsDatabase.Contains("dir2/dir", isFolder: true).ShouldBeTrue();
        }
        public override bool TryUpgrade(ITracer tracer, string enlistmentRoot)
        {
            ModifiedPathsDatabase modifiedPaths = null;

            try
            {
                PhysicalFileSystem fileSystem = new PhysicalFileSystem();

                string modifiedPathsDatabasePath = Path.Combine(enlistmentRoot, GVFSConstants.DotGVFS.Root, GVFSConstants.DotGVFS.Databases.ModifiedPaths);
                string error;
                if (!ModifiedPathsDatabase.TryLoadOrCreate(tracer, modifiedPathsDatabasePath, fileSystem, out modifiedPaths, out error))
                {
                    tracer.RelatedError($"Unable to create the modified paths database. {error}");
                    return(false);
                }

                string sparseCheckoutPath = Path.Combine(enlistmentRoot, GVFSConstants.WorkingDirectoryRootName, GVFSConstants.DotGit.Info.SparseCheckoutPath);
                bool   isRetryable;
                using (FileStream fs = File.OpenRead(sparseCheckoutPath))
                    using (StreamReader reader = new StreamReader(fs))
                    {
                        string entry = reader.ReadLine();
                        while (entry != null)
                        {
                            entry = entry.Trim();
                            if (!string.IsNullOrWhiteSpace(entry))
                            {
                                bool isFolder = entry.EndsWith(GVFSConstants.GitPathSeparatorString);
                                if (!modifiedPaths.TryAdd(entry.Trim(GVFSConstants.GitPathSeparator), isFolder, out isRetryable))
                                {
                                    tracer.RelatedError("Unable to add to the modified paths database.");
                                    return(false);
                                }
                            }

                            entry = reader.ReadLine();
                        }
                    }

                string alwaysExcludePath = Path.Combine(enlistmentRoot, GVFSConstants.WorkingDirectoryRootName, GVFSConstants.DotGit.Info.AlwaysExcludePath);
                if (fileSystem.FileExists(alwaysExcludePath))
                {
                    string alwaysExcludeData = fileSystem.ReadAllText(alwaysExcludePath);

                    char[] carriageReturnOrLineFeed = new[] { '\r', '\n' };
                    int    endPosition = alwaysExcludeData.Length;
                    while (endPosition > 0)
                    {
                        int startPosition = alwaysExcludeData.LastIndexOfAny(carriageReturnOrLineFeed, endPosition - 1);
                        if (startPosition < 0)
                        {
                            startPosition = 0;
                        }

                        string entry = alwaysExcludeData.Substring(startPosition, endPosition - startPosition).Trim();

                        if (entry.EndsWith("*"))
                        {
                            // This is the first entry using the old format and we don't want to process old entries
                            // because we would need folder entries since there isn't a file and that would cause sparse-checkout to
                            // recursively clear skip-worktree bits for everything under that folder
                            break;
                        }

                        // Substring will not return a null and the Trim will get rid of all the whitespace
                        // if there is a length it will be a valid path that we need to process
                        if (entry.Length > 0)
                        {
                            entry = entry.TrimStart('!');
                            bool isFolder = entry.EndsWith(GVFSConstants.GitPathSeparatorString);
                            if (!isFolder)
                            {
                                if (!modifiedPaths.TryAdd(entry.Trim(GVFSConstants.GitPathSeparator), isFolder, out isRetryable))
                                {
                                    tracer.RelatedError("Unable to add to the modified paths database.");
                                    return(false);
                                }
                            }
                        }

                        endPosition = startPosition;
                    }
                }

                modifiedPaths.ForceFlush();
                fileSystem.WriteAllText(sparseCheckoutPath, "/.gitattributes" + Environment.NewLine);
                fileSystem.DeleteFile(alwaysExcludePath);
            }
            catch (IOException ex)
            {
                tracer.RelatedError($"IOException: {ex.ToString()}");
                return(false);
            }
            finally
            {
                if (modifiedPaths != null)
                {
                    modifiedPaths.Dispose();
                    modifiedPaths = null;
                }
            }

            if (!this.TryIncrementMajorVersion(tracer, enlistmentRoot))
            {
                return(false);
            }

            return(true);
        }
Ejemplo n.º 5
0
        public override bool TryUpgrade(ITracer tracer, string enlistmentRoot)
        {
            ModifiedPathsDatabase modifiedPaths = null;

            try
            {
                PhysicalFileSystem fileSystem = new PhysicalFileSystem();

                string modifiedPathsDatabasePath = Path.Combine(enlistmentRoot, GVFSConstants.DotGVFS.Root, GVFSConstants.DotGVFS.Databases.ModifiedPaths);
                string error;
                if (!ModifiedPathsDatabase.TryLoadOrCreate(tracer, modifiedPathsDatabasePath, fileSystem, out modifiedPaths, out error))
                {
                    tracer.RelatedError($"Unable to create the modified paths database. {error}");
                    return(false);
                }

                string sparseCheckoutPath = Path.Combine(enlistmentRoot, GVFSConstants.WorkingDirectoryRootName, GVFSConstants.DotGit.Info.SparseCheckoutPath);
                IEnumerable <string> sparseCheckoutLines = fileSystem.ReadAllText(sparseCheckoutPath).Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                bool isRetryable;
                foreach (string entry in sparseCheckoutLines)
                {
                    bool isFolder = entry.EndsWith(GVFSConstants.GitPathSeparatorString);
                    if (!modifiedPaths.TryAdd(entry.Trim(GVFSConstants.GitPathSeparator), isFolder, out isRetryable))
                    {
                        tracer.RelatedError("Unable to add to the modified paths database.");
                        return(false);
                    }
                }

                string alwaysExcludePath = Path.Combine(enlistmentRoot, GVFSConstants.WorkingDirectoryRootName, GVFSConstants.DotGit.Info.AlwaysExcludePath);
                if (fileSystem.FileExists(alwaysExcludePath))
                {
                    string[] alwaysExcludeLines = fileSystem.ReadAllText(alwaysExcludePath).Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = alwaysExcludeLines.Length - 1; i >= 0; i--)
                    {
                        string entry = alwaysExcludeLines[i];
                        if (entry.EndsWith("*"))
                        {
                            // This is the first entry using the old format and we don't want to process old entries
                            // because we would need folder entries since there isn't a file and that would cause sparse-checkout to
                            // recursively clear skip-worktree bits for everything under that folder
                            break;
                        }

                        entry = entry.TrimStart('!');
                        bool isFolder = entry.EndsWith(GVFSConstants.GitPathSeparatorString);
                        if (!isFolder)
                        {
                            if (!modifiedPaths.TryAdd(entry.Trim(GVFSConstants.GitPathSeparator), isFolder, out isRetryable))
                            {
                                tracer.RelatedError("Unable to add to the modified paths database.");
                                return(false);
                            }
                        }
                    }
                }

                modifiedPaths.ForceFlush();
                fileSystem.WriteAllText(sparseCheckoutPath, "/.gitattributes" + Environment.NewLine);
                fileSystem.DeleteFile(alwaysExcludePath);
            }
            catch (IOException ex)
            {
                tracer.RelatedError($"IOException: {ex.ToString()}");
                return(false);
            }
            finally
            {
                if (modifiedPaths != null)
                {
                    modifiedPaths.Dispose();
                    modifiedPaths = null;
                }
            }

            if (!this.TryIncrementMajorVersion(tracer, enlistmentRoot))
            {
                return(false);
            }

            return(true);
        }