Skip to content

Instantly share code, notes, and snippets.

@teneko
Last active August 5, 2020 10:12
Show Gist options
  • Save teneko/d9cc2ca3c2d53c27322f19a0d5dc916d to your computer and use it in GitHub Desktop.
Save teneko/d9cc2ca3c2d53c27322f19a0d5dc916d to your computer and use it in GitHub Desktop.
Shadow Copy & Link
$(MSBuildProjectDirectory): NO trailing slash
$(MSBuildThisFileDirectory): HAS trailing slash
<!--
=================================================
WORK IN PROGRESS
Scenario: You have a MSBuild only project/package
but you need custom written msbuild tasks..
This set up requires you to create another
project.
But when you need the MSBuild only project in
solution you may face lock exceptions. This
solution tries to create a shadow copy of
the build artifacts and creates link files that
imports the original MSBuild .props and .targets
files.
=================================================
-->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TasksProjectFullPath>..\..\0.Tasks\src\Teronis.MSBuild.Packaging.PackExecutable.Tasks.csproj</TasksProjectFullPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(TasksProjectFullPath)">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
<GlobalPropertiesToRemove>TargetFramework</GlobalPropertiesToRemove>
<BuildProjectReferences>false</BuildProjectReferences>
<SetTargetFramework>TargetFrameworks=netcoreapp2.1;net472</SetTargetFramework>
</ProjectReference>
<None Include="build\**\*.props;build\**\*.targets">
<Pack>true</Pack>
<PackagePath>build</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\..\0.Tasks\src\bin\Debug\**\*">
<LinkPath>executables\any\%(RecursiveDir)</LinkPath>
<Link>%(LinkPath)\%(Filename)%(Extension)</Link>
<Pack>true</Pack>
<PackagePath>%(LinkPath)</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<PropertyGroup>
<_ShadowCopyPrefix>ShadowCopy-</_ShadowCopyPrefix>
</PropertyGroup>
<Target Name="MakeShadowCopy" AfterTargets="AfterBuild">
<PropertyGroup>
<_ShadowOutputDirName>$(_ShadowCopyPrefix)$([System.Guid]::NewGuid())</_ShadowOutputDirName>
</PropertyGroup>
<!--<WriteLinesToFile Lines="$(_ShadowOutputDirName)" File="$(BaseIntermediateOutputPath)RandomOutputPath.cache" />-->
<PropertyGroup>
<_ShadowCopyPath>$(OutputPath)..\$(_ShadowOutputDirName)\$(TargetFramework)\</_ShadowCopyPath>
<_ShadowLinkPath>$(OutputPath)..\ShadowLink\$(TargetFramework)\</_ShadowLinkPath>
</PropertyGroup>
<MakeDir Directories="$(_ShadowCopyPath)" />
<ItemGroup>
<_MovableFiles Include="$(OutputPath)**\*" />
</ItemGroup>
<Copy SourceFiles="@(_MovableFiles)" DestinationFiles="$(_ShadowCopyPath)%(RecursiveDir)%(Filename)%(Extension)" />
<ItemGroup>
<_ProjectFiles Include="$(_ShadowCopyPath)build\**\*.props;$(_ShadowCopyPath)build\**\*.targets" />
</ItemGroup>
<LinkShadowCopy ShadowLinkPath="$(_ShadowLinkPath)" ProjectFiles="@(_ProjectFiles)" />
</Target>
<!--DependsOnTargets="_GetTargetFrameworksOutput"-->
<Target Name="MyClean" BeforeTargets="Clean" >
<ItemGroup>
<_ShadowCopyDirectories Include="$([System.IO.Directory]::GetDirectories($(OutputPath)..,'$(_ShadowCopyPrefix)*-*-*-*-*'))" />
</ItemGroup>
<MSBuild Projects="$(TasksProjectFullPath)" Targets="_GetTargetFrameworksOutput">
<Output TaskParameter="TargetOutputs" ItemName="_TargetFrameworks" />
</MSBuild>
<!--<Message Text="ÖÖÖÖÖ %(_TargetFrameworks.Identity) %(_ShadowCopyDirectories.Identity)" Importance="high" />-->
<!--<CleanShadowCopies TargetFrameworks="@(_TargetFrameworks)" ShadowCopyDirectories="@(_ShadowCopyDirectories)" />-->
</Target>
</Project>
<Project>
<UsingTask
TaskName="LinkShadowCopy"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup>
<ShadowLinkPath ParameterType="System.String" Required="true" />
<ProjectFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
foreach (var projectFile in ProjectFiles) {
var recursiveDir = projectFile.GetMetadata("RecursiveDir");
var outputPath = Path.Combine(ShadowLinkPath, recursiveDir);
Directory.CreateDirectory(outputPath);
var importFullPath = projectFile.GetMetadata("FullPath");
var propsContent = $"<Project>\r\n<Import Project=\"{importFullPath}\" />\r\n</Project>";
var propsFileName = projectFile.GetMetadata("Filename");
var propsFileExtension = projectFile.GetMetadata("Extension");
var propsFile = Path.Combine(outputPath, propsFileName + propsFileExtension);
File.WriteAllText(propsFile, propsContent);
}
]]>
</Code>
</Task>
</UsingTask>
<UsingTask
TaskName="CleanShadowCopies"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup>
<TargetFrameworks ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<ShadowCopyDirectories ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
;
]]>
</Code>
</Task>
</UsingTask>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment