FlubuCore 入門:常用的工作與 API

第一集相同,本文內容僅適用於 .NET Core 專案。


內容綱要:
  • 工作目錄結構與檔案名稱
  • 使用 Console App 為建置腳本
  • 工作目錄與相對路徑
  • 編譯方案(專案)
  • 改寫預設參數
  • 清理輸出目錄
  • 目標工作的相依關係
  • 工作的事件
  • 結語

工具使用:FlubuCore v5.0.3

工作目錄結構與檔案名稱

上一篇文章裡提過,我偏好的目錄結構類似這樣:

(根目錄)
  + build

    build.csproj
    BuildScript.cs
  + source

    - BuildAll.sln
    + MyApp
    + ClassLibrary1
  + output
 


此目錄配置方式意味著當你在使用命令列指令來建置專案時,現行工作目錄會是 (根目錄)

另一種常見的安排是把建置腳本也放在 source 目錄底下:

(根目錄) 
  + source

    - BuildAll.sln
    + build
      build.csproj
      BuildScript.cs
   
    + MyApp

    + ClassLibrary1
  + output
 


這種目錄配置方式則意味著當你在使用命令列指令來建置專案時,現行工作目錄通常是(但不必然是)source

這兩種目錄結構的安排方式,對你在撰寫建置腳本時多少會有一些影響,例如 solution 檔案的相對路徑名稱、建置輸出結果(即 output 目錄)的相對路徑等等。當然,你在寫建置腳本時,也可以使用完整的路徑名稱,但這不是好主意,因為它有個缺點:一旦把建置腳本放到其他電腦上執行,可能就因為檔案路徑不同而建置失敗。(稍後會進一步說明如何在建置腳本中避免使用絕對路徑)

目錄結構的重點是 build 和 source 這兩個子目錄;前者用來存放建置腳本,腳本的專案名稱也命名為 build.csproj,而用來寫腳本內容的 C# 檔案則是 BuildScript.cs。這兩個檔案名稱都有其內定的慣例命名,在上一篇文章已經整理了預設名稱列表,就不重複列出。只要知道,按慣例來命名腳本檔案就能讓 FlubuCore 找到它們,可減少一些麻煩。同樣的,它們彼此的相對位置以及它們與「根目錄」的相對位置也是挺重要的,因為你得在建置腳本中指定建置結果的輸出路徑,也就是前面目錄結構範例中的 output 資料夾。
用來存放建置結果的 output 資料夾無需事先建立,也無須保存檔案的版本,所以通常會加入 .gitignore 檔案,以免存入 Git 儲存庫。 

使用 Console App 為建置腳本

FlubuCore 的建置腳本可以是 Class Library 或 Console Application 類型的專案,前者編譯結果為 .dll,後者為 .exe。無論哪一種應用程式類型,在命令列視窗裡面下的指令都一樣是 flubu [target]

如果你需要在 Visual Studio 中除錯你的建置腳本,那麼最簡單的方式就是採用 Console Application 了。相較於 Class Library,採用 Console App 類型的建置腳本只是在專案中多了一個 Program.cs,如下所示:


其中的 BuildScript 類別就是你的建置腳本。如果你對這個部分覺得陌生,請先閱讀我的上一篇文章:〈FlubuCore 入門:建置 .NET Core 專案〉。

如果想要在除錯建置腳本時,也能夠追進(trace into)FlubuCore 的原始碼,這會稍微 tricky 一點。還好我們通常不需要除錯 FlubuCore 原始碼,所以相關的專案配置以及可能碰到的問題與解法,這裡就不特別說明。
👉 如需除錯 FlubuCore 程式碼,可參考官方文件 Test and Debugging。我的作法比較像土法煉鋼,將來若有適當時機,再寫專文介紹。

工作目錄與相對路徑

前面提過,在編寫建置腳本時,檔案路徑名稱最好不要使用完整路徑,否則當你把建置腳本放在其他機器上面執行時,很可能會因為路徑找不到而發生錯誤。

乍聽之下,使用相對路徑應該很簡單,不會是令人頭疼的問題,然而事情也不是那麼單純。底下進一步說明原因。

在建立 Console Application 類型的建置腳本專案時,基本上有兩種運行建置腳本的方式:
  1. 在命令列視窗中,以 flubu 指令來執行建置腳本。
  2. 在 Visual Studio 環境中,以 F5 或 Ctrl+F5 來執行建置腳本專案(以便除錯建置腳本)。
而且,我的目標是以上兩種執行建置腳本的方式都要能產生一致的結果。也就是說,無論是在命令列視窗下指令,還是在 Visual Studio 中執行建置腳本,兩者都要順利執行完畢,而且建置結果也都會輸出至同一個資料夾。

然而,這兩種執行建置腳本的方式有個根本上的差異:執行時的工作目錄不一樣。

當你在 Visual Stduio 中按 F5 或 Ctrl+F5 來執行建置腳本專案時,其執行時的工作目錄是建置腳本專案的輸出目錄,例如 bin/debug/netcoreapp3.1/。另一方面,當你在命令列視窗透過 flubu 指令來執行建置腳本時,其工作目錄則是下指令當時的所在目錄,而且通常是 solution 所在的目錄,或整個專案的最上層目錄。

既然兩種運行建置腳本的工作目錄不一樣,那麼我們在建置腳本當中使用的相對路徑名稱,到底是相對於哪一個工作目錄呢?這裡就會有問題了。

解決方法:使用 .flubu 檔案

要達到前面說的目標(兩種運行建置腳本的結果必須一致),同時又要避免在建置腳本中使用完整路徑,目前看來最簡單、也可能是唯一的解決方法,就是使用 .flubu 檔案。

你可以在命令列視窗使用 flubu setup 指令來產生 .flubu 檔案,具體作法可參考上一篇文章的說明。這裡的重點是 .flubu 檔案該放在哪個資料夾。

根據我的經驗,在命令列視窗底下使用 flubu 命令來執行建置腳本時的所在目錄,就是存放 .flubu 檔案的最佳位置(通常會是整個 repository 的根目錄,或者根目錄之下的 source 目錄)。按此作法,將能夠避免許多檔案路徑找不到的問題。

如果你實際用過 flubu setup 指令來產生 .flubu 檔案,你會知道 .flubu 檔案裡面保存的是建置腳本檔案的相對路徑名。再細想一下,你可能會問:這樣一來,當你在 Visual Studio 中按 F5 來執行建置腳本時,其輸出目錄(也是執行時的工作目錄)是 bin/Debug 底下的資料夾,那麼建置腳本如何找到需要建置的 .sln 和其他相關檔案呢?

這裡有個關鍵:Flubu 會從建置腳本執行時的工作目錄開始尋找 .flubu 檔案,如果找不到,就會往上層目錄尋找,直到磁碟機的根目錄或者找到 .flubu 檔案為止;而 .flubu 檔案所在的資料夾,就會被 Flubu 設定為「運行建置腳本的工作目錄」。你在建置腳本中撰寫的相對路徑名,就是相對於這個工作目錄。
💬 萬一 Flubu 找不到 .flubu 檔案呢?那麼它就會以「執行建置腳本時的所在目錄」作為工作目錄。

以上是本文最重要的部分。接著介紹一些常見的工作與 API 用法範例。

編譯方案(專案)

建置腳本的各項工作,或者說目標(target),都是寫在 ConfigureTargets 方法裡面。底下範例的功能是用來編譯一個方案或專案:

執行此工作的命令列指令為: flubu compile

改寫預設參數

所有執行外部程序的工作,都可以加入其他參數,也可以改寫既有的參數。

範例:


第 19 行程式碼改寫了第 7 行所設定的 "Release" 組態。
另外,你也可以透過命令列的指令來蓋過建置腳本中的參數,例如:

flubu compile --configuration=Debug

上列指令,Flubu 在實際執行 dotnet 建置工作時,會轉換成類似底下的指令:

flubu dotnet build MyApp.sln --configuration Debug

也就是說,只要你知道某項工作在實際執行時的外部程式有哪些命令列參數,就可以在使用 flubu 命令列工具時一併傳入。
相關文件:Override existing options or add additional options to tasks through console

清理輸出目錄

底下範例 target 的作用是清除輸出目錄:

執行此工作的命令列指令為: flubu clean

目標工作的相依關係

建置腳本通常包含多項工作,而有些工作可能彼此有執行上的先後順序關係。以下結合剛才兩個範例來示範多個相依 target 之間的執行順序:

注意第 10 行的 DependsOn 方法,這行的作用是告訴 FluboCore:要執行 compile 工作之前,必須先執行 clean

DependsOn 方法接受一個參數陣列,這表示你可以傳入多個相依工作。例如:

當 targetC 執行時,實際執行的工作依序為 targetB, targetA, targetC。

工作的事件

你可以針對每一項工作出錯或結束的時候寫一些額外的程式碼。出錯的時候是呼叫工作的 OnError 方法,工作結束時呼叫 Finally 方法。Finally 方法的運作方式如同 C# 的
finally 關鍵字:無論執行過程是否發生錯誤,最終都會呼叫 Finally 方法。參考以下範例:


結語

這是我的第二篇介紹 FlubuCore 的文章,其中最重要的部分,我認為是 FlubuCore 針對「如何決定工作目錄」所提出的解決辦法,也就是 .flubu 檔案以及自動搜尋 .flubu 檔案的機制。解決了這個問題,我們便能夠在建置腳本中使用相對路徑名,而無須擔心在哪個資料夾啟動建置腳本。

FlubuCore 還有許多功能是我在最近兩篇文章裡面沒還提到的,例如:以互動模式執行、為工作撰寫自訂方法、撰寫自訂工作(task plugin)等等。如果需要更多資訊,可以參考 Flubu 官方文件

如果你也在使用 FlubuCore,記得到它的 GitHub 頁面上點個星星喔。

Happy building!
技術提供:Blogger.