/// <summary> /// Executes this action. /// </summary> /// <returns>Returns 0 to indicate success.</returns> public int Execute(CancellationToken cancellationToken) { string repositoryDir = RepoPath; while (!Directory.Exists(Path.Combine(repositoryDir, ".git"))) { repositoryDir = Path.GetDirectoryName(repositoryDir); if (repositoryDir == null) { log.Error("Directory {0} is not a git repository.", RepoPath); return(1); } } RepoPath = repositoryDir; if (FieldCount < 1 || FieldCount > 5) { log.Error("The argument for --fields ({0}) must be an integer between 1 and 5.", FieldCount); return(1); } if (!String.IsNullOrEmpty(PrintLog)) { int nLines = 0; if (!int.TryParse(PrintLog, out nLines) || nLines <= 0) { log.Error("The argument for --log ({0}) must be an integer greater than 0.", PrintLog); return(1); } return(DoPrintLog(cancellationToken)); } string versionString = null; using (GitVersionCalulator calc = new GitVersionCalulator(RepoPath)) { if (String.IsNullOrEmpty(Sha)) { versionString = calc.GetVersion().ToString(FieldCount); } else { versionString = calc.GetVersion(Sha).ToString(FieldCount); } } if (!String.IsNullOrEmpty(ReplaceFile)) { if (!File.Exists(ReplaceFile)) { log.Error("File '{0}' given in --replace argument could not be found.", Path.GetFullPath(ReplaceFile)); return(1); } int replaceLineCount = DoReplaceFile(ReplaceFile, versionString); if (replaceLineCount == 0) { log.Warning("Nothing to replace. '$(GitVersion)' was not found in {0}.", ReplaceFile); } else { log.Info("Replaced '$(GitVersion)' with '{0}' in {1} line(s) of {2}", versionString, replaceLineCount, ReplaceFile); } return(0); } log.Info(versionString); return(0); }
private static string TryReplaceMacro(string text, string ProjectDirectory) { if (string.IsNullOrEmpty(text)) { return(text); } // Find macro var match = Regex.Match(text, @"(.*)(?:\$\()(.*)(?:\))(.*)"); if (match == null || match.Groups.Count < 2) { return(text); } // Replace macro if (match.Groups[2].ToString() == "GitVersion") { using (GitVersionCalulator calc = new GitVersionCalulator(ProjectDirectory)) { SemanticVersion version = calc.GetVersion(); text = match.Groups[1].ToString() + version + match.Groups[3].ToString(); } } else { throw new NotSupportedException(string.Format("The macro \"{0}\" is not supported.", match.Groups[2].ToString())); } // Find "pre-processor funcions" match = Regex.Match(text, @"(.*)(?:\$\()(.*?),(.*)(?:\))(.*)"); // With text = "Rolf$(ConvertFourValue,1.0.0.69)Asger", this regex should return 4 matching groups: "Rolf", "ConvertFourValue", "1.0.0.69" and "Asger". if (match == null || match.Groups.Count < 4 || !match.Groups[2].Success || !match.Groups[3].Success) { return(text); } var plugins = PluginManager.GetPlugins <IVersionTryConverter>().Concat(PluginManager.GetPlugins <IVersionConverter>()); Type converter = plugins.FirstOrDefault(pt => pt.GetDisplayAttribute().Name == match.Groups[2].Value); SemanticVersion convertedVersion = null; var str = match.Groups[3].Value; if (converter != null) { object conv = Activator.CreateInstance(converter); if (conv is IVersionTryConverter cv2) { if (cv2.TryConvert(match.Groups[3].Value, out convertedVersion) == false) { throw new FormatException("Unable to convert version format: " + str); } } else if (conv is IVersionConverter cv1) { convertedVersion = cv1.Convert(str); } } if (convertedVersion != null) { text = match.Groups[1].Value + convertedVersion + match.Groups[4].Value; log.Warning("The version was converted from {0} to {1} using the converter '{2}'.", str, convertedVersion, converter.GetDisplayAttribute().Name); } else { throw new Exception(string.Format("No IVersionConverter found named \"{0}\". Valid ones are: {1}", match.Groups[2].Value, String.Join(", ", plugins.Select(p => $"\"{p.GetDisplayAttribute().Name}\"")))); } return(text); }
private int DoPrintLog(CancellationToken cancellationToken) { ConsoleColor defaultColor = Console.ForegroundColor; ConsoleColor graphColor = ConsoleColor.DarkYellow; ConsoleColor versionColor = ConsoleColor.DarkRed; using (GitVersionCalulator versionCalculater = new GitVersionCalulator(RepoPath)) using (LibGit2Sharp.Repository repo = new LibGit2Sharp.Repository(RepoPath)) { Commit tip = repo.Head.Tip; if (!string.IsNullOrEmpty(Sha)) { tip = repo.Lookup <Commit>(Sha); if (tip == null) { log.Error($"The commit with reference {Sha} does not exist in the repository."); return(1); } } IEnumerable <Commit> History = repo.Commits.QueryBy(new CommitFilter() { IncludeReachableFrom = tip, SortBy = CommitSortStrategies.Topological }); // Run through to determine max Position (number of concurrent branches) to be able to indent correctly later int maxLines = int.Parse(PrintLog); int lineCount = 0; Dictionary <Commit, int> commitPosition = new Dictionary <Commit, int>(); commitPosition.Add(History.First(), 0); int maxPosition = 0; foreach (Commit c in History) { cancellationToken.ThrowIfCancellationRequested(); if (maxPosition < commitPosition[c]) { maxPosition = commitPosition[c]; } if (!c.Parents.Any()) { // this is the very first commit in the repo. Stop here. maxLines = ++lineCount; break; } Commit p1 = c.Parents.First(); if (c.Parents.Count() > 1) { Commit p2 = c.Parents.Last(); if (commitPosition.ContainsKey(p1)) { if (commitPosition[p1] != commitPosition[c]) { int startPos = Math.Min(commitPosition[p1], commitPosition[c]); int endPos = Math.Max(commitPosition[p1], commitPosition[c]); commitPosition[c] = startPos; foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == endPos).ToList()) { commitPosition.Remove(kvp.Key); } } } if (!commitPosition.ContainsKey(p2)) { // move out to an position out for the new branch int newPosition = commitPosition[c] + 1; while (commitPosition.ContainsValue(newPosition) && (newPosition <= commitPosition.Values.Max())) { newPosition++; } commitPosition[p2] = newPosition; commitPosition[p1] = commitPosition[c]; } else if (!commitPosition.ContainsKey(p1)) { commitPosition[p1] = commitPosition[c]; } } else { if (!commitPosition.ContainsKey(p1)) { commitPosition[p1] = commitPosition[c]; } if (commitPosition[p1] != commitPosition[c]) { int startPos = Math.Min(commitPosition[p1], commitPosition[c]); int endPos = Math.Max(commitPosition[p1], commitPosition[c]); // c is now merged back, no need to keep track of it (or any other commit on this branch) // this way we can reuse the position for another branch foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == endPos).ToList()) { commitPosition.Remove(kvp.Key); } commitPosition[p1] = startPos; foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == startPos).ToList()) { if (kvp.Key != p1) { commitPosition.Remove(kvp.Key); } } } } if (++lineCount >= maxLines) { break; } } { maxPosition++; } { // Run through again to print lineCount = 0; commitPosition = new Dictionary <Commit, int>(); commitPosition.Add(History.First(), 0); HashSet <Commit> taggedCommits = repo.Tags.Select(t => t.Target.Peel <Commit>()).ToHashSet(); foreach (Commit c in History) { cancellationToken.ThrowIfCancellationRequested(); void DrawPositionSpacer(int fromPos, int toPos) { for (int i = fromPos; i < toPos; i++) { if (commitPosition.ContainsValue(i)) { Console.Write("\u2502 "); } else { Console.Write(" "); } } } void DrawMergePositionSpacer(int fromPos, int toPos) { for (int i = fromPos; i < toPos; i++) { if (commitPosition.ContainsValue(i)) { Console.Write("\u2502\u2500"); } else { Console.Write("\u2500\u2500"); } } } Console.ForegroundColor = graphColor; DrawPositionSpacer(0, commitPosition[c]); Console.ForegroundColor = defaultColor; if (taggedCommits.Contains(c)) { Console.Write("v "); } else { Console.Write("* "); } Console.ForegroundColor = graphColor; DrawPositionSpacer(commitPosition[c] + 1, maxPosition); Console.ForegroundColor = versionColor; Console.Write(versionCalculater.GetVersion(c).ToString(FieldCount)); Console.ForegroundColor = defaultColor; Console.Write(" - "); Console.Write(c.MessageShort.Trim()); if (++lineCount >= maxLines) { Console.WriteLine(); break; } if (c.Parents.Any()) { Commit p1 = c.Parents.First(); //Console.Write("Parent1: " + p1.Sha.Substring(0,8)); Console.WriteLine(); Console.ForegroundColor = graphColor; if (c.Parents.Count() > 1) { Commit p2 = c.Parents.Last(); int startPos; int endPos; if (commitPosition.ContainsKey(p1)) { if (commitPosition[p1] != commitPosition[c]) { startPos = Math.Min(commitPosition[p1], commitPosition[c]); // something we already printed has the current commit as its parent, draw the line to that commit now DrawPositionSpacer(0, startPos); // Draw ├─┘ Console.Write("\u251C\u2500"); endPos = Math.Max(commitPosition[p1], commitPosition[c]); DrawMergePositionSpacer(startPos + 1, endPos); Console.Write("\u2518 "); DrawPositionSpacer(endPos + 1, maxPosition); Console.WriteLine(); commitPosition[c] = startPos; foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == endPos).ToList()) { commitPosition.Remove(kvp.Key); } } } if (!commitPosition.ContainsKey(p2)) { DrawPositionSpacer(0, commitPosition[c]); // move out to an position out for the new branch int newPosition = commitPosition[c] + 1; while (commitPosition.ContainsValue(newPosition) && (newPosition <= commitPosition.Values.Max())) { newPosition++; } commitPosition[p2] = newPosition; commitPosition[p1] = commitPosition[c]; // Draw ├─┐ Console.Write("\u251C\u2500"); DrawMergePositionSpacer(commitPosition[c] + 1, commitPosition[p2]); Console.Write("\u2510 "); DrawPositionSpacer(commitPosition[p2] + 1, maxPosition); Console.WriteLine(); } else if (!commitPosition.ContainsKey(p1)) { commitPosition[p1] = commitPosition[c]; // this branch is merged several times startPos = Math.Min(commitPosition[p2], commitPosition[c]); DrawPositionSpacer(0, startPos); // draws something like: ├─┤ Console.Write("\u251C\u2500"); endPos = Math.Max(commitPosition[p2], commitPosition[c]); DrawMergePositionSpacer(startPos + 1, endPos); Console.Write("\u2524 "); DrawPositionSpacer(endPos + 1, maxPosition); Console.WriteLine(); } //else //{ // DrawPositionSpacer(0, commitPosition[p2]); // Console.Write("\u251C\u2500"); // DrawMergePositionSpacer(commitPosition[p2] + 1, commitPosition[c]); // Console.WriteLine("\u2524"); //} } else { if (!commitPosition.ContainsKey(p1)) { commitPosition[p1] = commitPosition[c]; } if (commitPosition[p1] != commitPosition[c]) { int startPos = Math.Min(commitPosition[p1], commitPosition[c]); DrawPositionSpacer(0, startPos); // Draw ├─┘ Console.Write("\u251C\u2500"); int endPos = Math.Max(commitPosition[p1], commitPosition[c]); DrawMergePositionSpacer(startPos + 1, endPos); Console.Write("\u2518 "); DrawPositionSpacer(endPos + 1, maxPosition); Console.WriteLine(); // c is now merged back, no need to keep track of it (or any other commit on this branch) // this way we can reuse the position for another branch foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == endPos).ToList()) { commitPosition.Remove(kvp.Key); } commitPosition[p1] = startPos; foreach (var kvp in commitPosition.Where((KeyValuePair <Commit, int> kvp) => kvp.Value == startPos).ToList()) { if (kvp.Key != p1) { commitPosition.Remove(kvp.Key); } } } } } } } } return(0); }