【问题标题】:Fake Glob operator (!!) not expanding directory paths假 Glob 运算符 (!!) 不扩展目录路径
【发布时间】:2018-07-09 16:54:30
【问题描述】:

我有一种情况,在假脚本中,我试图使用 Glob (!!) 运算符从路径中获取所有单元测试 dll。

问题是在我的机器上 glob 扩展不起作用,在其他类似的 Windows 10 机器上工作,它很好并且可以找到 dll。

下面是一个例子:

let path = [function to generate path]
trace path [would look something like "c:\git\project\src\**\*UnitTest*"]
!! path.ToLower()
|> Seq.iter (fun file -> trace file ) [this would not output anything]

我尝试了很多方法:

  • 卸载旧版本的 F#
  • 重新安装最新版本
  • 确保 F# 在我的路径中

我使用的软件版本是:

  • 假v4.63.2
  • Windows 10
  • F#4.1

不会引发错误或异常。
如果是 F# 或 Fake 问题,解决问题的最佳方法是什么?
我怎样才能知道 F# Fake 使用的是哪个版本?

更新
我重新安装了 F# 4.1 并使用 fsi.exe 执行了测试,并使用以下命令:

Microsoft (R) F# Interactive version 4.1
<snip>
#r @"packages/FAKE/tools/FakeLib.dll";;
open Fake;;
!! "**\*UnitTests.dll" |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll

!! "**\*UnitTests.dll".ToLower() |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll

已找到所有测试 dll,无论是否调用 ToLower()

当我从脚本中删除 ToLower() 时,它现在可以在我的机器上运行。

但是,在其他人的机器上删除 path 上的 ToLower() 会导致他们找不到任何文件。

那么,Fake 是否使用了不同版本的 fsi.exe
我已经打开了一个 github 问题,看看是否可以对此有所了解:https://github.com/fsharp/FAKE/issues/1772

【问题讨论】:

  • 您看到的行为是什么?您的示例中的路径是真实路径吗?因为如果是这样,我认为它需要反斜杠转义
  • 这个字符串应该抛出,因为它包含无效的转义序列
  • 实际上,好点 - 我们使用函数来确定路径。所以我会换个例子
  • 您写道“……在我的机器上,glob 扩展不起作用,在其他类似的机器上正常工作。”这对我来说似乎是非常重要的一点。您的机器可能有些不同,脚本可能没问题。如果您的机器中的某个文件夹丢失或命名为其他文件夹,则 glob 将扩展为一个空列表,这就是没有打印任何内容的原因。您能否仔细检查计算机上是否存在 C: 根目录下的每个文件夹?并且没有一些奇怪的文件夹权限会阻止读取一个文件夹?
  • 我在示例中遗漏了一个细节,因为在做原始帖子时我面前没有代码,请参阅帖子中的更新。

标签: f# f#-fake


【解决方案1】:

使用以下脚本,我能够重现该问题并确定问题是由于 Windows 10 如何处理路径中 company 名称的原始大小写造成的。

我通过在文件路径表达式中将company名称更改为**来确认这一点,操作员工作并找到了所有的dll。

我记得我把公司名称的大写从大写改为小写。如果我删除路径上的ToLower(),则脚本可以正常工作并找到所有 dll。

这个隐藏的问题,结合FAKE does a case sensitive search 的方式,也无济于事。

Powershell

packages\FAKE\tools\FAKE.exe glob.test.fsx

glob.test.fsx

#r @"packages/FAKE/tools/FakeLib.dll"
open Fake

let thePath = """C:\git\company/projectname/**/bin/Debug/*UnitTests.dll"""

sprintf "the path is %s" thePath |> trace 

!! thePath.ToLower() |> Seq.iter (fun f -> trace f)

我查看了 ProcMon 中执行的进程,没有看到目录的原始大小写。 NTFS 文件系统仍然将此目录视为其原始外壳(请参阅下面的 cmets)。

我每隔几个月重新映像一次我的机器,所以它很快就会消失,但很高兴了解发生了什么。

感谢所有帮助缩小问题范围的人。

【讨论】:

  • 没有“某处”。 NTFS 保留文件名的大小写,即使它不使用区分大小写的匹配。你不应该必须使用ToLower()。如果这样做,则意味着 glob 运算符的代码中存在错误。 NTFS 只提供简单的模式匹配。 Glob 运算符使用字符串比较过滤文件。看起来其中一些是区分大小写的
  • BTW Linux 文件系统区分大小写,这意味着Companycompany 是不同的,您甚至可以将这两个文件夹放在同一个根目录下。而不是使用ToLower(),您应该确保大小写在所有情况下都是正确的。例如,如果 path 名称是大写的,ToLower() 将无济于事。
  • 最后,Glob 运算符确实执行了case-sensitive match
【解决方案2】:

在 F# 和所有 .NET 语言中一样,反斜杠用于字符串中的转义序列。

您需要转义反斜杠或使用逐字字符串,例如:

let path = "c:\\git\\project\\src\\**\\*UnitTest*"

let path = @"c:\git\project\src\**\*UnitTest*"

Fake 也可以使用正斜杠:

let path = "c:/git/project/src/**/*UnitTest*"

如果您希望构建脚本在 Linux 上运行,则无论如何都必须使用正斜杠。

更好的选择是使用 relative 路径。您的构建脚本很可能存储在您的项目文件夹中。你可以写

let path = "src/**/*UnitTest*"

【讨论】:

  • 感谢您的帮助,我已经发布了问题所在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多