在FAKE中有多种构建文件结构的方法吗?

时间:2013-12-02 00:30:51

标签: f# f#-fake

FAKE中,您通常有一个类似的构建脚本:

// "foo.fsx"
#r @"./packages/tools/FAKE/tools/FakeLib.dll"

open Fake

Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" )

Run "Foo"

哪个工作正常。现在假设您需要另一个名为“bar.fsx”的构建脚本,

// "bar.fsx"
#r @"./packages/tools/FAKE/tools/FakeLib.dll"
#load "foo.fsx"

open Fake

Target "Bar" (fun _ -> trace "And you have me building software ..." )

Run "Bar"

现在这是错误的。如果您尝试运行“bar.fsx”,它将首先执行任务“Foo”,即使我没有明确要求将其作为依赖项。这是因为load指令运行foo.fsx脚本。

所以,我的问题是,如何导入foo.fsx文件,获取所有目标,但不执行Run命令。或者更有趣的是,我真正想做的事情;如何在FAKE中的脚本之间共享Target

如果我将Target定义放入模块中,这样做无效:

module FooTargets =
    Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" )

这对我来说可能有点令人惊讶......

欣赏有关如何实现这一目标的任何建议。到目前为止,我的“最佳”想法是在'foo.fsx'中定义一些常量,然后在所有其他脚本中有条件地load。但这似乎很令人反感(编辑:很开心,甚至不可能。)

- 更新:下面是一个更完整(即可运行)的示例。由于模块Common已加载两次,并且FAKE已使用相同的“Env”目标填充目标字典,因此FAKE 2.2.12.0失败并出现Duplicate Key错误。

// "common.fsx"
#r     @"../../tools/FAKE/FakeLib.dll"

open Fake

module Common = 
    Target "Env" (fun _ -> trace "Env")

// "foo.fsx"
#r     @"../../tools/FAKE/FakeLib.dll"
#load  @"common.fsx"

open Fake

module Foo =
    Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" )

"Env" ==> "Foo"

// "bar.fsx"
#r     @"../../tools/FAKE/FakeLib.dll"
#load  @"common.fsx"

open Fake

module Bar =
    Target "Bar" (fun _ -> trace "And you have me building software ..."  )

"Env" ==> "Bar"

// "marvin.fsx"
#r     @"../../tools/FAKE/FakeLib.dll"

#load  @"common.fsx"
#load  @"foo.fsx"
#load  @"bar.fsx"

open Fake

module Marvin =
    Target "Marvin" (fun _ -> ())

"Bar" ==> "Marvin"
"Foo" ==> "Marvin"

Run "Marvin"

使用:fake.exe Marvin.fsx构建。

错误:

System.TypeInitializationException: The type initializer for '<StartupCode$FSI_0002>.$FSI_0002_Common$fsx' threw an exception. ---> System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Fake.TargetHelper.targetFromTemplate[a](TargetTemplate`1 template, String name, a parameters)
   at Fake.TargetHelper.TargetTemplateWithDependecies@140.Invoke(String name, a parameters)
   at <StartupCode$FSI_0002>.$FSI_0002_Common$fsx..cctor() in c:\Users\Noon\dev\beep\common.fsx:line 7
   --- End of inner exception stack trace ---
   at <StartupCode$FSI_0002>.$FSI_0002_Foo$fsx.main@() in c:\Users\Noon\dev\beep\foo.fsx:line 8
Stopped due to error
Searching for process with name = fsi.exe
Searching for process with name = msbuild

2 个答案:

答案 0 :(得分:9)

Build.Tools中,我们最终将各种目标的代码放在不同的脚本文件中作为普通的F#函数,然后在Core.fsx中将目标组合在一起,设置目标及其依赖项。

我的低优先级待办事项列表中的一个实际上是将Core分成两个文件 - 一个用于构建配置和目标定义,另一个用于设置依赖项并调用Run。通过这种方式,您可以重新使用所有基础目标,同时定义不必包含完整默认依赖关系树的不同运行程序。

当前Core.fsx如下所示:

#r    "./fake/fakelib.dll"
#load "./Utils.fsx"
#load "./Packaging.fsx"
#load "./Versioning.fsx"
#load "./Solution.fsx"
#load "./Test.fsx"
#load "./Specflow.fsx"

open System.IO
open Fake

let config = 
    Map.ofList [
        "build:configuration", environVarOrDefault "configuration"         "Release"
        "build:solution",      environVar          "solution"
        "core:tools",          environVar          "tools"
        "packaging:output",    environVarOrDefault "output"                (sprintf "%s\output" (Path.GetFullPath(".")))
        "packaging:updateid",  environVarOrDefault "updateid"              ""
        "packaging:pushurl",   environVarOrDefault "pushurl"               ""
        "packaging:apikey",    environVarOrDefault "apikey"                ""
        "packaging:packages",  environVarOrDefault "packages"              ""
        "versioning:build",    environVarOrDefault "build_number"          "0"
        "versioning:branch",   match environVar "teamcity_build_branch" with
                                   | "<default>" -> environVar "vcsroot_branch"
                                   | _ -> environVar "teamcity_build_branch"
    ]

Target "Default"           <| DoNothing
Target "Packaging:Package" <| Packaging.package config
Target "Packaging:Restore" <| Packaging.restore config
Target "Packaging:Update"  <| Packaging.update config
Target "Packaging:Push"    <| Packaging.push config
Target "Solution:Build"    <| Solution.build config
Target "Solution:Clean"    <| Solution.clean config
Target "Versioning:Update" <| Versioning.update config
Target "Test:Run"          <| Test.run config
Target "SpecFlow:Run"      <| Specflow.run config

"Solution:Clean"
    ==> "Packaging:Restore"
    ==> "Versioning:Update"
    ==> "Solution:Build"
    ==> "Packaging:Package"
    ==> "SpecFlow:Run"
    ==> "Test:Run"
    =?> ("Packaging:Push", not isLocalBuild)
    ==> "Default"

RunParameterTargetOrDefault "target" "Default"

答案 1 :(得分:1)

Here's我想出了一个解决方案。由于#load的实际情况以及运行目标的FAKE流程,我不得不从构建过程中分离出目标。但它至少可以实现我的目标。我并不完全确定我的感受,因为&#34;松散&#34;文件间依赖关系之间的连接;但也许人们可以说这是件好事。