Любой способ иметь много-buildfile структуру в FAKE?
В FAKE у вас обычно есть подобный buildscript:
// "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
скрипт.
Итак, мой вопрос, как я могу импортировать foo.fsx
файл, получить все цели, но не выполнить, скажем, Run
команда. Или, может быть, более интересно, и что я действительно хочу сделать; как я могу поделиться Target
между скриптами в фейке?
Это не поможет, если я поставлю Target
определения в модуль, например, так:
module FooTargets =
Target "Foo" (fun _ -> trace "Here I am, foo the size of a bar" )
что, пожалуй, слегка удивляет меня...
Цените любые советы о том, как этого добиться. Моя "лучшая" идея до сих пор заключалась в том, чтобы определить некоторую константу, скажем, в "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 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 ответа
Вот решение, которое я придумал. Мне пришлось отделить цели от процесса сборки, из-за реалий #load
и процесс FAKE для запуска целей. Но это по крайней мере выполняет мою цель. Я не совсем уверен, что я чувствую по этому поводу из-за "слабой" связи между межфайловыми зависимостями; но, возможно, можно утверждать, что это хорошо.
В 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"