はじめに
前回はビルドイベントにバッチファイルを指定しましたが、バッチファイルでは柔軟性に欠け、罠のような記述もあって可読性もよろしくないので、どうにかしたと思います。
ビルドコマンドにコンソールアプリケーションを使う
結局の所、Delphi でコンソールアプリケーションを作ってそれをビルドコマンドとして渡してやればいいのです (なんて Delphi 脳)。
deploy.exe
前回のバッチファイル deploy.bat と同等のものをこしらえてみます。
ビルドイベントの指定
bat が exe になっただけですね。
SET PROJECTNAME=$(PROJECTNAME)
SET INPUTDIR=$(INPUTDIR)
SET OUTPUTPATH=$(OUTPUTPATH)
"$(INPUTDIR)deploy.exe"
コンソールアプリケーションの準備
次のファイル (deploy.dpr) をプロジェクトフォルダに置き、
program deploy;
{$APPTYPE CONSOLE}
begin
end.
IDE の [プロジェクト | 既存プロジェクトを追加] で deploy.dpr を追加します。
ProjectGroup1 の所を右クリックしてコンテキストメニューから プロジェクトグループに名前を付けて保存 を選びます。
保存先は Project1 と同じ場所にします。
C:\EMBARCADERO\PROJECTS\BUILD TEST
deploy.dpr
deploy.dproj
deploy.dproj.local
Project1.dpr
Project1.dproj
Project1.dproj.local
Project1.res
ProjectGroup1.groupproj
ProjectGroup1.groupproj.local
Unit1.dfm
Unit1.pas
コンソールアプリケーションを記述
内容は前回のバッチファイル deploy.bat を踏襲します。
program deploy;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.IOUtils, System.Zip;
begin
// 環境変数がセットされていなければ抜ける
if GetEnvironmentVariable('OUTPUTPATH') = '' then
Halt(1);
try
var PRJ := GetEnvironmentVariable('PROJECTNAME');
var DST1 := TPath.Combine(GetEnvironmentVariable('INPUTDIR'), 'Deploy');
var DST2 := TPath.Combine(DST1, 'work');
var DST3 := TPath.Combine(DST2, PRJ); // TZipFile.ZipDirectoryContents() は指定フォルダそのものを格納しない
var SRCEXE := GetEnvironmentVariable('OUTPUTPATH');
var DSTEXE := TPath.Combine(DST3, TPath.GetFileName(SRCEXE));
// 最新版 EXE を配布フォルダへコピー
if not TDirectory.Exists(DST3) then
TDirectory.CreateDirectory(DST3);
TFile.Copy(SRCEXE, DSTEXE, True);
// 既存の ZIP ファイルを削除
for var FileName in TDirectory.GetFiles(DST1, '*.zip') do
TFile.Delete(FileName);
// ファイル名に使う日付時刻を EXE のタイムスタンプから取得 (_YYYYMMDD_HHNN)
var ZIPNAME := PRJ + FormatDateTime('"_"YYYYMMDD"_"HHNN".zip"', TFile.GetLastWriteTime(DSTEXE));
ZIPNAME := TPath.Combine(DST1, ZIPNAME);
// ZIP ファイルを作成
TZipFile.ZipDirectoryContents(ZIPNAME, DST2);
except
on E: Exception do
begin
Write(E.Message);
ExitCode := 2;
end;
end;
end.
コードは次のような事をやっています:
- EXE が Explorer からダブルクリックされるなどして実行されたら処理しない
-
Deploy\<プロジェクト名>\<プロジェクト名>フォルダをプロジェクトフォルダ内に作成 - 以前に作成された ZIP ファイルは削除
- 実行時にエラーが出たらメッセージを標準出力
deploy.dpr をコンパイルすると、同じ場所に deploy.exe が生成されます。
C:\EMBARCADERO\PROJECTS\BUILD TEST
deploy.dpr
deploy.dproj
deploy.dproj.local
deploy.exe
deploy.res
Project1.dpr
Project1.dproj
Project1.dproj.local
Project1.res
ProjectGroup1.groupproj
ProjectGroup1.groupproj.local
Unit1.dfm
Unit1.pas
ビルドテスト
deploy.exe ができたら [プロジェクトマネージャ] で Project1 に切り替えます。
[プロジェクト | ビルド] を行い、正常に (Release) ビルドされたら プロジェクト名_YYYYMMDD_HHNN.zip が Deploy サブフォルダにできているハズです。
C:\EMBARCADERO\PROJECTS\BUILD TEST
│ deploy.dpr
│ deploy.dproj
│ deploy.dproj.local
│ deploy.exe
│ deploy.res
│ Project1.dpr
│ Project1.dproj
│ Project1.dproj.local
│ Project1.res
│ ProjectGroup1.groupproj
│ ProjectGroup1.groupproj.local
│ Unit1.dfm
│ Unit1.pas
│
├─Deploy
│ │ Project_120251201_0246.zip
│ │
│ └─work
│ └─Project1
│ Project1.exe
│
└─Win32
└─Release
Project1.exe
Unit1.dcu
バッチファイル版との違いは収集フォルダの階層が一段深い事です。これはフォルダを圧縮する TZipFile.ZipDirectoryContents() メソッドが指定フォルダそのものを格納しない仕様によるものです。
プロジェクトの切り替えが面倒?
配布用 EXE (deploy.exe) を作るのにプロジェクトを切り替えてビルドするのが面倒?
ちゃんとデバッグくらいはした方がいいとは思うのですが、スクリプトの書き替えみたいなお手軽さを求めるのであれば、ビルドイベントで配布用 EXE をビルドすればいいと思います! (なんて Delphi 脳)
先頭行で deploy.dpr をビルドして deploy.exe を生成しています。
DCC32 -cc "$(INPUTDIR)deploy.dpr"
SET PROJECTNAME=$(PROJECTNAME)
SET INPUTDIR=$(INPUTDIR)
SET OUTPUTPATH=$(OUTPUTPATH)
"$(INPUTDIR)deploy.exe"
Delphi の爆速コンパイラだとビルド時間が 0.1 秒増えた程度でしょうか?配布用 EXE をガチャガチャやって作り込んでる時はこれでもいいかもですね。最終的に仕様が固まったら先頭行を外すなりコメントアウトすればいいので。
おわりに
バッチファイルに比べれば、多少記述量は増えましたが、視認性は格段によくなりました。PowerShell を呼び出すオーバーヘッドもないので EXE 版の方が高速動作するのもメリットです。
TZipFile は XE2 以降で実装されているので、ZIP 圧縮を XE 以前の古いプロジェクトに組み込みたい場合には工夫が必要です。XE 以前ならバッチファイル版の方がお手軽でいいかもですね。
See also:






