请考虑以下事项:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Shell.Exec("mkdir","exampleDirectory")
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
上面的脚本运行正常,但是当我在这样的目标中移动Shell.Exec时:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory")
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
我最后得到一个错误:
FsiEvaluationException:
Error:
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
unit
but here has type
int
Output: [Loading C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx]
Input: C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx
\Arguments:
C:\fsi.exe
Exception: Yaaf.FSharp.Scripting.FsiEvaluationException: Error while compiling or executing fsharp snippet. ---> System.Exception: Operation failed. The error text has been print the error stream. To return the corresponding FSharpErrorInfo use the EvalInteractionNonThrowing, EvalScriptNonThrowing or EvalExpressionNonThrowing
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.commitResult[a,b](FSharpChoice`2 res)
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.EvalScript(String filePath)
at Yaaf.FSharp.Scripting.Helper.evalScript@1303.Invoke(String arg00) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1303
at Yaaf.FSharp.Scripting.Helper.save_@1276-2.Invoke(Unit unitVar0) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1277
at Yaaf.FSharp.Scripting.Helper.consoleCapture[a](TextWriter out, TextWriter err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1221
at Yaaf.FSharp.Scripting.Helper.redirectOut@1247[a](Boolean preventStdOut, OutStreamHelper out, OutStreamHelper err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1254
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1276
--- End of inner exception stack trace ---
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1284
at Yaaf.FSharp.Scripting.Helper.session@1306.Yaaf-FSharp-Scripting-IFsiSession-EvalScriptWithOutput(String ) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1308
at Fake.FSIHelper.runScriptUncached(Boolean useCache, String scriptPath, IEnumerable`1 fsiOptions, Boolean printDetails, CacheInfo cacheInfo, TextWriter out, TextWriter err) in C:\code\fake\src\app\FakeLib\FSIHelper.fs:line 471
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
这里的重点是我试图仅在某个目标下执行shell命令。不注意mkdir命令,因为我实际上想使用schtasks命令。我只是为了简单起见而使用了mkdir。也许我在这里失踪的细微差别。我还注意到使用environVarOrFail时的这种行为。提前感谢所有回复的人。
答案 0 :(得分:7)
Shell.Exec
会返回int
,但Target
需要一个返回unit
的函数。
试试这个:
let returnUnit() = ()
let return42() = 42
Target "One" returnUnit // works
Target "Two" return42 // fails: expected to have type unit, but here has type int
目标"两个"无法编译,因为它的第二个参数是一个返回int
的函数,而一个返回unit
的函数是预期的。
这个错误可以让你忘记忘记函数返回值:编译器有用地告诉你"嘿,你确定你不想对这个int做任何事吗?那么你为什么要首先调用这个函数呢?"
然而,有时候抛弃返回值是有道理的。例如,在这种特殊情况下,您为其副作用调用了Shell.Exec
,并且其返回值对您不感兴趣。这种情况经常令人惊讶地发生,因此通常会有一个特殊功能 - ignore
。
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory") |> ignore // compiles fine
)
此函数接受任何值,抛出它并返回一个单位。通过将其应用于Shell.Exec
的结果,您告诉编译器:"是的,我确定我不需要此值,请ignore
它。&# 34;
那就是说,我强烈建议使用专门的函数而不是通用的系统调用。这将使您的脚本更具可读性,甚至可以帮助您尽早发现错误。例如,要创建目录,请使用FileUtils.mkdir
:
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
FileUtils.mkdir "exampleDirectory" // no need for `ignore`, mkdir already returns `unit`
)