summaryrefslogtreecommitdiff
path: root/Tools/BinPlace.targets
blob: f93f0ff687994e8a129dd6c5950ee2a8ae9cc671 (plain)
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
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Binplacing targets and properties -->
  <PropertyGroup>
    <BinPlaceUseHardlinksIfPossible Condition="'$(BinPlaceUseHardlinksIfPossible)' == ''">true</BinPlaceUseHardlinksIfPossible>
    <EnableBinPlacing Condition="'$(EnableBinPlacing)' == '' AND ('$(BinPlaceRef)' == 'true' OR '$(BinPlaceRuntime)' == 'true' OR '$(BinPlaceTest)' == 'true')">true</EnableBinPlacing>
  </PropertyGroup>

  <Target Name="BinPlace"
          DependsOnTargets="GetBinPlaceConfiguration;BinPlaceFiles;BinPlaceProps"
          AfterTargets="CopyFilesToOutputDirectory"
          Condition="'$(EnableBinPlacing)' == 'true'" />

  <Target Name="BinPlaceFiles"
          Condition="'@(BinPlaceDir)' != ''"
          DependsOnTargets="GetBinPlaceItems"
          Inputs="@(BinPlaceDir);%(BinPlaceDir.ItemName);%(BinPlaceDir.Identity)"
          Outputs="unused" >

    <PropertyGroup>
      <_BinPlaceItemName>%(BinPlaceDir.ItemName)</_BinPlaceItemName>
      <_BinPlaceItemName Condition="'$(_BinPlaceItemName)' == ''">BinPlaceItem</_BinPlaceItemName>
      <_BinPlaceDir>%(BinPlaceDir.Identity)</_BinPlaceDir>
    </PropertyGroup>

    <ItemGroup>
      <!-- Temporary collection to allow dynamic include name. -->
      <_BinPlaceItems Include="@($(_BinPlaceItemName))" />
      <BinPlaceItemsWithFullTargetPath Include="@(_BinPlaceItems)">
        <TargetPath Condition="'%(_BinPlaceItems.TargetPath)' != ''">%(_BinPlaceItems.TargetPath)</TargetPath>
        <TargetPath Condition="'%(_BinPlaceItems.TargetPath)' == ''">%(Filename)%(Extension)</TargetPath>
      </BinPlaceItemsWithFullTargetPath>
    </ItemGroup>

    <Message Importance="low" Text="BinPlaceDir: $(_BinPlaceDir)" />

    <Copy SourceFiles="@(BinPlaceItemsWithFullTargetPath)"
          DestinationFiles="@(BinPlaceItemsWithFullTargetPath -> '$([MSBuild]::EnsureTrailingSlash('$(_BinPlaceDir)'))%(TargetPath)')"
          SkipUnchangedFiles="true"
          OverwriteReadOnlyFiles="true"
          Retries="$(CopyRetryCount)"
          RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
          UseHardlinksIfPossible="$(BinPlaceUseHardlinksIfPossible)">
      <Output TaskParameter="DestinationFiles" ItemName="FileWrites" />
    </Copy>
  </Target>

  <UsingTask TaskName="SaveItems" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.Tasks.dll"/>
  <Target Name="BinPlaceProps"
          Condition="'@(PackageFileDir)' != ''"
          DependsOnTargets="GetBinPlaceItems"
          Inputs="%(PackageFileDir.Identity);%(PackageFileDir.ItemName)"
          Outputs="unused"  >
    <ItemGroup>
      <!-- in the case of an overlapping batch (eg: multiple configurations using same directory)
           use the first -->
      <_packageFileDir Include="@(PackageFileDir->Distinct())" />
    </ItemGroup>

    <PropertyGroup>
      <_propsFilename>$(TargetName).$(TargetGroup)-$(OSGroup)</_propsFilename>
      <_propsFilename Condition="'$(TargetName)' == ''">$(MSBuildProjectName).$(TargetGroup)-$(OSGroup)</_propsFilename>
      <_projectDirLength>$(ProjectDir.Length)</_projectDirLength>
    </PropertyGroup>

    <PropertyGroup>
      <_BinPlaceItemName>%(_packageFileDir.ItemName)</_BinPlaceItemName>
      <_BinPlaceItemName Condition="'$(_BinPlaceItemName)' == ''">BinPlaceItem</_BinPlaceItemName>
    </PropertyGroup>

    <ItemGroup>
      <_itemsToSave Include="@($(_BinPlaceItemName))">
        <!-- intentionally empty: to be set by pkgproj -->
        <TargetPath></TargetPath>
        <TargetFramework>%(_packageFileDir.BuildConfiguration_NuGetTargetMonikerShort)</TargetFramework>
      </_itemsToSave>

      <!-- Include doc files. -->
      <_docFiles Condition="'$(BinPlaceRef)' == 'true'" Include="$(XmlDocDir)/**/$(TargetName).xml" />
      <_docFiles>
        <SubFolder Condition="'%(RecursiveDir)' != ''">/$([System.String]::new('%(RecursiveDir)').TrimEnd('\').TrimEnd('/'))</SubFolder>
      </_docFiles>
      <_docFiles>
        <TargetFramework>%(_packageFileDir.BuildConfiguration_NuGetTargetMonikerShort)</TargetFramework>
      </_docFiles>
      <_itemsToSave Include="@(_docFiles)"/>

    </ItemGroup>

    <Message Importance="low" Text="PackageFileDir: @(PackageFileDir)" />

    <SaveItems ItemName="%(_packageFileDir.SaveItemName)"
               Items="@(_itemsToSave)"
               Files="%(_packageFileDir.Identity)\$(_propsFilename).props">
      <Output TaskParameter="Files" ItemName="FileWrites" />
    </SaveItems>
  </Target>

  <Target Name="GetBinPlaceItems" DependsOnTargets="GetCopyToOutputDirectoryItems">
    <ItemGroup>
      <BinPlaceItem Condition="Exists('$(TargetPath)')" Include="$(TargetPath)" />
      <BinPlaceItem Condition="Exists('$(TargetDir)$(TargetName).pdb')" Include="$(TargetDir)$(TargetName).pdb" />
      <BinPlaceItem Condition="'$(BinPlaceReferenceCopyLocalPaths)' != 'false'" Include="@(ReferenceCopyLocalPaths)" />
      <BinPlaceItem Condition="'$(BinPlaceCopyToOutputDirectoryItems)' != 'false'" Include="@(AllItemsFullPathWithTargetPath)" />
    </ItemGroup>
  </Target>

  <UsingTask TaskName="FindBestConfigurations" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.Tasks.dll"/>
  <Target Name="GetBinPlaceConfiguration" DependsOnTargets="GetBuildConfigurations">
    <!-- find which, if any, build configuration of this project is best
         for each binplace configuration -->
    <FindBestConfigurations Properties="@(Property)"
                            PropertyValues="@(PropertyValue)"
                            SupportedConfigurations="$(_AllBuildConfigurations)"
                            Configurations="@(BinPlaceConfiguration)">
      <Output TaskParameter="BestConfigurations" ItemName="_bestBinlaceConfigurations" />
    </FindBestConfigurations>

    <ItemGroup>
      <_currentBinPlaceConfigurations Include="@(_bestBinlaceConfigurations)" Condition="'%(Identity)' == '$(Configuration)' OR '%(Identity)-$(ConfigurationGroup)' == '$(Configuration)'" />

      <BinPlaceDir Condition="'$(BinPlaceTest)' == 'true'" Include="@(_currentBinPlaceConfigurations->'%(TestPath)')" />
      <BinPlaceDir Condition="'$(BinPlaceRuntime)' == 'true'" Include="@(_currentBinPlaceConfigurations->'%(RuntimePath)')" />
      <BinPlaceDir Condition="'$(BinPlaceRef)' == 'true'" Include="@(_currentBinPlaceConfigurations->'%(RefPath)')" />

      <PackageFileDir Condition="'$(BinPlaceRuntime)' == 'true'" Include="@(_currentBinPlaceConfigurations->'%(PackageFileRuntimePath)')">
        <SaveItemName Condition="'%(_currentBinPlaceConfigurations.SaveItemName)' == ''">LibFile</SaveItemName>
      </PackageFileDir>
      <PackageFileDir Condition="'$(BinPlaceRef)' == 'true'" Include="@(_currentBinPlaceConfigurations->'%(PackageFileRefPath)')">
        <SaveItemName Condition="'%(_currentBinPlaceConfigurations.SaveItemName)' == ''">RefFile</SaveItemName>
      </PackageFileDir>

      <!-- permit BinplaceConfigurations to define SetProperties metadata,
           set those properties when BinplaceConfiguration is active -->
      <_binplacePropertyTuples Include="%(_currentBinPlaceConfigurations.SetProperties)" />

      <_binplaceSetProperty Condition="'%(_binplacePropertyTuples.Identity)' != ''"
                            Include="$([System.String]::new('%(_binplacePropertyTuples.Identity)').Split('=')[0])">
        <Value>$([System.String]::new('%(_binplacePropertyTuples.Identity)').Split('=')[1])</Value>
      </_binplaceSetProperty>
    </ItemGroup>

    <CreateProperty Value="%(_binplaceSetProperty.Value)" Condition="'@(_binplaceSetProperty)' != ''" >
      <Output TaskParameter="Value" PropertyName="%(_binplaceSetProperty.Identity)" />
    </CreateProperty>
  </Target>

  <!-- IncrementalClean and CoreClean only clean paths under Intermediate or OutDir, handle additional paths -->
  <ItemGroup>
    <AdditionalCleanDirectories Include="@(BinPlaceConfiguration->'%(RefPath)')" />
    <AdditionalCleanDirectories Include="@(BinPlaceConfiguration->'%(RuntimePath)')" />
    <AdditionalCleanDirectories Include="@(BinPlaceConfiguration->'%(PackageFileRefPath)')" />
    <AdditionalCleanDirectories Include="@(BinPlaceConfiguration->'%(PackageFileRuntimePath)')" />
    <AdditionalCleanDirectories Include="@(BinPlaceConfiguration->'%(TestPath)')" />
  </ItemGroup>

  <Target Name="_CleanGetCurrentAdditionalFileWrites" BeforeTargets="_CleanGetCurrentAndPriorFileWrites" Condition="'@(AdditionalCleanDirectories)' != ''">
    <!-- find files under paths we care about and add them to _CleanCurrentFileWrites to ensure they are written to the file list -->
    <FindUnderPath Path="%(AdditionalCleanDirectories.Identity)" Files="@(FileWrites)" UpdateToAbsolutePaths="true">
      <Output TaskParameter="InPath" ItemName="_CleanCurrentFileWrites" />
    </FindUnderPath>
  </Target>

  <!-- delete files under our AdditionalCleanDirectories on Incremental clean -->
  <Target Name="IncrementalCleanAdditionalDirectories" BeforeTargets="IncrementalClean" Condition="'@(AdditionalCleanDirectories)' != ''">
    <ItemGroup>
      <_CleanOrphanAdditionalFileWrites Include="@(_CleanPriorFileWrites)" Exclude="@(_CleanCurrentFileWrites)" />
    </ItemGroup>
    <FindUnderPath Path="%(AdditionalCleanDirectories.Identity)" Files="@(_CleanOrphanAdditionalFileWrites)">
      <Output TaskParameter="InPath" ItemName="_CleanOrphanFileWritesInAdditionalDirectories" />
    </FindUnderPath>

    <!-- Delete the orphaned files.  IncrementalClean will remove these from the file list -->
    <Delete Files="@(_CleanOrphanFileWritesInAdditionalDirectories)" TreatErrorsAsWarnings="true">
      <Output TaskParameter="DeletedFiles" ItemName="_CleanOrphanFilesDeleted" />
    </Delete>
  </Target>

  <!-- delete files under our AdditionalCleanDirectories on CoreClean -->
  <Target Name="CleanAdditionalDirectories" AfterTargets="CoreClean" Condition="'@(AdditionalCleanDirectories)' != ''">
    <FindUnderPath Path="%(AdditionalCleanDirectories.Identity)" Files="@(_CleanUniqueRemainingFileWrites)">
      <Output TaskParameter="InPath" ItemName="_CleanUniqueRemainingFileWritesInAdditionalDirectories"/>
    </FindUnderPath>

    <Delete Files="@(_CleanUniqueRemainingFileWritesInAdditionalDirectories)" TreatErrorsAsWarnings="true">
      <Output TaskParameter="DeletedFiles" ItemName="_CleanUniqueRemainingFileWritesInAdditionalDirectoriesDeleted" />
    </Delete>

    <!-- Create a list of everything that wasn't deleted. -->
    <ItemGroup>
      <_CleanRemainingFileWritesAfterCleanAdditionalDirectories Include="@(_CleanUniqueRemainingFileWrites)" Exclude="@(_CleanUniqueRemainingFileWritesInAdditionalDirectoriesDeleted)"/>
    </ItemGroup>

    <!-- Remove duplicates. -->
    <RemoveDuplicates Inputs="@(_CleanRemainingFileWritesAfterCleanAdditionalDirectories)">
      <Output TaskParameter="Filtered" ItemName="_CleanAdditionalDirectoriesUniqueRemainingFileWrites"/>
    </RemoveDuplicates>

    <!-- Make sure the directory exists. -->
    <MakeDir Directories="$(IntermediateOutputPath)"/>

    <!-- Write new list of current files back to disk. -->
    <WriteLinesToFile File="$(IntermediateOutputPath)$(CleanFile)" Lines="@(_CleanAdditionalDirectoriesUniqueRemainingFileWrites)" Overwrite="true" />
  </Target>
</Project>