Skip to content

Instantly share code, notes, and snippets.

@a-h
Created October 17, 2014 09:02
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-h/e49022a04050be0c6f69 to your computer and use it in GitHub Desktop.
Save a-h/e49022a04050be0c6f69 to your computer and use it in GitHub Desktop.
Handle merge conflicts in NuGet packages.config files
using System.Xml.Serialization;
using System.IO;
public static class Program
{
void Main()
{
AcceptLatestPackages(@"C:\projects\MergeMigrations_AddTableB\");
}
private void AcceptLatestPackages(string directory)
{
foreach(var subdirectory in Directory.GetDirectories(directory))
{
AcceptLatestPackages(subdirectory);
}
foreach(var file in Directory.GetFiles(directory, "packages.config", SearchOption.AllDirectories))
{
string workingPackagesConfig = file + ".working";
bool workingPackagesConfigExists = File.Exists(workingPackagesConfig);
string incomingPackagesConfig = Directory.GetFiles(directory, "packages.config.merge-right.*").FirstOrDefault();
bool incomingPackagesConfigExists = string.IsNullOrEmpty(incomingPackagesConfig) ? false : File.Exists(incomingPackagesConfig);
if(workingPackagesConfigExists && incomingPackagesConfigExists)
{
var updatedPackagesConfig = ResolveConflict(workingPackagesConfig, incomingPackagesConfig);
// Overwrite the packages.config file which has merge markers in it.
// e.g.
// <<<<<<< .working
// <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
// =======
// <package id="Newtonsoft.Json" version="6.0.5" targetFramework="net45" />
// >>>>>>> .merge-right.r44653
Packages.Save(updatedPackagesConfig, file);
}
}
}
public Packages ResolveConflict(string workingPackagesConfig, string incomingPackagesConfig)
{
var working = Packages.Load(workingPackagesConfig).ToDictionary(p => p.Id);
var incoming = Packages.Load(incomingPackagesConfig).ToDictionary(p => p.Id);
var toAddFromIncoming = new List<Package>();
var toReplaceWithIncoming = new List<Package>();
foreach(var incomingKey in incoming.Keys)
{
if(working.ContainsKey(incomingKey))
{
// Check versions.
var workingPackage = working[incomingKey];
var incomingPackage = incoming[incomingKey];
// If the incoming version is higher, use it.
if(incomingPackage.Version.CompareTo(workingPackage.Version) > 0)
{
toReplaceWithIncoming.Add(incomingPackage);
}
}
else
{
// If there's a new package to merge, add it in.
toAddFromIncoming.Add(incoming[incomingKey]);
}
}
foreach(var itemToAdd in toAddFromIncoming)
{
working.Add(itemToAdd.Id, itemToAdd);
}
foreach(var itemToReplace in toReplaceWithIncoming)
{
working.Remove(itemToReplace.Id);
working.Add(itemToReplace.Id, itemToReplace);
}
var rv = new Packages();
rv.AddRange(working.Select(g => g.Value).OrderBy(p => p.Id));
return rv;
}
}
[XmlRoot("packages")]
public class Packages : List<Package>
{
public static Packages Load(string fileName)
{
using(var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
var serializer = new XmlSerializer(typeof(Packages));
return (Packages)serializer.Deserialize(fs);
}
}
public static void Save(Packages packages, string fileName)
{
using(var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
Save(packages, fs);
}
}
public static void Save(Packages packages, Stream fs)
{
var serializer = new XmlSerializer(typeof(Packages));
// Remove namespace attributes.
var ns = new XmlSerializerNamespaces();
ns.Add("","");
serializer.Serialize(fs, packages, ns);
}
public override string ToString()
{
var ms = new MemoryStream();
Packages.Save(this, ms);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
[XmlType("package")]
public class Package
{
[XmlAttribute("id")]
public string Id { get; set; }
[XmlAttribute("version")]
public string Version { get; set; }
[XmlAttribute("targetFramework")]
public string TargetFramework { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment