所以这就是我想要做的事情:
我想要一个构建脚本,它将xcopy将遗留winform应用程序的构建输出部署到给定目录。我想指定一个不覆盖的文件列表(一些配置文件)。
我宁愿让不覆盖的文件列表作为参数传递,而不是硬编码。
这似乎真的很难。这是我到目前为止所做的:
<!-- A property that is passed a semicolon delimited list of file names -->
<PropertyGroup>
<ProtectedFiles/>
</PropertyGroup>
<--! An ItemGroup to pick up the files>
<ItemGroup>
<FilesToDelete Include=$(DeploymentTargetFolder)\*.* Exclude="@(ProtectedFiles->'$(DeployTargetFolder)\%(identity)')"
<ItemGroup/>
<--! the delete isn't working, so I will stop just with that to keep the code brief -->
<Delete Files="@(FilesToDelete)"/>
删除只会忽略排除文件并删除所有内容
有更好的方法吗?它似乎并不太疯狂 - 我只想
答案 0 :(得分:1)
您的特定标记的第一个问题似乎会使MsBuild $(properties)与MsBuild %(items)和MsBuild @(itemgroups)混淆。
ProtectedFiles是一个属性:
<!-- A property that is passed a semicolon delimited list of file names -->
<PropertyGroup>
<ProtectedFiles/>
</PropertyGroup>
但它被视为一个项目,并且没有任何%item.metadata:
<--! An ItemGroup to pick up the files>
<ItemGroup>
<FilesToDelete Include=$(DeploymentTargetFolder)\*.* Exclude="@(ProtectedFiles->'$(DeployTargetFolder)\%(identity)')"
<ItemGroup/>
将以下标记保存为“foo.xml”,然后调用“ msbuild.exe foo.xml ”并观察输出:
<Project ToolsVersion="4.0" DefaultTargets="foo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FilesProp>FileA.txt;FileB.txt</FilesProp>
</PropertyGroup>
<ItemGroup>
<ProtectedFiles Include="FileA.txt" />
<ProtectedFiles Include="FileA.txt" />
</ItemGroup>
<Target Name="foo">
<Message Importance="high" Text="ProtectedFiles ItemGroup: @(ProtectedFiles)" />
<Message Importance="high" Text="ProtectedFiles ItemGroup transform: @(ProtectedFiles->'%(Identity)')" />
<Message Importance="high" Text="FilesProp Property: $(FilesProp)" />
<Message Importance="high" Text="FilesProp Property: @(FilesProp->'%(FilesProp.Identity)')" />
</Target>
</Project>
将产生以下输出:
foo:
ProtectedFiles ItemGroup: FileA.txt;FileA.txt
ProtectedFiles ItemGroup transform: FileA.txt;FileA.txt
FilesProp Property: FileA.txt;FileB.txt
FilesProp Property:
如果您无法更改设计并需要转换包含以分号分隔的文件路径列表的Property,请使用MsBuild <CreateItem /> task。
将此标记添加到Foo目标之后发生的foo.xml,然后再次调用msbuild,但使用“bar”目标(例如 msbuild.exe foo.xml / t:bar )
<Target Name="bar">
<CreateItem Include="$(FilesProp)">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles ItemGroup: @(TheFiles)" Importance="high" />
<Message Text="Output each item: %(TheFiles.Identity)" Importance="high" />
</Target>
将产生以下输出:
bar:
TheFiles ItemGroup: FileA.txt;FileB.txt
Output each item: FileA.txt
Output each item: FileB.txt
接下来你应该重新考虑你的一些假设。我不认为文件扩展名应该是决定更新哪些文件的决定因素,而是你应该依赖于MsBuild能够逐步构建任务,只有当输入比输出更新时才能执行任务。您可以使用配置为跳过未更改文件的MsBuild <Copy /> task来执行此操作。
将此标记添加到上面的Xml文件中,然后修改$(SourceFolder)和$(TargetFolder)以指向要递归复制的源文件夹,以及放置文件的目标文件夹。使用“ msbuild.exe foo.xml / t:部署”构建并观察输出。
<Target Name="Deployment">
<PropertyGroup>
<SourceFolder>c:\sourcefolder\</SourceFolder>
<TargetFolder>c:\destinationfolder\</TargetFolder>
</PropertyGroup>
<CreateItem Include="$(SourceFolder)\**\*.*">
<Output TaskParameter="Include" ItemName="FilesToCopy" />
</CreateItem>
<Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(TargetFolder)%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
如果不修改任何源文件,请再次运行该命令并注意没有复制文件。
修改源文件夹中的文件,然后再次运行该命令。请注意,只复制了更新的文件?
我希望这能让你走上正轨。
答案 1 :(得分:0)
似乎有一个已经存在的帖子,类似于此。请查看此Trying to exclude certain extensions doing a recursive copy (MSBuild)