#region ======================== Namespaces using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; #endregion namespace mxd.ChangelogMaker { class Program { #region ======================== Constants private const string SEPARATOR = "--------------------------------------------------------------------------------"; #endregion #region ======================== Main static int Main(string[] args) { Console.WriteLine("Changelog Maker v03 by MaxED"); if(args.Length != 4) { return Fail("USAGE: ChangelogMaker.exe input output author revision_number\n" + "input: xml file generated by MakeRelese.bat\\MakeGITRelese.bat\n" + "output: directory to store Changelog.txt in\n" + "renameauthor: commit authors rename scheme. For example, \"m-x-d>MaxED|biwa>Boris\"\n" + "revision_number: latest revision number", 1); } string input = args[0]; string output = args[1]; string renameauthor = args[2]; // m-x-d>MaxED|biwa>Boris int revnum; if(!int.TryParse(args[3], out revnum)) return Fail("Unable to parse revision number from string '" + revnum + "'.", 4); if(!File.Exists(input)) return Fail("Input file '" + input + "' does not exist.", 2); if(!Directory.Exists(output)) return Fail("Output folder '" + output + "' does not exist.", 3); // Create author rename array, because git log can't decide how to call me... Dictionary authorrename = new Dictionary(StringComparer.OrdinalIgnoreCase); string[] parts = renameauthor.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); foreach(string ren in parts) { string[] rename = ren.Split(new[] { '>' }, StringSplitOptions.RemoveEmptyEntries); if(rename.Length == 2 && !string.IsNullOrEmpty(rename[0].Trim()) && !string.IsNullOrEmpty(rename[1].Trim())) { authorrename[rename[0].Trim()] = rename[1].Trim(); } else { Console.WriteLine("Invalid rename scheme: \"" + ren + "\""); } } //Replace bracket placeholders, because git log command doesn't escape xml-unfriendly chars like < or >... string inputtext = File.ReadAllText(input); inputtext = inputtext.Replace("<", "<").Replace(">", ">").Replace("&", "&").Replace("[OB]", "<").Replace("[CB]", ">"); XmlDocument log = new XmlDocument(); using(MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(inputtext))) { log.Load(stream); } StringBuilder result = new StringBuilder(1000); char[] messagetrim = {' ', '\r', '\n' }; foreach(XmlNode node in log.ChildNodes) { if(node.ChildNodes.Count == 0) continue; foreach (XmlNode logentry in node.ChildNodes) { string commit = (logentry.Attributes != null ? logentry.Attributes.GetNamedItem("commit").Value : "unknown"); DateTime date = DateTime.Now; string message = string.Empty; string author = string.Empty; // Add revision info... if(logentry.Attributes != null) { var revinfo = log.CreateAttribute("revision"); revinfo.Value = revnum.ToString(); logentry.Attributes.SetNamedItem(revinfo); } foreach(XmlNode value in logentry.ChildNodes) { switch(value.Name) { case "author": if(authorrename.ContainsKey(value.InnerText)) { author = authorrename[value.InnerText]; value.InnerText = author; // save author } else { author = value.InnerText; } break; case "date": date = Convert.ToDateTime(value.InnerText); break; case "msg": message = value.InnerText.Trim(messagetrim); value.InnerText = message; // also save trimmed message break; } } result.Append("R" + revnum) .Append(" | ") .Append(commit) .Append(" | ") .Append(author) .Append(" | ") .Append(date.ToShortDateString()) .Append(", ") .Append(date.ToShortTimeString()) .Append(Environment.NewLine) .AppendLine(SEPARATOR) .Append(message) .Append(Environment.NewLine) .Append(Environment.NewLine) .Append(Environment.NewLine); // Decrease revision number... revnum--; } break; } // Save modified xml log.Save(input); //Save result string outputpath = Path.Combine(output, "Changelog.txt"); File.WriteAllText(outputpath, result.ToString()); Console.WriteLine("Saved '" + outputpath + "'"); //All done return 0; } #endregion private static int Fail(string message, int exitcode) { Console.WriteLine(message + "\nPress any key to quit"); Console.ReadKey(); return exitcode; } } }