MSBuild项目包含(通配符)未展开
本文关键字:通配符 项目 包含 MSBuild | 更新日期: 2023-09-27 18:15:05
这很奇怪。我们一直想弄清楚这个问题,但它真的没有任何意义。
我们的web项目导入了一个target文件,该文件的目标如下所示:
<Target Name="CSSCheckInternal">
<ItemGroup>
<CSSFiles Include="$(MSBuildProjectDirectory)'**'*.css" />
</ItemGroup>
<CSSChecker Files="@(CSSFiles)" />
</Target>
目前,一个分支正在完美地构建,按预期执行任务;但是另一个分支在上面的目标上失败了。
失败的原因是当任务接收到@(CSSFiles)
项时,似乎没有扩展成ITaskItem
数组。
任务写如下(直到我得到FullPath元数据的点):
public class CSSChecker : Task
{
[Required]
public ITaskItem[] Files
{
get;
set;
}
public override bool Execute()
{
string fullFilePath = null;
if (Files != null)
{
foreach (var item in Files)
{
fullFilePath = item.GetMetadata("FullPath");
if(!File.Exists(fullFilePath))
throw new InvalidOperationException(
string.Format("{0} does not exist", fullFilePath));
//rest of the code elided
失败的构建是在最后一行抛出InvalidOperationException
,像这样:
文件不存在:C:'Code'Project'**'*.css
因此,MSBuild似乎不是在Include
属性中扩展通配符,而是仅仅传递字符串,从而在任务上仅创建一个ITaskItem
。
目标文件夹在磁盘上不存在,损坏的项目文件和工作的项目文件之间的唯一区别是单个文件包含在项目文件的更早的地方。
更新我在twitter上问Sayed Hashimi(写了MSBuild书),并通过它,尝试取出**
文件夹通配符,现在它开始工作了。这实际上并不合适,因为任务意味着在项目之间可重用。但它似乎与此有关。
结束更新
请如果有人知道在什么情况下MSBuild不会正确扩展通配符,这将是一个很大的帮助!
我已经弄清楚了-我不得不删除我的项目目录中的obj'文件夹,突然文件夹通配符又开始工作了。
对于我的情况的简短回答是,如果任何路径太长,MSBuild的通配符处理代码似乎会完全崩溃,并且只是不构建项目组。
这里的问题是我是如何创建那么长的路径的?好吧,我没有。它是内置的web发布任务——我是这样使用的(对于我们所做的自定义部署):
<MSBuild Projects="$(Proj)" Properties="Platform=$(Platform);
Configuration=$(Configuration);DeployOnBuild=true;PackageAsSingleFile=False;
AutoParameterizationWebConfigConnectionStrings=False" />
当你做PackageAsSingleFile=False
时,我用它来防止构建zip,因为我想要网站可部署,在obj文件夹中,你会得到这样的文件夹结构:
[Project_Dir]'obj'[configuration]'Package'PackageTemp'[Project Dir]'[output *]
如果[Project_Dir]是c:'my project'
,那么临时包文件的基本文件夹将是c:'my project'obj'debug'Package'PackageTemp'c_c'my project'
。
正如你所看到的,这已经是一个相当深的文件夹结构了,实际上项目通常不是驱动器根目录下的顶级文件夹。
我发现,在使用这种部署方法的一些项目中,由于路径太长,在资源管理器或命令行中删除obj'
文件夹变得不可能。为了解决这个问题,我所做的是将尽可能多的父文件夹重命名为1
,以便缩短完整路径,然后进行删除。例如,在前面的示例中,我将重命名如下:
c:'my project'obj'1'1'1'1'1
效果很好。
你可以想象——如果项目从一个足够深的文件夹开始——那么为发布任务生成的项目的最终路径将变得非常长。我发现,如果我只是在VS内使用Publish
任务,这实际上会在发布期间导致错误-但似乎以我上面显示的方式炮击MSBuild,实际上以某种方式回避了文件夹最大路径限制。我很快就会做一个项目来证明这一点。
所以,在我的情况下,我不得不重写我的任务,以获取要处理的基本文件夹,然后让它递归遍历文件夹和文件本身,忽略它找到的任何'obj'文件夹。
我尝试使用'Exclude'属性排除obj文件夹中的任何文件,但没有任何区别(大概是因为两者都很糟糕!)。
我遇到了同样的问题,可以确认这也与长路径有关。我的在node_modules文件夹中,这个文件夹是由npm管理的。
我发现我能够删除长路径,而不必像Andreas使用rimraf工具那样重命名文件夹。如果出现任何错误,值得再试一次。
同样,如果你对真正的递归不感兴趣——比如你只是使用双星号(**)语法作为包含三个文件夹级别的快捷方式——那么你可以用一系列使用单星号(*)的表达式来替换双星号语法。
例如,假设实际上只需要包含三个级别的文件夹,您可以交换这个…
C:'**'*.*
…。
C:'*'*.*
C:'*'*'*.*
C:'*'*'*'*.*
此问题仅在递归搜索中的任何路径长于MAX_PATH
时发生。您可以通过尝试使用资源管理器在最深处的路径中创建一个目录来检查这一点,您将得到一个错误,告诉您路径太长,无法创建目录。或者,如果您想重现此问题,请使用CreateFileW()
和扩展的'''?'
路径语法创建一个比max路径长的路径。
MsBuild在再次调用FindNextFile()
之前必须内部检查长度,因为在procmon中您永远不会看到任何路径太长错误。您将看到的是,在路径太长之前的一层,它只是获得预期的ERROR_NO_MORE_FILES
,然后关闭搜索句柄,但甚至没有尝试下一层。一旦发生这种情况,MsBuild将放弃它的枚举,没有错误!
无效的NTFS文件系统链接也会导致此行为,例如包含的文件夹中的硬链接指向不存在的路径。