Last active
June 12, 2017 15:30
-
-
Save BobStrogg/161d3d80e0fd9af501a39eefdb9990f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var writeChanges = false; | |
var basePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), @"..\..")); | |
UpdateVersions(basePath, writeChanges); | |
} | |
void UpdateVersions(string basePath, bool writeChanges = false) | |
{ | |
var repo = new FileRepositoryBuilder().SetMustExist(true).SetWorkTree(basePath).Build(); | |
var git = new Git(repo); | |
var projectRegex = new Regex(@".*\..*proj", RegexOptions.Compiled); | |
var diffEntries = git.Diff().Call() | |
.ToLookup(de => GetFullPath(basePath, de.GetPath(GetBestChangeSide(de))), StringComparer.CurrentCultureIgnoreCase); | |
Func<string, XDocument> loadOld = p => | |
{ | |
if (diffEntries.Contains(p)) | |
{ | |
var diffEntry = diffEntries[p].First(); | |
if (diffEntry.GetOldId() != null) return OpenXml(repo, diffEntry.GetOldId().ToObjectId(), p).Result; | |
} | |
return null; | |
}; | |
var projects = Directory.GetFiles(basePath, "*.*proj", SearchOption.AllDirectories) | |
.ToDictionary(p => p, p => new Project(p, loadOld(p)), StringComparer.CurrentCultureIgnoreCase); | |
foreach (var project in projects.Values) | |
{ | |
foreach (var pr in project.Content.Elements("Project").Elements("ItemGroup").Elements("ProjectReference")) | |
{ | |
var path = GetFullPath(project.Folder, (string)pr.Attribute("Include")); | |
projects[path].Dependencies.Add(project); | |
} | |
} | |
var folders = projects.ToLookup(p => Path.GetDirectoryName(p.Key), p => p.Value); | |
foreach (var diffEntry in diffEntries) | |
{ | |
var projectFolder = Path.GetDirectoryName(diffEntry.Key); | |
while (projectFolder.Length > basePath.Length && Directory.GetFiles(projectFolder, "*.*proj").Length == 0) | |
{ | |
projectFolder = Path.GetDirectoryName(projectFolder); | |
} | |
if (projectFolder.Length > basePath.Length && folders.Contains(projectFolder)) | |
{ | |
foreach (var p in folders[projectFolder]) p.Touch(); | |
} | |
} | |
projects.Values.Where(p => p.Touched).Select(p => new { Folder = Path.GetFileName(p.Folder), Original = p.OriginalVersion?.ToString(), Version = p.Version?.ToString(), Changed = p.Changed }) | |
.Dump(writeChanges ? "Versions (WRITTEN)" : "Versions (not written)"); | |
diffEntries.Select(de => new { Folder = Path.GetDirectoryName(de.Key) }).Distinct().Dump("Changed folders"); | |
diffEntries.Select(de => new { File = de.Key, Type = de.First().GetChangeType() }).Distinct().Dump("Changed files"); | |
if (writeChanges) | |
{ | |
foreach (var p in projects.Values.Where(p => p.Touched)) p.Content.Save(p.Filename); | |
} | |
} | |
private DiffEntry.Side GetBestChangeSide(DiffEntry de) | |
{ | |
switch (de.GetChangeType()) | |
{ | |
case DiffEntry.ChangeType.DELETE: return DiffEntry.Side.OLD; | |
default: return DiffEntry.Side.NEW; | |
} | |
} | |
private string GetFullPath(string basePath, string filename) | |
{ | |
return Path.GetFullPath(Path.Combine(basePath, filename)); | |
} | |
class Project | |
{ | |
private const string versionElementName = "Version"; | |
private const string authorsElementName = "Authors"; | |
public string Filename { get; } | |
public string Folder { get; } | |
public XDocument Content { get; } | |
public Version OriginalVersion { get; } | |
public Version Version { get; private set; } | |
public bool Touched { get; private set; } | |
public bool Changed { get; private set; } | |
public HashSet<Project> Dependencies { get; } = new HashSet<Project>(); | |
public Project(string filename, XDocument oldContent = null) | |
{ | |
this.Filename = filename; | |
this.Folder = Path.GetDirectoryName(filename); | |
this.Content = XDocument.Load(filename); | |
var version = (string)PropertyElement(versionElementName); | |
if (oldContent != null) | |
{ | |
var oldVersion = (string)PropertyElement(oldContent, versionElementName); | |
if (oldVersion != null) | |
{ | |
this.OriginalVersion = new Version(oldVersion); | |
if (version == null) version = oldVersion; | |
else if (version != oldVersion) this.Touched = true; | |
} | |
} | |
if (version != null) this.Version = new Version(version); | |
if (this.OriginalVersion == null) this.OriginalVersion = this.Version; | |
} | |
public void Touch() | |
{ | |
if (!Touched && Version != null) | |
{ | |
Version = new Version(Version.Major, Version.Minor, Version.Build, Version.Revision + 1); | |
ReplaceValue(versionElementName, Version); | |
ReplaceValue(authorsElementName, "Western Digital"); | |
Touched = true; | |
Changed = true; | |
} | |
foreach (var d in Dependencies.Where(d => !d.Touched)) d.Touch(); | |
} | |
private void ReplaceValue(string name, object value) | |
{ | |
PropertyElement(name).ReplaceWith(new XElement(name, value)); | |
} | |
private XElement PropertyElement(string name) | |
{ | |
return PropertyElement(Content, name); | |
} | |
private static XElement PropertyElement(XDocument element, string name) | |
{ | |
return element.Elements("Project").Elements("PropertyGroup").Elements(name).FirstOrDefault(); | |
} | |
} | |
async Task<XDocument> OpenXml(Repository repo, ObjectId objectId, string path) | |
{ | |
using (var ms = new MemoryStream()) | |
{ | |
using (var stream = repo.HasObject(objectId) ? (Stream)repo.Open(objectId).OpenStream() : File.Exists(path) ? File.OpenRead(path) : null) | |
{ | |
if (stream != null) await stream.CopyToAsync(ms); | |
} | |
ms.Seek(0, SeekOrigin.Begin); | |
try | |
{ | |
return (ms.Length > 0) ? XDocument.Load(ms) : null; | |
} | |
catch (Exception ex) | |
{ | |
Encoding.UTF8.GetString(ms.ToArray()).Dump(); | |
path.Dump($"{objectId} {ex.Message}"); | |
throw; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment