这很奇怪。我们一直试图弄清楚它,但它确实没有任何意义。
我们的网络项目会导入目标文件,其目标类似于:
<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
。
磁盘上存在目标文件夹 ,并且损坏的项目文件和工作文件之间的唯一区别是单个文件包含在项目文件的更早版本中。
我asked Sayed Hashimi on twitter(写了MSBuild book)并通过它尝试取出**
文件夹通配符,它现在开始工作了。这不太合适,因为任务可以在项目之间重复使用。但这似乎与此有关。
如果有人知道在什么情况下MSBuild不能正确扩展通配符,那将是一个很大的帮助!
答案 0 :(得分:18)
我已经弄明白了 - 我必须删除项目目录中的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'文件夹。 / p>
我尝试使用'Exclude' attribute排除obj文件夹中的所有文件,但它没有任何区别(大概是因为两者都被淘汰了!)。
答案 1 :(得分:7)
我遇到了同样的问题,可以确认它也与长路径有关。我在node_modules文件夹中,由npm管理。
我发现我可以删除长路径,而无需使用rename folders as Andreas did工具rimraf。如果您遇到任何错误,请再试一次。
另外,如果它实际上并不是您感兴趣的真正递归 - 比如说您只使用双星号(**)语法作为包含三个文件夹级别的快捷方式 - 那么您可以将双星号语法替换为使用单个星号(*)的一系列表达式。
例如,假设实际上只需要包含三个级别的文件夹,您可以交换它...
C:\**\*.*
......为此。
C:\*\*.*
C:\*\*\*.*
C:\*\*\*\*.*
答案 2 :(得分:5)
只有在递归搜索中的任何路径长于MAX_PATH
时才会出现此问题。您可以通过尝试使用资源管理器在最深的路径中创建目录来检查这一点,您将收到一条错误消息,告诉您路径太长并且无法创建目录。或者,如果要重现此问题,请使用CreateFileW()
扩展\\\?\
路径语法创建比最大路径长的路径。
MsBuild必须在再次调用FindNextFile()
之前在内部检查长度,因为你从未在procmon中看到任何路径太长的错误。你会看到的是,在路径太长之前,它只是获得了预期的ERROR_NO_MORE_FILES
,然后关闭了搜索句柄,但是甚至不打算尝试下一个级别。一旦发生这种情况,MsBuild将放弃其枚举而没有错误!
答案 3 :(得分:2)
无效的NTFS文件系统链接也会导致此行为,例如,包含的文件夹中的硬链接指向不存在的路径。