Пример #1
0
        public string RevToDate(string rev)
        {
            var stamp = Convert.ToInt32(GitStats.GetPipeOutput(new[]
            {
                $"git log --pretty=format:%%at \"{rev}\" -n 1"
            }));

            return(DateTimeOffset.FromUnixTimeSeconds(stamp).DateTime.ToString("%Y-%m-%d"));
        }
Пример #2
0
        private void GetExtensions()
        {
            Extensions = new DictionaryWithDefault <string, Extension>();
            var lines = GitStats.GetPipeOutput(new[]
            {
                "git ls-tree -r -z HEAD"
            }).Split("\0").ToList().Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();

            ;
            TotalFiles = lines.Length;
            Console.WriteLine($"Processing {TotalFiles} files in repo");
            foreach (var line in lines)
            {
                if (line.Length == 0)
                {
                    continue;
                }
                var    parts    = Regex.Split(line, "\\s+", RegexOptions.None);
                var    sha1     = parts[2];
                var    filename = parts[3];
                string ext;
                if (filename.IndexOf(".", StringComparison.Ordinal) == -1 ||
                    filename.IndexOf(".", StringComparison.Ordinal) == 0)
                {
                    ext = "";
                }
                else
                {
                    ext = filename.Substring(filename.LastIndexOf(".", StringComparison.Ordinal) + 1);
                }
                if (ext.Length > _configuration.MaxExtensionLength)
                {
                    ext = "";
                }
                if (!Extensions.ContainsKey(ext))
                {
                    Extensions[ext] = new Extension();
                }
                Extensions[ext].Files += 1;
                try
                {
                    Extensions[ext].Lines += GetLinesInBlob(sha1);
                }
                catch
                {
                    Console.WriteLine("Warning: Could not count lines for file \"%s\"", line);
                }
            }
        }
Пример #3
0
 private void GetTotalAuthors()
 {
     try
     {
         TotalAuthors = Convert.ToInt32(GitStats.GetPipeOutput(new[]
         {
             "git shortlog -s",
             "wc -l"
         }));
     }
     catch (Exception)
     {
         TotalAuthors = 0;
     }
 }
Пример #4
0
        public int GetLinesInBlob(string sha1)
        {
            if (Cache.LinesInBlob.TryGetValue(sha1, out var res))
            {
                return(res);
            }

            res = Convert.ToInt32(GitStats.GetPipeOutput(new[]
            {
                $"git cat-file blob {sha1}",
                "wc -l"
            }, PipingLevel.Minimal).Split()[0]);

            Cache.LinesInBlob[sha1] = res;

            return(res);
        }
Пример #5
0
        public int GetFilesInCommit(string rev)
        {
            if (Cache.FilesInTree.TryGetValue(rev, out var res))
            {
                return(res);
            }

            res = Convert.ToInt32(GitStats.GetPipeOutput(new[]
            {
                $"git ls-tree -r --name-only \"{rev}\"",
                "wc -l"
            }).Split("\n")[0]);

            Cache.FilesInTree[rev] = res;

            return(res);
        }
Пример #6
0
        private void GetFilesByStampAndTotalCommits(List <string> lines)
        {
            // TODO Optimize this, it's the worst bottleneck
            // outputs "<stamp> <files>" for each revision
            lines.Clear();
            FilesByStamp = new DictionaryWithDefault <DateTime, int>();
            var revLines = GitStats.GetPipeOutput(new[]
            {
                "git rev-list --remotes --pretty=format:\"%at %T\" HEAD",
                "grep -v ^commit"
            }).Trim().Split("\n");

            foreach (var revLine in revLines)
            {
                var tup2      = revLine.Split(" ");
                var time      = tup2[0];
                var rev       = tup2[1];
                var lineCount = GetFilesInCommit(rev);
                lines.Add($"{Convert.ToInt32(time)} {lineCount}");
            }

            TotalCommits = lines.Count;
            foreach (var line in lines)
            {
                var parts = line.Split(" ");
                if (parts.Length != 2)
                {
                    continue;
                }
                try
                {
                    FilesByStamp[DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(parts[0])).DateTime] = Convert.ToInt32(parts[1]);
                }
                catch (FormatException)
                {
                    Console.WriteLine("Warning: failed to parse line \"%s\"", line);
                }
            }
        }
Пример #7
0
        private void GetChangesByDateAndTotalLines()
        {
            // line statistics
            // outputs:
            //  N files changed, N insertions (+), N deletions(-)
            // <stamp> <author>
            ChangesByDate = new DictionaryWithDefault <DateTime, Change>();
            var lines = GitStats.GetPipeOutput(new[] { "git log --shortstat --pretty=format:\"%at %an\"" }).Split("\n")
                        .ToList();

            lines.Reverse();
            var files      = 0;
            var inserted   = 0;
            var deleted    = 0;
            var totalLines = 0;

            foreach (var line in lines)
            {
                if (line.Length == 0)
                {
                    files    = 0;
                    inserted = 0;
                    deleted  = 0;
                    continue;
                }
                if (line.IndexOf(" changed,", StringComparison.CurrentCultureIgnoreCase) == -1)
                {
                    var pos = line.IndexOf(" ", StringComparison.CurrentCultureIgnoreCase);
                    if (pos != -1)
                    {
                        try
                        {
                            var datetime = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(line.Substring(0, pos))).DateTime;
                            var author   = line.Substring(pos + 1);
                            ChangesByDate[datetime] = new Change
                            {
                                Files      = files,
                                Inserted   = inserted,
                                Deleted    = deleted,
                                TotalLines = totalLines
                            };
                            if (!Authors.ContainsKey(author))
                            {
                                Authors[author] = new Author();
                            }
                            Authors[author].LinesAdded   += inserted;
                            Authors[author].LinesRemoved += deleted;
                        }
                        catch (Exception)
                        {
                            Console.WriteLine($"Warning: unexpected line \"{line}\"");
                        }
                    }
                    else
                    {
                        Console.WriteLine($"Warning: unexpected line \"{line}\"");
                    }
                }
                else
                {
                    files    = GetIntFromStartOfRegex(line, "\\d+ file");
                    inserted = GetIntFromStartOfRegex(line, "\\d+ insertion");
                    deleted  = GetIntFromStartOfRegex(line, "\\d+ delet");

                    totalLines        += inserted;
                    totalLines        -= deleted;
                    TotalLinesAdded   += inserted;
                    TotalLinesRemoved += deleted;
                }
            }

            TotalLines = totalLines;
        }
Пример #8
0
        // Collect revision statistics
        // Outputs "<stamp> <date> <time> <timezone> <author> '<' <mail> '>'"
        private List <string> GetActivityDataAndAuthors()
        {
            var lines = GitStats.GetPipeOutput(new[]
            {
                "git rev-list --remotes --pretty=format:\"%at %ai %an <%aE>\" HEAD",
                "grep -v ^commit"
            }, PipingLevel.Full, true).Split("\n").ToList();

            foreach (var line in lines)
            {
                var parts = Regex.Split(line, "([01-9-:+]+ )").Where(x => !string.IsNullOrEmpty(x)).Select(s => s.Trim())
                            .ToArray();
                DateTime stamp;
                try
                {
                    stamp = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(parts[0])).DateTime;
                }
                catch (FormatException)
                {
                    stamp = DateTime.MinValue;
                }

                var timezone = parts[3];
                var tup1     = parts[4].Split("<");
                var author   = tup1[0];
                var mail     = tup1[1];
                author = author.TrimEnd();
                mail   = mail.TrimEnd('>');
                var domain = "?";
                if (mail.IndexOf("@", StringComparison.CurrentCultureIgnoreCase) != -1)
                {
                    domain = mail.Split("@")[1];
                }
                var date = stamp;
                // First and last commit stamp
                if (LastCommitStamp == DateTime.MinValue)
                {
                    LastCommitStamp = stamp;
                }
                FirstCommitStamp = stamp;
                // activity
                // hour
                var hour = date.Hour;
                ActivityByHourOfDay[hour] = ActivityByHourOfDay[hour] + 1;
                // most active hour?
                if (ActivityByHourOfDay[hour] > ActivityByHourOfDayBusiest)
                {
                    ActivityByHourOfDayBusiest = ActivityByHourOfDay[hour];
                }
                // day of week
                var day = (int)date.DayOfWeek - 1;
                ActivityByDayOfWeek[day] = ActivityByDayOfWeek[day] + 1;
                // domain stats
                if (!Domains.ContainsKey(domain))
                {
                    Domains[domain] = new Domain();
                }
                // commits
                Domains[domain].Commits = Domains[domain].Commits + 1;
                // hour of week
                if (!ActivityByHourOfWeek.ContainsKey(day))
                {
                    ActivityByHourOfWeek[day] = new DictionaryWithDefault <int, int>();
                }

                ActivityByHourOfWeek[day][hour] = ActivityByHourOfWeek[day][hour] + 1;
                // most active hour?
                if (ActivityByHourOfWeek[day][hour] > ActivityByHourOfWeekBusiest)
                {
                    ActivityByHourOfWeekBusiest = ActivityByHourOfWeek[day][hour];
                }
                // month of year
                var month = date.Month;
                ActivityByMonthOfYear[month] = ActivityByMonthOfYear[month] + 1;
                // yearly/weekly activity
                var yyw =
                    $"{date.Year}-{_calendar.GetWeekOfYear(date, _cultureInfo.DateTimeFormat.CalendarWeekRule, _cultureInfo.DateTimeFormat.FirstDayOfWeek)}";
                ActivityByYearWeek[yyw] = ActivityByYearWeek[yyw] + 1;
                if (ActivityByYearWeekPeak < ActivityByYearWeek[yyw])
                {
                    ActivityByYearWeekPeak = ActivityByYearWeek[yyw];
                }
                // author stats
                if (!Authors.ContainsKey(author))
                {
                    Authors[author] = new Author();
                }
                // commits
                if (Authors[author].LastCommitStamp == DateTime.MinValue)
                {
                    Authors[author].LastCommitStamp = stamp;
                }

                Authors[author].FirstCommitStamp = stamp;
                Authors[author].Commits          = Authors[author].Commits + 1;
                // author of the month/year
                var yymm = $"{date.Year}-{date.Month:D2}";
                if (AuthorOfMonth.ContainsKey(yymm))
                {
                    AuthorOfMonth[yymm][author] = AuthorOfMonth[yymm][author] + 1;
                }
                else
                {
                    AuthorOfMonth[yymm] = new DictionaryWithDefault <string, int> {
                        [author] = 1
                    }
                };
                CommitsByMonth[yymm] = CommitsByMonth[yymm] + 1;
                var yy = date.Year;
                if (AuthorOfYear.ContainsKey(yy))
                {
                    AuthorOfYear[yy][author] = AuthorOfYear[yy][author] + 1;
                }
                else
                {
                    AuthorOfYear[yy] = new DictionaryWithDefault <string, int> {
                        [author] = 1
                    }
                };
                CommitsByYear[yy] = CommitsByYear[yy] + 1;
                // authors: active days
                var yymmdd = date;
                if (Authors[author].LastActiveDay == DateTime.MinValue)
                {
                    Authors[author].LastActiveDay = yymmdd;
                    Authors[author].ActiveDays    = 1;
                }
                else if (yymmdd != Authors[author].LastActiveDay)
                {
                    Authors[author].LastActiveDay = yymmdd;
                    Authors[author].ActiveDays   += 1;
                }

                // project: active days
                if (yymmdd != LastActiveDay)
                {
                    LastActiveDay = yymmdd;
                    ActiveDays.Add(yymmdd);
                }

                // timezone
                CommitsByTimezone[timezone] = CommitsByTimezone[timezone] + 1;
            }

            return(lines);
        }
Пример #9
0
        private void GetTagData()
        {
            string[] parts;
            string   output;

            var lines = GitStats.GetPipeOutput(new[]
            {
                "git show-ref --tags"
            }).Split("\n").ToList();

            foreach (var line in lines)
            {
                if (line.Length == 0)
                {
                    continue;
                }
                var split = line.Split(" ");
                var hash  = split[0];
                var tag   = split[1];

                tag    = tag.Replace("refs/tags/", "");
                output = GitStats.GetPipeOutput(new[]
                {
                    $"git log \"{hash}\" --pretty=format:\"%at %an\" -n 1"
                });

                if (output.Length <= 0)
                {
                    continue;
                }

                parts = output.Split(" ");
                DateTime stamp;
                try
                {
                    stamp = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt32(parts[0])).DateTime;
                }
                catch (FormatException)
                {
                    stamp = DateTime.MinValue;
                }

                Tags[tag] = new Tag
                {
                    Stamp   = stamp, Hash = hash, Date = stamp,
                    Commits = 0, Authors = new Dictionary <string, int>()
                };
            }

            // Collect info on tags, starting from latest
            var tagsSortedByDateDesc = Tags.Select(el => (el.Value.Date, el.Key)).OrderBy(p1 => p1).Reverse()
                                       .Select(el => el.Key);

            foreach (var tag in tagsSortedByDateDesc.Reverse())
            {
                var cmd = string.Format($"git shortlog -s \"{tag}\"");
                output = GitStats.GetPipeOutput(new[] { cmd });
                if (output.Length == 0)
                {
                    continue;
                }
                var prev = tag;
                foreach (var line in output.Split("\n"))
                {
                    parts = Regex.Split(line, "\t", RegexOptions.None);
                    var commits = Convert.ToInt32(parts[0].Trim());
                    var author  = parts[1];
                    Tags[tag].Commits        += commits;
                    Tags[tag].Authors[author] = commits;
                }
            }
        }
Пример #10
0
        public void CreateGraphs(string path)
        {
            Console.WriteLine("Generating graphs...");
            // hour of day
            var f = new StreamWriter(path + "\\hour_of_day.plot");

            f.Write(GnuplotCommon);
            f.Write($@"
set output 'hour_of_day.{ImageType}'
unset key
set xrange [0.5:24.5]
set xtics 4
set grid y
set ylabel ""Commits""
plot 'hour_of_day.dat' using 1:2:(0.5) w boxes fs solid
");
            f.Close();
            // day of week
            f = new StreamWriter(path + "\\day_of_week.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'day_of_week.{ImageType}'
unset key
set xrange [0.5:7.5]
set xtics 1
set grid y
set ylabel ""Commits""
plot 'day_of_week.dat' using 1:2:(0.5) w boxes fs solid
");
            f.Close();
            // Domains
            f = new StreamWriter(path + "\\domains.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'domains.{ImageType}'
unset key
unset xtics
set grid y
set ylabel ""Commits""
plot 'domains.dat' using 2:3:(0.5) with boxes fs solid, '' using 2:3:1 with labels rotate by 45 offset 0,1
");
            f.Close();
            // Month of Year
            f = new StreamWriter(path + "\\month_of_year.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'month_of_year.{ImageType}'
unset key
set xrange [0.5:12.5]
set xtics 1
set grid y
set ylabel ""Commits""
plot 'month_of_year.dat' using 1:2:(0.5) w boxes fs solid
");
            f.Close();
            // commits_by_year_month
            f = new StreamWriter(path + "\\commits_by_year_month.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'commits_by_year_month.{ImageType}'
unset key
set xdata time
set timefmt ""%Y-%m""
set format x ""%Y-%m""
set xtics rotate by 90 15768000
set bmargin 5
set grid y
set ylabel ""Commits""
plot 'commits_by_year_month.dat' using 1:2:(0.5) w boxes fs solid
");
            f.Close();
            // commits_by_year
            f = new StreamWriter(path + "\\commits_by_year.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'commits_by_year.{ImageType}'
unset key
set xtics 1 rotate by 90
set grid y
set ylabel ""Commits""
set yrange [0:]
plot 'commits_by_year.dat' using 1:2:(0.5) w boxes fs solid
");
            f.Close();
            // Files by date
            f = new StreamWriter(path + "\\files_by_date.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'files_by_date.{ImageType}'
unset key
set xdata time
set timefmt ""%Y-%m-%d""
set format x ""%Y-%m-%d""
set grid y
set ylabel ""Files""
set xtics rotate by 90
set ytics autofreq
set bmargin 6
plot 'files_by_date.dat' using 1:2 w steps
");
            f.Close();
            // Lines of Code
            f = new StreamWriter(path + "\\lines_of_code.plot");
            f.Write(GnuplotCommon);
            f.Write($@"
set output 'lines_of_code.{ImageType}'
unset key
set xdata time
set timefmt ""%s""
set format x ""%Y-%m-%d""
set grid y
set ylabel ""Lines""
set xtics rotate by 90
set bmargin 6
plot 'lines_of_code.dat' using 1:2 w lines
");
            f.Close();
            Directory.SetCurrentDirectory(path);
            var matchingFiles = Glob.Files(path, "*.plot").ToArray();

            foreach (var file in matchingFiles)
            {
                var output = GitStats.GetPipeOutput(new[]
                {
                    Program.GnuPlotCmd + $" \"{file}\""
                });
                if (output.Length > 0)
                {
                    Console.WriteLine(output);
                }
            }
        }