aboutsummaryrefslogtreecommitdiff
path: root/source/packages/Baseclass.Contrib.Nuget.Output.2.0.0/build/net40/Baseclass.Contrib.Nuget.Output.targets
blob: efe8e996b36c1590e9b246e6d6961e89186c0fc9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<?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>