28

这很奇怪。我们一直在试图弄清楚它,但它真的没有任何意义。

我们的 Web 项目导入了一个目标文件,该文件的目标类似于:

<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 不会正确扩展通配符,那将是一个很大的帮助!

4

4 回答 4

23

我已经想通了——我不得不删除我的项目目录中的 obj\ 文件夹,突然文件夹通配符又开始工作了。

对我的情况的简短回答是,如果任何路径太长,MSBuild 的通配符处理代码似乎会完全失效,并且不会构建项目组。

这里的问题是我是如何设法创建那么长的路径的?好吧,我没有。这是内置的网络发布任务——我像这样使用它(用于我们所做的自定义部署):

<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

哪个效果很好。

你可以想象——如果项目从一个足够深的文件夹开始——那么为发布任务生成的项目的最终路径将变得很长。我发现,如果我只是Publish在 VS 中使用该任务,这实际上会在发布期间导致错误 - 但似乎以我上面显示的方式对 MSBuild 进行炮击,实际上以某种方式回避了文件夹最大路径限制。我将组织一个项目来证明这一点。

因此,就我而言,我不得不重写我的任务以获取要处理的基本文件夹,然后让它通过文件夹和文件本身递归,忽略它找到的任何“obj”文件夹。

我尝试使用'Exclude' 属性排除obj 文件夹中的任何文件,但没有任何区别(可能是因为两者都被淘汰了!)。

于 2013-05-24T15:44:31.697 回答
8

我遇到了同样的问题,可以确认它也与长路径有关。我的位于由 npm 管理的 node_modules 文件夹中。

我发现我可以删除长路径,而无需像 Andreas使用rimraf工具那样重命名文件夹。如果您遇到任何错误,值得再次尝试。

此外,如果您感兴趣的实际上不是真正的递归 - 假设您仅使用双星号 (**) 语法作为包含三个文件夹级别的快捷方式 - 那么您可以用一系列的替换双星号语法使用单个星号 (*) 的表达式。

例如,假设实际上只需要包含三个级别的文件夹,您可以交换这个...

C:\**\*.*

...为了这。

C:\*\*.*
C:\*\*\*.*
C:\*\*\*\*.*
于 2015-07-27T10:56:17.057 回答
5

仅当递归搜索中的任何路径长于MAX_PATH. 您可以通过尝试使用资源管理器在最深路径中创建目录来检查这一点,您将收到一条错误消息,告诉您路径太长并且无法创建目录。CreateFileW()或者,如果您想重现此问题,请使用扩展\\\?\路径语法创建一个比最大路径长的路径。

MsBuild 必须在再次调用之前在内部检查长度,FindNextFile()因为您在 procmon 中永远不会看到任何路径太长的错误。您会看到,在路径太长之前上一级它只是获得了预期的ERROR_NO_MORE_FILES,然后关闭搜索句柄,但甚至不费心尝试下一级。一旦发生这种情况,MsBuild 将毫无错误地放弃其枚举!

于 2014-04-02T09:26:36.980 回答
3

无效的 NTFS 文件系统链接也会导致此行为,例如包含文件夹中的硬链接指向不存在的路径。

于 2014-10-08T19:28:02.650 回答