Copy task doesn't make it easy to copy the entire directory, it forces you to mess with wildcards etc. and it's gnarly
We should consider adding a new SourceFolder parameter on the Copy task that, if specified, pre-populates the SourceFiles with the entire directory. Of course SourceFolder and SourcesFiles should be mutually exclusive.
Microsoft.Build.Artifacts can do this, as a workaround. Still agree it would be nice for the copy to be built in and something like Microsoft.Build.Artifacts would just call it.
Ugh, we should really fix this. Copying some files into a directory and preserving the directory structure is super painful.
I'm imagining two new properties, SourceRoot and DestinationRoot, that when set, act as the corresponding roots, and the relative path from SourceRoot is preserved for each file.
This way this won't be a breaking change.
or maybe just SourceRoot and PreserveRelativePaths combined with the existing DestinationFolder.
When I eventually come back here, here's how to do it:
<Project DefaultTargets="Copy">
<PropertyGroup>
<SourceDir>C:\temp\a</SourceDir>
<DestinationDir>C:\temp\b</DestinationDir>
</PropertyGroup>
<Target Name="Copy">
<!--
PITFALL: if this runs during evaluation, the files might not exist on disk yet.
So ensure this runs during execution and the glob is expanded immediately
before the actual copy.
-->
<ItemGroup>
<SourceFile Include="$(SourceDir)\**\*" />
<DestinationFile Include="@(SourceFile->'$(DestinationDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
</ItemGroup>
<Copy SourceFiles="@(SourceFile)"
DestinationFiles="@(DestinationFile)"
SkipUnchangedFiles="true" />
</Target>
</Project>
Another issue is that with the current approach you can't copy symbolic links from a source to a destination directory, the link gets resolved and the actual file copied instead of the symlink.
This will probably need to wait for BCL support (https://github.com/dotnet/runtime/issues/24271) though.
@KirillOsenkov did you try Microsoft.Build.Artifacts?
No, I鈥檓 using vanilla MSBuild.
I just corrected the snippet I posted earlier to expand the globs during execution (inside the target), and not during evaluation. When it ran during evaluation the project may be evaluated too early, and the glob might not pick up the files which are copied later by another target. Expanding the glob from inside the target is more reliable.
Most helpful comment
When I eventually come back here, here's how to do it: