継続的インテグレーション その2

NAntを使って、Subversionからソースをチェックアウトする。
でも、NAntにはSubversion用のタスクが用意されていないので、とりあえずexecタスクを使ってやってみる。

<?xml version="1.0" encoding="shift-jis"?>
<project default="svn">
    <target name="svn">
        <exec program="C:\Program Files\Subversion\bin\svn.exe"
            commandline="checkout http://localhost/svn/default/hoge/trunk c:\temp" />
    </target>
</project>

これでNAntを実行してみると、簡単にソースをチェックアウトできた。
でもこれだけだと面白くないので、NAnt用のタスクを自分で作ってみることにする。

NAntのカスタムタスク

  • 開発環境:vs2003.net
  • 言語:c#
  • NAntのバージョン:0.85

まず、プロジェクトをクラスライブラリで作成する。
プロジェクト名を「NAnt.SvnTasks」に設定、NAntはカスタムタスクの定義されたアセンブリを*.Tasks.dllというパターンで検索してロードするため、プロジェクト名をそれに合わせておく。

NAnt.Core.dllアセンブリを参照設定する。
次にクラスファイルを追加する。
Subversionからチェックアウトするクラスなので、「SvnCheckoutTask」とする。
カスタムタスクは「NAnt.Core.Task」クラスから派生させて、「ExecuteTask」メソッドをオーバーライドする必要があるので、そのようにする。
以下、全ソース

using System;
using System.Diagnostics;

using NAnt.Core;
using NAnt.Core.Attributes;

namespace NAnt.SvnTasks {
    [Serializable]
    [TaskName("svn-checkout")]
    public class SvnCheckoutTask : Task {
        private string executable = "svn.exe";
        private string repository;
        private string workingDirectory;
        private string userName;
        private string password;

        [TaskAttribute("executable", Required=false)]
        public string Executable {
            get { return executable; }
            set { executable = value; }
        }
        [TaskAttribute("repository", Required=true)]
        public string Repository {
            get { return repository; }
            set { repository = value; }
        }
        [TaskAttribute("workingDir", Required=true)]
        public string WorkingDirectorya {
            get { return workingDirectory; }
            set { workingDirectory = value; }
        }
        [TaskAttribute("username", Required=false)]
        public string UserName {
            get { return userName; }
            set { userName = value; }
        }
        [TaskAttribute("password", Required=false)]
        public string Password {
            get { return password; }
            set { password = value; }
        }

        public SvnCheckoutTask() {
        }

        protected override void ExecuteTask() {
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = executable;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;
            // 0 : リポジトリ
            // 1 : 作業フォルダ
            // 2 : ユーザ名
            // 3 : パスワード
            startInfo.Arguments = string.Format(
                "checkout \"{0}\" \"{1}\" {2} {3}",
                repository, workingDirectory,
                IsNotNullOrEmpty(userName) ? "--username " + userName : string.Empty,
                IsNotNullOrEmpty(password) ? "--password " + password : string.Empty);
            if(Verbose) Log(Level.Info, startInfo.Arguments);

            Process proc = Process.Start(startInfo);

            string stdout = proc.StandardOutput.ReadToEnd();

            proc.WaitForExit();

            if(Verbose) Log(Level.Info, stdout);
        }

        private bool IsNotNullOrEmpty(string value) {
            return value != null && value.Length != 0;
        }
    }
}

カスタムタスクとして認識させるには、クラスを「TaskName」属性でマークする。
「TaskName」属性の引数に指定する名前がそのままNAntのタスク名になる。
カスタムタスクの属性として認識させるには、プロパティを「TaskAttribute」属性でマークする。
引数に指定する名前がそのまま属性名になる。オプションで必須属性かどうかを指定できる。(Required=true or false)

これをビルドして、NAnt.SvnTasks.dllをNAnt.exeのあるフォルダにコピーする。
こんな感じで使う。

<?xml version="1.0" encoding="shift-jis"?>
<project default="svn">
    <target name="svn">
        <svn-checkout
            repository="http://localhost/svn/default/hoge/trunk"
            workingDir="c:\temp" verbose="true" />
    </target>
</project>

ビルド実行......おっ動いた!
結構、簡単に作れる。でもexecのときとあんまり変わってない気がする。
まぁ、勉強になったからいいか。

次はこのタスクをCruiseControl.NETから動かしてみる。