Skip to content

Instantly share code, notes, and snippets.

@BobStrogg
Last active June 12, 2017 15:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BobStrogg/161d3d80e0fd9af501a39eefdb9990f6 to your computer and use it in GitHub Desktop.
Save BobStrogg/161d3d80e0fd9af501a39eefdb9990f6 to your computer and use it in GitHub Desktop.
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