示例#1
0
        public static ObjectHash WriteFixedTree(string vcsPath, Tree tree)
        {
            var resultingTreeLines = new List <Tree.TreeLine>();

            bool fixRequired = false;

            foreach (var treeLine in tree.Lines)
            {
                if (!treeLine.IsDirectory())
                {
                    resultingTreeLines.Add(treeLine);
                    continue;
                }

                var childTree     = GitObjectFactory.ReadTree(vcsPath, treeLine.Hash);
                var fixedTreeHash = WriteFixedTree(vcsPath, childTree);
                resultingTreeLines.Add(new Tree.TreeLine(treeLine.TextBytes, fixedTreeHash));
                if (fixedTreeHash != childTree.Hash)
                {
                    fixRequired = true;
                }
            }

            if (fixRequired || Tree.HasDuplicateLines(resultingTreeLines))
            {
                tree = Tree.GetFixedTree(resultingTreeLines);
                HashContent.WriteObject(vcsPath, tree);
            }

            return(tree.Hash);
        }
示例#2
0
        private static ConcurrentStack <Commit> ReadCommitsFromRefs(string vcsPath)
        {
            var refs         = Refs.ReadAll(vcsPath);
            var addedCommits = new ConcurrentDictionary <ObjectHash, bool>();
            var result       = new ConcurrentStack <Commit>();

            Parallel.ForEach(refs, new ParallelOptions {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            }, @ref =>
            {
                var gitObject = @ref is TagRef tag
                    ? GitObjectFactory.ReadGitObject(vcsPath, new ObjectHash(tag.CommitHash))
                    : GitObjectFactory.ReadGitObject(vcsPath, new ObjectHash(@ref.Hash));

                while (gitObject is Tag tagObject)
                {
                    gitObject = GitObjectFactory.ReadGitObject(vcsPath, new ObjectHash(tagObject.Object));
                }

                // Tags pointing to trees are ignored
                if (gitObject.Type == GitObjectType.Commit && addedCommits.TryAdd(gitObject.Hash, true))
                {
                    result.Push((Commit)gitObject);
                }
            });

            return(result);
        }
示例#3
0
        private static bool HasDefectiveTree(string vcsPath, Commit commit)
        {
            if (SeenTrees.TryGetValue(commit.TreeHash, out bool isDefective))
            {
                return(isDefective);
            }

            var tree = GitObjectFactory.ReadTree(vcsPath, commit.TreeHash);

            return(IsDefectiveTree(vcsPath, tree));
        }
示例#4
0
        public static IEnumerable <Commit> CommitsRandomOrder(string vcsPath)
        {
            var commitsAlreadySeen = new HashSet <ObjectHash>();
            var commits            = ReadCommitsFromRefs(vcsPath);

            while (commits.TryPop(out var commit))
            {
                if (!commitsAlreadySeen.Add(commit.Hash))
                {
                    continue;
                }

                yield return(commit);

                foreach (var parent in commit.Parents.Where(parent => !commitsAlreadySeen.Contains(parent)))
                {
                    commits.Push(GitObjectFactory.ReadCommit(vcsPath, parent));
                }
            }
        }
示例#5
0
        private static ObjectHash RewriteRef(string vcsPath, string hash, string refName, Dictionary <ObjectHash, ObjectHash> rewrittenCommits)
        {
            var gitObject = GitObjectFactory.ReadGitObject(vcsPath, new ObjectHash(hash));

            if (gitObject.Type == GitObjectType.Commit)
            {
                var path          = Path.Combine(vcsPath, refName);
                var correctedHash = GetRewrittenCommitHash(new ObjectHash(hash), rewrittenCommits);
                Directory.CreateDirectory(Path.GetDirectoryName(path));
                File.WriteAllText(path, correctedHash.ToString());
                return(correctedHash);
            }

            if (gitObject.Type == GitObjectType.Tag)
            {
                var tag = (Tag)gitObject;

                if (tag.PointsToTree)
                {
                    // Do not touch tags pointing to trees right now as this is not properly implemented yet
                    return(tag.Hash);
                }

                var rewrittenObjectHash = tag.PointsToTag
                    ? RewriteRef(vcsPath, tag.Object, "", rewrittenCommits)
                    : GetRewrittenCommitHash(new ObjectHash(tag.Object), rewrittenCommits);

                // points to commit
                var rewrittenTag = tag.WithNewObject(rewrittenObjectHash.ToString());
                HashContent.WriteObject(vcsPath, rewrittenTag);

                var path = Path.Combine(vcsPath, "refs/tags", rewrittenTag.TagName);
                File.WriteAllText(path, rewrittenTag.Hash.ToString());

                return(rewrittenTag.Hash);
            }

            throw new NotImplementedException();
        }
