Without editing the csproj file, get MSBuild to co

2019-07-19 07:17发布

问题:

Question

Ultimately, we would like to use the command line to copy all files that a csproj has marked as Content, while preserving the directory structure, and without editing the original csprog file.

We have seen How can I get MSBuild to copy all files marked as Content to a folder, preserving folder structure? This doesn't work for us, because it involves editing the csproj file. We want to avoid doing that.

MSBuild?

We've thought of using msbuild via the command line but we don't know how to ask it to do just the equivalent of this:

<Target Name="CopyContentFiles">
  <Copy SourceFiles="@(Content)"
        DestinationFiles="@(Content->'$(DestFolder)%(RelativeDir)%(Filename)%(Extension)')"/>
</Target>

In other words, we would like to use the command line to define a target (not just specify one) from at the command line. E.g. in pseudo-code we want this:

msbuild MyApp.csproj /t:"Copy SourceFiles="@(Content)" DestinationFiles=..."

XCopy?

We've also thought of using xcopy though we haven't determined how to ask it to only copy files that the csproj marks as Content.

回答1:

I use PowerShell.

If you have a script Get-VSProjectItems.ps1 like this:

param(
    [Parameter(Mandatory=$true)] $project
)

$ErrorActionPreference = 'stop';
$project = (resolve-path $project).Path;
$projectDir = Split-Path $project -Parent;
$ns = @{
    msb = 'http://schemas.microsoft.com/developer/msbuild/2003';
}

Select-Xml -Path:$project -XPath:'//msb:Content' -Namespace:$ns |
    Select-Object -ExpandProperty:Node | 
    % {
        New-Object psobject -Property:@{
            RelPath = $_.Include;
            Directory = (Split-Path -Parent $_.Include);
            FullName = Join-Path $projectDir $_.Include;
        }
    }

Then copying the content files becomes as simple as piping the output to a script block that creates the target folder structure and copies the file (nb: fragment below assumes you want to recreate the directory tree in current working directory):

.\Get-VSProjectItems.ps1 ..\SomeProject\SomeProject.csproj | % { 
    [void](mkdir $_.Directory -ErrorAction:SilentlyContinue); 
    copy-item $_.fullname $_.relpath;
}