0.15.2 中 GetFiles 的重大变化无法排除文件夹

Breaking change in GetFiles with 0.15.2 can't exclude folders

我不记得在哪里,但找到了一个如何从搜索中排除文件夹的示例。我们的问题是搜索 node_modules 会导致长路径异常。

Func<IFileSystemInfo, bool> exclude_node_modules = fileSystemInfo=>!fileSystemInfo.Path.FullPath.Contains("node_modules");

var solutions = GetFiles("./**/*.sln", exclude_node_modules);

任何解决此问题的帮助都会有所帮助。

为了加速文件系统的递归遍历,Cake 利用 .NET 内置的功能来实现这一点,但它受到 Windows 旧的 260 个字符限制的限制。 因此,当它在大多数用例中快得多时,它会在太深的文件夹结构上失败,例如 Node 模块可以引入。

您可以通过逐个文件夹迭代并在输入之前应用谓词排除哪个文件夹来解决此问题。

在我的示例中,使用了以下文件夹结构

Repo directory
    |   build.cake
    |   test.sln
    |
    \---src
        |   test.sln
        |
        +---proj1
        |   |   test.sln
        |   |
        |   \---node_modules
        |           node.sln
        |
        +---proj2
        |   |   test.sln
        |   |
        |   \---node_modules
        |           node.sln
        |
        +---proj3
        |   |   test.sln
        |   |
        |   \---node_modules
        |           node.sln
        |
        \---proj4
            |   test.sln
            |
            \---node_modules
                    node.sln

我们想要的是从 repo 目录递归地找到所有解决方案,而不是进入 node_modules 目录并且找不到 node.sln

下面建议的解决方案是创建一个名为 RecursiveGetFile 的实用方法来为您执行此操作:

// find and iterate all solution files
foreach(var filePath in RecursiveGetFile(
    Context,
    "./",
    "*.sln",
    path=>!path.EndsWith("node_modules", StringComparison.OrdinalIgnoreCase)
    ))
{
    Information("{0}", filePath);
}


// Utility method to recursively find files
public static IEnumerable<FilePath> RecursiveGetFile(
    ICakeContext context,
    DirectoryPath directoryPath,
    string filter,
    Func<string, bool> predicate
    )
{
    var directory = context.FileSystem.GetDirectory(context.MakeAbsolute(directoryPath));
    foreach(var file in directory.GetFiles(filter, SearchScope.Current))
    {
        yield return file.Path;
    }
    foreach(var file in directory.GetDirectories("*.*", SearchScope.Current)
        .Where(dir=>predicate(dir.Path.FullPath))
        .SelectMany(childDirectory=>RecursiveGetFile(context, childDirectory.Path, filter, predicate))
        )
    {
        yield return file;
    }
}

此脚本的输出类似于

RepoRoot/test.sln
RepoRoot/src/test.sln
RepoRoot/src/proj1/test.sln
RepoRoot/src/proj2/test.sln
RepoRoot/src/proj3/test.sln
RepoRoot/src/proj4/test.sln

这通过跳过已知的麻烦制造者来解决 260 个字符的问题,如果其他未知路径有相同的问题则不会解决。