示例#6
0
        public static IEnumerable <Commit> CommitsInOrder(string vcsPath)
        {
            var commits          = ReadCommitsFromRefs(vcsPath);
            var parentsSeen      = new HashSet <ObjectHash>();
            var commitsProcessed = new HashSet <ObjectHash>();

            while (commits.TryPop(out var commit))
            {
                if (commitsProcessed.Contains(commit.Hash))
                {
                    parentsSeen.Remove(commit.Hash);
                }
                else
                {
                    if (!parentsSeen.Add(commit.Hash) || !commit.HasParents)
                    {
                        commitsProcessed.Add(commit.Hash);
                        yield return(commit);
                    }
                    else
                    {
                        commits.Push(commit);
                        foreach (var parent in commit.Parents)
                        {
                            if (!commitsProcessed.Contains(parent))
                            {
                                var parentCommit = GitObjectFactory.ReadCommit(vcsPath, parent);
                                if (parentCommit == null)
                                {
                                    throw new Exception("Commit not found: " + parent);
                                }
                                commits.Push(parentCommit);
                            }
                        }
                    }
                }
            }
        }
示例#7
0
        public static bool IsDefectiveTree(string vcsPath, Tree tree)
        {
            if (SeenTrees.TryGetValue(tree.Hash, out bool isDefective))
            {
                return(isDefective);
            }

            if (Tree.HasDuplicateLines(tree.Lines))
            {
                SeenTrees.TryAdd(tree.Hash, true);
                return(true);
            }

            var childTrees = tree.GetDirectories();

            foreach (var childTree in childTrees)
            {
                if (SeenTrees.TryGetValue(childTree.Hash, out isDefective))
                {
                    if (isDefective)
                    {
                        return(true);
                    }

                    continue;
                }

                var childTreeObject = (Tree)GitObjectFactory.ReadGitObject(vcsPath, childTree.Hash);
                if (IsDefectiveTree(vcsPath, childTreeObject))
                {
                    return(true);
                }
            }

            SeenTrees.TryAdd(tree.Hash, false);
            return(false);
        }
示例#8
0
        static Dictionary <ObjectHash, ObjectHash> FixDefectiveCommits(string vcsPath, List <ObjectHash> defectiveCommits)
        {
            var rewrittenCommitHashes = new Dictionary <ObjectHash, ObjectHash>();

            foreach (var commit in CommitWalker.CommitsInOrder(vcsPath))
            {
                if (rewrittenCommitHashes.ContainsKey(commit.Hash))
                {
                    continue;
                }

                // Rewrite this commit
                byte[] newCommitBytes;
                if (defectiveCommits.Contains(commit.Hash))
                {
                    var fixedTreeHash = WriteFixedTree(vcsPath, GitObjectFactory.ReadTree(vcsPath, commit.TreeHash));
                    newCommitBytes = Commit.GetSerializedCommitWithChangedTreeAndParents(commit, fixedTreeHash,
                                                                                         CorrectParents(commit.Parents, rewrittenCommitHashes).ToList());
                }
                else
                {
                    newCommitBytes = Commit.GetSerializedCommitWithChangedTreeAndParents(commit, commit.TreeHash,
                                                                                         CorrectParents(commit.Parents, rewrittenCommitHashes).ToList());
                }

                var fileObjectBytes = GitObjectFactory.GetBytesWithHeader(GitObjectType.Commit, newCommitBytes);
                var newCommitHash   = new ObjectHash(Hash.Create(fileObjectBytes));
                if (newCommitHash != commit.Hash && !rewrittenCommitHashes.ContainsKey(commit.Hash))
                {
                    HashContent.WriteFile(vcsPath, fileObjectBytes, newCommitHash.ToString());
                    rewrittenCommitHashes.Add(commit.Hash, newCommitHash);
                }
            }

            return(rewrittenCommitHashes);
        }