Любой способ иметь структуру многострочного файла в 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"
Что отлично работает. Теперь предположим, что вам нужен еще один buildscript, называемый "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
script.
Итак, мой вопрос: как я могу импортировать файл foo.fsx
, получить все целевые объекты, но не выполнять команду Run
. Или, может быть, более интересно, и что я действительно хочу сделать; как я могу поделиться Target
между сценариями в FAKE?
Это не помогает, если я помещаю определения Target
в модуль, например:
module FooTargets =
Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" )
что, возможно, слегка удивительно для меня...
Оцените любые советы о том, как это сделать. Моя "лучшая" идея до сих пор заключалась в определении некоторой константы в say 'foo.fsx', а затем условно load
во всех других скриптах. Это кажется довольно оскорбительным, хотя (редактировать: и счастливо, даже не возможно.)
- Обновление: Ниже приведен более полный (то есть исполняемый) пример. Он не работает с FAKE 2.2.12.0 с ошибкой Duplicate Key, так как модуль Common был загружен дважды, и FAKE запустил целевой словарь с тем же целевым значением "Env".
// "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 [email protected](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>[email protected]() 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
В Build.Tools мы положили код для различных целей в разные файлы script как обычные функции F #, а затем составляли цели вместе в Core.fsx, который устанавливает цели и их зависимости.
Одна из вещей в моем низкоприоритетном списке todo состоит в том, чтобы разделить 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"