ShiftOS-C-/source/Baseclass.Contrib.Nuget.Output.targets

228 lines
9.8 KiB
Text
Raw Normal View History

2016-07-06 13:13:15 -04:00
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- ============================================================ -->
<!-- Build targets -->
<!-- ============================================================ -->
<!--
Is run once after build, checks if the project's nuget package's .nuspec depends on Baseclass.Contrib.Nuget.Output and copies everything which is in the
output folder to the builds OutDir.
-->
<Target Name="CopyToOutput" AfterTargets="Compile" DependsOnTargets="CollectNugetOutputFiles">
<Copy SourceFiles="@(NugetOutputFiles)" DestinationFiles="@(NugetOutputFiles->'$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<!--
Is run once after clean, delete all files that match files collected by the CollectNugetOutputFiles task.
-->
<Target Name="CleanOutput" AfterTargets="Clean" DependsOnTargets="CollectNugetOutputFiles">
<Delete Files="@(NugetOutputFiles->'$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<!--
Is run once per file which has been deleted by the CleanOutput target, if the containing folder is empty it gets deleted.
-->
<Target Name="CleanEmptyFolder" Inputs="@(NugetOutputFiles)" Outputs="%(Identity).Dummy" AfterTargets="CleanOutput">
<ItemGroup>
<EmptyCheck Include="$(OutDir)%(NugetOutputFiles.RecursiveDir)**\*.*" />
</ItemGroup>
<RemoveDir Condition="'@(EmptyCheck)' == '' And '%(NugetOutputFiles.RecursiveDir)' != ''" Directories="$(OutDir)%(NugetOutputFiles.RecursiveDir)" />
</Target>
<!-- ============================================================ -->
<!-- Web publication targets -->
<!-- ============================================================ -->
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
$(PipelineCollectFilesPhaseDependsOn);
CollectNugetPackageFiles;
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>
<!--
Is run once during the PipelineCollectFilesPhase to fill FilesForPackagingFromProject with the files from NugetOutputFiles
-->
<Target Name="CollectNugetPackageFiles" DependsOnTargets="CollectNugetOutputFiles">
<ItemGroup>
<FilesForPackagingFromProject Include="@(NugetOutputFiles)" >
<DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<!-- ============================================================ -->
<!-- Common targets -->
<!-- ============================================================ -->
<ItemGroup>
<NupkgFiles Include="$(MSBuildThisFileDirectory)\..\..\..\*\*.nupkg"/>
</ItemGroup>
<ItemGroup>
<PackageFiles Include="$(MSBuildProjectDirectory)\packages.config"/>
</ItemGroup>
<!--
Is run once to compute the NugetOutputFiles item from the NuGet dependencies of the project
-->
<Target Name="CollectNugetOutputFiles">
<Message Text="Collecting NuGet output files for $(MSBuildProjectName):" />
<PackageFilter PackageConfigs="@(PackageFiles)" NugetPackages="@(NupkgFiles)">
<Output ItemName="FilteredNugetPackages" TaskParameter="Result" />
</PackageFilter>
<Message Text="@(FilteredNugetPackages->'%(RecursiveDir)%(Filename)%(Extension)', '%0D%0A')" />
<Message Text="Total filtered packages : @(FilteredNugetPackages->Count())" />
<ItemGroup>
<NugetOutputFiles Include="%(FilteredNugetPackages.RootDir)%(FilteredNugetPackages.Directory)\output\**\*.*" />
</ItemGroup>
<Message Text="@(NugetOutputFiles->'%(RecursiveDir)%(Filename)%(Extension)', '%0D%0A')" />
<Message Text="Total files collected : @(NugetOutputFiles->Count())" />
</Target>
<!--
Filter the NugetPackages list to only include nuget packages referenced in the PackageConfigs list which depend on Baseclass.Contrib.Nuget.Output
-->
<UsingTask TaskName="PackageFilter" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<PackageConfigs ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<NugetPackages ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Result ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Xml"/>
<Reference Include="System.Xml.Linq"/>
<Reference Include="WindowsBase" />
<Using Namespace="System" />
<Using Namespace="System.Collections.Generic" />
<Using Namespace="System.IO" />
<Using Namespace="System.IO.Packaging" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Threading" />
<Using Namespace="System.Xml" />
<Code Type="Fragment" Language="cs">
<![CDATA[
var usedPackages = new HashSet<string>(); // packaged used by the project
try
{
foreach (var packageConfig in PackageConfigs)
{
var path = packageConfig.GetMetadata("FullPath");
var xml = new XmlDocument();
xml.LoadXml(File.ReadAllText(path));
var deps = xml.GetElementsByTagName("package");
foreach (XmlNode dep in deps)
{
if (dep.Attributes == null)
{
continue;
}
var id = dep.Attributes.GetNamedItem("id").Value;
if ("Baseclass.Contrib.Nuget.Output".Equals(id))
{
continue;
}
var version = dep.Attributes.GetNamedItem("version").Value;
var s = string.Format("{0}.{1}", id, version);
usedPackages.Add(s);
}
}
}
catch (Exception e)
{
Log.LogError("Failed to load package files: {0}", e.Message);
return false;
}
var usedNugetPackages = new List<ITaskItem>(); // list of nuget packages used by the project
try
{
foreach (var nugetPackage in NugetPackages)
{
var path = nugetPackage.GetMetadata("FullPath");
var parts = path.Split(Path.DirectorySeparatorChar);
usedNugetPackages.AddRange(from part in parts where usedPackages.Contains(part) select nugetPackage);
}
}
catch (Exception e)
{
Log.LogError("Failed to filter nuget specs: {0}", e.Message);
return false;
}
var result = new List<ITaskItem>(); // list of nuget packages used by the project that depends on Baseclass.Contrib.Nuget.Output
foreach (var nugetPackage in usedNugetPackages)
{
var path = nugetPackage.GetMetadata("FullPath");
var nupkgpath = Path.GetDirectoryName(path);
using (var archive = Package.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var nuspec = archive.GetParts().Single(part => part.Uri.ToString().EndsWith(".nuspec"));
var nugetSpec = Path.Combine(nupkgpath, Path.GetFileName(nuspec.Uri.ToString()));
// use a mutex to ensure that only one process unzip the nuspec
// and that one process do not start reading it due to its existence while another one is still writing it.
Mutex mut = new Mutex(false, "UnzipNuSpec");
try
{
mut.WaitOne();
if (!File.Exists(nugetSpec))
{
// unpack the nuget spec file from the package
try
{
using (var outputstream = new FileStream(nugetSpec, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
using (var nspecstream = nuspec.GetStream())
{
nspecstream.CopyTo(outputstream);
}
}
}
catch (IOException)
{
if (!File.Exists(nugetSpec))
{
throw;
}
}
}
}
finally
{
mut.ReleaseMutex();
}
var xml = new XmlDocument();
xml.LoadXml(File.ReadAllText(nugetSpec));
var deps = xml.GetElementsByTagName("dependency");
foreach (XmlNode dep in deps)
{
if (dep.Attributes == null)
{
continue;
}
var id = dep.Attributes.GetNamedItem("id").Value;
if ("Baseclass.Contrib.Nuget.Output".Equals(id))
{
result.Add(new TaskItem(nugetPackage));
break;
}
}
}
}
Result = result.ToArray();
return true;
]]>
</Code>
</Task>
</UsingTask>
</Project>