using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
namespace ILLink.Tasks
{
///
/// This class exists as a workaround. It strips the publish
/// dependency file of assemblies excluded from the publish
/// output by the linker. Ideally we would pass appropriate
/// parameters to the task that generates the deps file in
/// the first place, instead of rewriting it. We may be
/// ablee to do this once
/// https://github.com/dotnet/sdk/pull/1052 is merged.
///
public class DepsJsonLinker : Task
{
[Required]
public ITaskItem InputDepsFilePath { get; set; }
[Required]
public ITaskItem OutputDepsFilePath { get; set; }
[Required]
public ITaskItem[] ManagedPublishAssemblies { get; set; }
[Required]
public ITaskItem[] KeptAssemblies { get; set; }
public override bool Execute()
{
string inputFile = InputDepsFilePath.ItemSpec;
string outputFile = OutputDepsFilePath.ItemSpec;
string[] keptAssemblies = KeptAssemblies.Select(a => a.ItemSpec).ToArray();
string[] allAssemblies = ManagedPublishAssemblies.Select(a => a.ItemSpec).ToArray();
string[] removedAssemblies = allAssemblies.Except(keptAssemblies).ToArray();
var removedAssembliesSet = new HashSet (removedAssemblies, StringComparer.InvariantCultureIgnoreCase);
JObject o = JObject.Parse (File.ReadAllText (inputFile));
JObject targets = (JObject)o["targets"];
// Remove targets
foreach (JProperty target in targets.Children()) {
JEnumerable children = target.Value.Children ();
for (int i = 0; i < children.Count(); ++i) {
//foreach (JProperty subtarget in target.Value.Children()) {
var subtarget = (JProperty) children.ElementAt (i);
string name = subtarget.Name.Substring (0, subtarget.Name.IndexOf ('/'));
if (removedAssembliesSet.Contains (name + ".dll")) {
subtarget.Remove ();
i--;
continue;
}
// Remove dependencies
var dependencies = subtarget.Value["dependencies"];
if (dependencies != null) {
for (int j = 0; j < dependencies.Count (); ++j) {
var dependency = ((JProperty)dependencies.ElementAt (j));
if (removedAssembliesSet.Contains (dependency.Name + ".dll")) {
dependency.Remove ();
j--;
continue;
}
}
}
// Remove runtimes
var runtimes = subtarget.Value["runtime"];
if (runtimes != null) {
for (int j = 0; j < runtimes.Count (); ++j) {
var runtime = ((JProperty)runtimes.ElementAt (j));
string runtimeFileName = runtime.Name.Substring (runtime.Name.LastIndexOf ('/') + 1);
if (removedAssembliesSet.Contains (runtimeFileName)) {
runtime.Remove ();
j--;
continue;
}
}
}
}
}
// Remove libraries
JObject libraries = (JObject)o["libraries"];
JEnumerable libraryChildren = libraries.Children ();
for (int i = 0; i < libraryChildren.Count (); ++i) {
var library = (JProperty)libraryChildren.ElementAt (i);
string name = library.Name.Substring (0, library.Name.IndexOf ('/'));
if (removedAssembliesSet.Contains (name + ".dll")) {
library.Remove ();
i--;
continue;
}
}
File.WriteAllText (outputFile, o.ToString ());
return true;
}
}
}