Ejemplo n.º 1
0
        private void LazyLoadTree(IList <TreeEntryModel> entries, Commit commit, string path, double scale)
        {
            var tree = string.IsNullOrEmpty(path)
                ? commit.Tree
                : commit[path].Target as Tree;

            var sha = tree.Sha;

            if (GitCache.Exists(sha, "summary"))
            {
                return;
            }

            var job = new SingleJob(() =>
            {
                Task.Delay(1000).Wait(); // let's the page going on

                using (var repo = new Repository(_repositoryPath))
                {
                    var ancestors = repo.Commits.QueryBy(new CommitFilter {
                        Since = commit, SortBy = CommitSortStrategies.Topological
                    });
                    var summary = CalculateRevisionSummary(entries, ancestors, null);
                    GitCache.Set(sha, "summary", summary, true);
                }
            }, scale / 10000);

            Scheduler.Instance.AddJob(job, string.Format("LazyLoadTree {0}/{1}/{2}", this.Name, commit.Sha, path));
        }
Ejemplo n.º 2
0
        public BranchesModel GetBranches()
        {
            var head = _repository.Head;

            if (head.Tip == null)
            {
                return(new BranchesModel());
            }

            var sha          = CalcBranchesSha();
            var aheadBehinds = GitCache.Get <RevisionSummaryCacheItem[]>(sha, "branches");

            if (aheadBehinds == null)
            {
                aheadBehinds = _repository.Branches
                               .Where(s => s != head && s.Name != "HEAD")
                               .OrderByDescending(s => s.Tip.Author.When)
                               .Select(branch =>
                {
                    var commit     = branch.Tip;
                    var divergence = _repository.ObjectDatabase.CalculateHistoryDivergence(commit, head.Tip);
                    return(new RevisionSummaryCacheItem
                    {
                        Ahead = divergence.AheadBy ?? 0,
                        Behind = divergence.BehindBy ?? 0,
                        Name = branch.Name,
                        Sha = commit.Sha,
                        AuthorName = commit.Author.Name,
                        AuthorEmail = commit.Author.Email,
                        AuthorWhen = commit.Author.When,
                        CommitterName = commit.Committer.Name,
                        CommitterEmail = commit.Committer.Email,
                        CommitterWhen = commit.Committer.When,
                    });
                })
                               .ToArray();
                GitCache.Set(sha, "branches", aheadBehinds);
            }
            var model = new BranchesModel
            {
                Commit       = ToCommitModel(head.Tip, head.Name),
                AheadBehinds = aheadBehinds.Select(s => new AheadBehindModel
                {
                    Ahead  = s.Ahead,
                    Behind = s.Behind,
                    Commit = new CommitModel
                    {
                        ReferenceName = s.Name,
                        Author        = new Signature(s.AuthorName, s.AuthorEmail, s.AuthorWhen),
                        Committer     = new Signature(s.CommitterName, s.CommitterEmail, s.CommitterWhen),
                    },
                }).ToArray(),
            };

            return(model);
        }
Ejemplo n.º 3
0
        public ContributorsModel GetContributors(string path)
        {
            string referenceName;
            var    commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                return(null);
            }

            var ancestors = _repository.Commits
                            .QueryBy(new CommitFilter {
                Since = commit
            });

            var contributors = GitCache.Get <ContributorCommitsModel[]>(commit.Sha, "contributors");

            if (contributors == null)
            {
                contributors = ancestors.GroupBy(s => s.Author.ToString())
                               .Select(s => new ContributorCommitsModel
                {
                    Author       = s.Key,
                    CommitsCount = s.Count(),
                })
                               .OrderByDescending(s => s.CommitsCount)
                               .ThenBy(s => s.Author, new StringLogicalComparer())
                               .ToArray();
                GitCache.Set(commit.Sha, "contributors", contributors);
            }

            var statistics = new RepositoryStatisticsModel();
            var stats      = GitCache.Get <RepositoryStatisticsModel.Statistics>(commit.Sha, "statistics");
            int size;

            if (stats == null)
            {
                stats = new RepositoryStatisticsModel.Statistics
                {
                    Branch       = referenceName,
                    Commits      = ancestors.Count(),
                    Contributors = ancestors.Select(s => s.Author.ToString()).Distinct().Count(),
                    Files        = FilesInCommit(commit, out size),
                    SourceSize   = size,
                };

                GitCache.Set(commit.Sha, "statistics", stats);
            }
            statistics.Current = stats;

            if (_repository.Head.Tip != commit)
            {
                commit = _repository.Head.Tip;
                stats  = GitCache.Get <RepositoryStatisticsModel.Statistics>(commit.Sha, "statistics");
                if (stats == null)
                {
                    ancestors = _repository.Commits.QueryBy(new CommitFilter {
                        Since = commit
                    });
                    stats = new RepositoryStatisticsModel.Statistics
                    {
                        Branch       = _repository.Head.Name,
                        Commits      = ancestors.Count(),
                        Contributors = ancestors.Select(s => s.Author.ToString()).Distinct().Count(),
                        Files        = FilesInCommit(commit, out size),
                        SourceSize   = size,
                    };

                    GitCache.Set(commit.Sha, "statistics", stats);
                }
                statistics.Default = stats;
            }

            var sha        = CalcBranchesSha(true);
            var sizeOfRepo = GitCache.Get <long>(sha, "size");

            if (sizeOfRepo == 0)
            {
                sizeOfRepo = SizeOfRepository();
                GitCache.Set(sha, "size", sizeOfRepo);
            }
            statistics.RepositorySize = sizeOfRepo;

            var model = new ContributorsModel
            {
                RepositoryName = Name,
                Contributors   = contributors,
                Statistics     = statistics,
            };

            return(model);
        }
Ejemplo n.º 4
0
        public TreeModel GetTree(string path)
        {
            var    isEmptyPath = string.IsNullOrEmpty(path);
            string referenceName;
            var    commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                if (isEmptyPath)
                {
                    var branch = _repository.Branches["master"]
                                 ?? _repository.Branches.FirstOrDefault();
                    return(new TreeModel
                    {
                        ReferenceName = branch == null ? "HEAD" : branch.Name,
                    });
                }
                return(null);
            }

            var model = new TreeModel
            {
                ReferenceName = referenceName,
                Path          = string.IsNullOrEmpty(path) ? "" : path,
                Commit        = new CommitModel
                {
                    Sha                = commit.Sha,
                    Author             = commit.Author,
                    Committer          = commit.Committer,
                    CommitMessageShort = commit.MessageShort.RepetitionIfEmpty(NoCommitMessage),
                    Parents            = commit.Parents.Select(s => s.Sha).ToArray()
                },
            };

            var tree = string.IsNullOrEmpty(path)
                ? commit.Tree
                : commit[path] == null
                    ? null
                    : commit[path].Target as Tree;

            if (tree == null)
            {
                return(null);
            }

            IEnumerable <Commit> ancestors = _repository.Commits
                                             .QueryBy(new CommitFilter {
                Since = commit, SortBy = CommitSortStrategies.Topological
            });

            var scope = GitCache.Get <RepositoryScope>(commit.Sha, "scope");

            if (scope == null)
            {
                ancestors = ancestors.ToList();
                scope     = new RepositoryScope
                {
                    Commits      = ancestors.Count(),
                    Contributors = ancestors.Select(s => s.Author.ToString()).Distinct().Count(),
                };
                GitCache.Set(commit.Sha, "scope", scope);
            }

            var entries = tree
                          .OrderBy(s => s.TargetType == TreeEntryTargetType.Blob)
                          .ThenBy(s => s.Name, new StringLogicalComparer())
                          .Select(s => new TreeEntryModel
            {
                Name          = s.Name,
                ReferenceName = referenceName,
                Path          = s.Path.Replace('\\', '/'),
                Commit        = new CommitModel
                {
                    CommitMessageShort = "???",
                    Author             = new Signature("???", "???", DateTimeOffset.MinValue),
                },
                Sha       = s.Target.Sha,
                EntryType = s.TargetType,
            })
                          .ToList();

            var    summary = GitCache.Get <RevisionSummaryCacheItem[]>(tree.Sha, "summary");
            var    missing = summary == null;
            double scale   = scope.Commits * tree.Count;

            if ((missing || summary.Length == 0) && scale > 20000)
            {
                LazyLoadTree(entries, commit, path, scale);
            }
            else
            {
                summary = CalculateRevisionSummary(entries, ancestors, summary);
            }

            if (missing)
            {
                GitCache.Set(tree.Sha, "summary", summary ?? new RevisionSummaryCacheItem[0]);
            }

            model.Entries = entries;
            model.Readme  = entries.FirstOrDefault(s => s.EntryType == TreeEntryTargetType.Blob &&
                                                   (string.Equals(s.Name, "readme", StringComparison.OrdinalIgnoreCase)
                                                    //|| string.Equals(s.Name, "readme.txt", StringComparison.OrdinalIgnoreCase)
                                                    || string.Equals(s.Name, "readme.md", StringComparison.OrdinalIgnoreCase)));

            if (model.Readme != null)
            {
                var data     = ((Blob)tree[model.Readme.Name].Target).GetContentStream().ToBytes();
                var encoding = FileHelper.DetectEncoding(data, CpToEncoding(commit.Encoding), _i18n.Value);
                if (encoding == null)
                {
                    model.Readme.BlobType = BlobType.Binary;
                }
                else
                {
                    model.Readme.BlobType = model.Readme.Name.EndsWith(".md", StringComparison.OrdinalIgnoreCase)
                        ? BlobType.MarkDown
                        : BlobType.Text;
                    model.Readme.TextContent = FileHelper.ReadToEnd(data, encoding);
                    model.Readme.TextBrush   = "no-highlight";
                }
            }

            model.BranchSelector = GetBranchSelectorModel(referenceName, commit.Sha, path);
            model.PathBar        = new PathBarModel
            {
                Name          = Name,
                Action        = "Tree",
                Path          = path,
                ReferenceName = referenceName,
                ReferenceSha  = commit.Sha,
                HideLastSlash = false,
            };

            if (model.IsRoot)
            {
                scope.Branches = _repository.Branches.Count();
                scope.Tags     = _repository.Tags.Count();
                model.Scope    = scope;
            }

            return(model);
        }
Ejemplo n.º 5
0
        public string GetArchiveFilename(string path, string newline, out string referenceName)
        {
            var commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                return(null);
            }

            if (referenceName == null)
            {
                referenceName = commit.Sha;
            }

            var key = "archive";

            if (newline != null)
            {
                key += newline.GetHashCode().ToString("x");
            }
            bool exist;
            var  filename = GitCache.GetCacheFilename(commit.Sha, key, out exist, true);

            if (exist)
            {
                return(filename);
            }

            using (var zipOutputStream = new ZipOutputStream(new FileStream(filename, FileMode.Create)))
            {
                var stack = new Stack <Tree>();

                stack.Push(commit.Tree);
                while (stack.Count != 0)
                {
                    var tree = stack.Pop();
                    foreach (var entry in tree)
                    {
                        byte[] bytes;
                        switch (entry.TargetType)
                        {
                        case TreeEntryTargetType.Blob:
                            zipOutputStream.PutNextEntry(new ZipEntry(entry.Path));
                            var blob = (Blob)entry.Target;
                            bytes = blob.GetContentStream().ToBytes();
                            if (newline == null)
                            {
                                zipOutputStream.Write(bytes, 0, bytes.Length);
                            }
                            else
                            {
                                var encoding = FileHelper.DetectEncoding(bytes, CpToEncoding(commit.Encoding), _i18n.Value);
                                if (encoding == null)
                                {
                                    zipOutputStream.Write(bytes, 0, bytes.Length);
                                }
                                else
                                {
                                    bytes = FileHelper.ReplaceNewline(bytes, encoding, newline);
                                    zipOutputStream.Write(bytes, 0, bytes.Length);
                                }
                            }
                            break;

                        case TreeEntryTargetType.Tree:
                            stack.Push((Tree)entry.Target);
                            break;

                        case TreeEntryTargetType.GitLink:
                            zipOutputStream.PutNextEntry(new ZipEntry(entry.Path + "/.gitsubmodule"));
                            bytes = Encoding.ASCII.GetBytes(entry.Target.Sha);
                            zipOutputStream.Write(bytes, 0, bytes.Length);
                            break;
                        }
                    }
                }
                zipOutputStream.SetComment(commit.Sha);
            }

            return(filename);
        }
Ejemplo n.º 6
0
        public BlameModel GetBlame(string path)
        {
            string referenceName;
            var    commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                return(null);
            }

            var entry = commit[path];

            if (entry == null || entry.TargetType != TreeEntryTargetType.Blob)
            {
                return(null);
            }

            var blob     = (Blob)entry.Target;
            var bytes    = blob.GetContentStream().ToBytes();
            var encoding = FileHelper.DetectEncoding(bytes, CpToEncoding(commit.Encoding), _i18n.Value);

            if (encoding == null)
            {
                return(null);
            }

            var code   = FileHelper.ReadToEnd(bytes, encoding);
            var reader = new StringReader(code);

            var hunks = GitCache.Get <BlameHunkModel[]>(blob.Sha, "blame");

            if (hunks == null)
            {
                var blame = _repository.Blame(path, new BlameOptions {
                    StartingAt = commit
                });
                hunks = blame.Select(s => new BlameHunkModel
                {
                    Code         = reader.ReadLines(s.LineCount),
                    StartLine    = s.FinalStartLineNumber,
                    EndLine      = s.LineCount,
                    MessageShort = s.FinalCommit.MessageShort.RepetitionIfEmpty(NoCommitMessage),
                    Sha          = s.FinalCommit.Sha,
                    Author       = s.FinalCommit.Author.Name,
                    AuthorEmail  = s.FinalCommit.Author.Email,
                    AuthorDate   = s.FinalCommit.Author.When,
                })
                        .ToArray();
                GitCache.Set(blob.Sha, "blame", hunks);
            }

            var model = new BlameModel
            {
                ReferenceName  = referenceName,
                Sha            = commit.Sha,
                Path           = string.IsNullOrEmpty(path) ? "" : path,
                SizeString     = FileHelper.GetSizeString(blob.Size),
                Brush          = FileHelper.GetBrush(path),
                Hunks          = hunks,
                BranchSelector = GetBranchSelectorModel(referenceName, commit.Sha, path),
                PathBar        = new PathBarModel
                {
                    Name          = Name,
                    Action        = "Tree",
                    Path          = path,
                    ReferenceName = referenceName,
                    ReferenceSha  = commit.Sha,
                    HideLastSlash = true,
                },
            };

            return(model);
        }
Ejemplo n.º 7
0
        public CommitsModel GetCommits(string path, int page = 1, int pagesize = 20)
        {
            string referenceName;
            var    commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                return(null);
            }

            var tree = commit[path];

            if (!string.IsNullOrEmpty(path) && tree == null)
            {
                return(null);
            }

            var cacheKey = commit.Sha;

            if (tree != null)
            {
                cacheKey += "-" + tree.Target.Sha;
            }
            var commits = GitCache.Get <RevisionSummaryCacheItem[]>(cacheKey, "commits");

            if (commits == null)
            {
                var ancestors = _repository.Commits
                                .QueryBy(new CommitFilter {
                    Since = commit, SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time
                })
                                .PathFilter(path)
                                .ToList();

                commits = ancestors.Select(s => new RevisionSummaryCacheItem
                {
                    Sha            = s.Sha,
                    MessageShort   = s.MessageShort.RepetitionIfEmpty(NoCommitMessage),
                    AuthorName     = s.Author.Name,
                    AuthorEmail    = s.Author.Email,
                    AuthorWhen     = s.Author.When,
                    CommitterName  = s.Committer.Name,
                    CommitterEmail = s.Committer.Email,
                    CommitterWhen  = s.Committer.When,
                }).ToArray();

                GitCache.Set(cacheKey, "commits", commits);
            }

            var model = new CommitsModel
            {
                ReferenceName = referenceName,
                Sha           = commit.Sha,
                Commits       = commits
                                .Skip((page - 1) * pagesize)
                                .Take(pagesize)
                                .Select(s => new CommitModel
                {
                    CommitMessageShort = s.MessageShort,
                    Sha       = s.Sha,
                    Author    = new Signature(s.AuthorName, s.AuthorEmail, s.AuthorWhen),
                    Committer = new Signature(s.CommitterName, s.CommitterEmail, s.CommitterWhen),
                })
                                .ToList(),
                CurrentPage = page,
                ItemCount   = commits.Count(),
                Path        = string.IsNullOrEmpty(path) ? "" : path,
                PathBar     = new PathBarModel
                {
                    Name          = Name,
                    Action        = "Commits",
                    Path          = path,
                    ReferenceName = referenceName,
                    ReferenceSha  = commit.Sha,
                    HideLastSlash = path != "" && commit[path].TargetType == TreeEntryTargetType.Blob,
                },
            };

            return(model);
        }
Ejemplo n.º 8
0
        public TreeEntryModel GetBlob(string path)
        {
            string referenceName;
            var    commit = GetCommitByPath(ref path, out referenceName);

            if (commit == null)
            {
                return(null);
            }

            var entry = commit[path];

            if (entry == null || entry.TargetType != TreeEntryTargetType.Blob)
            {
                return(null);
            }

            var blob = (Blob)entry.Target;

            var lastCommitSha = GitCache.Get <string>(blob.Sha, "affectedcommit");

            if (lastCommitSha == null)
            {
                var hs    = new HashSet <string>();
                var queue = new Queue <Commit>();
                queue.Enqueue(commit);
                hs.Add(commit.Sha);
                while (queue.Count > 0)
                {
                    commit = queue.Dequeue();
                    var has = false;
                    foreach (var parent in commit.Parents)
                    {
                        var tree = parent[path];
                        if (tree == null)
                        {
                            continue;
                        }
                        var eq = tree.Target.Sha == blob.Sha;
                        if (eq && hs.Add(parent.Sha))
                        {
                            queue.Enqueue(parent);
                        }
                        has = has || eq;
                    }
                    if (!has)
                    {
                        break;
                    }
                }
                lastCommitSha = commit.Sha;
                GitCache.Set(blob.Sha, "affectedcommit", lastCommitSha);
            }
            if (lastCommitSha != commit.Sha)
            {
                commit = _repository.Lookup <Commit>(lastCommitSha);
            }

            var data      = blob.GetContentStream().ToBytes();
            var encoding  = FileHelper.DetectEncoding(data, CpToEncoding(commit.Encoding), _i18n.Value);
            var extension = Path.GetExtension(entry.Name).ToLower();
            var model     = new TreeEntryModel
            {
                Name          = entry.Name,
                ReferenceName = referenceName,
                Sha           = commit.Sha,
                Path          = string.IsNullOrEmpty(path) ? "" : path,
                Commit        = new CommitModel
                {
                    Sha                = commit.Sha,
                    Author             = commit.Author,
                    Committer          = commit.Committer,
                    CommitMessage      = commit.Message.RepetitionIfEmpty(NoCommitMessage),
                    CommitMessageShort = commit.MessageShort.RepetitionIfEmpty(NoCommitMessage),
                    Parents            = commit.Parents.Select(s => s.Sha).ToArray()
                },
                EntryType   = entry.TargetType,
                RawData     = data,
                SizeString  = FileHelper.GetSizeString(data.Length),
                TextContent = encoding == null
                    ? null
                    : FileHelper.ReadToEnd(data, encoding),
                TextBrush = FileHelper.BrushMapping.ContainsKey(extension)
                    ? FileHelper.BrushMapping[extension]
                    : "no-highlight",
                BlobType = encoding == null
                    ? FileHelper.ImageSet.Contains(extension)
                        ? BlobType.Image
                        : BlobType.Binary
                    : extension == ".md"
                        ? BlobType.MarkDown
                        : BlobType.Text,
                BlobEncoding   = encoding,
                BranchSelector = GetBranchSelectorModel(referenceName, commit.Sha, path),
                PathBar        = new PathBarModel
                {
                    Name          = Name,
                    Action        = "Tree",
                    Path          = path,
                    ReferenceName = referenceName,
                    ReferenceSha  = commit.Sha,
                    HideLastSlash = true,
                },
            };

            return(model);
        }