tracのpre/post-commit

前にまとめた気がしたけど。id:ladybug:20100607だな。
pre-commitは、

  • コミットコメントには refs #999 または fixed #999 を含める必要がある。(変更はtracに登録してから)
  • 指定されたチケット番号が有効でopenであること。
  • コミット先が
    • /trunk/ で始まる場合、チケット属性targetがnullであること。(ブランチ用のチケットでトランクを変更できない)
    • /branches/NAME/ で始まる場合、チケット属性targetがNAMEであること。(ブランチ用の変更は該当のブランチへのみ)
    • /tags/NAME/ の場合、トランザクションの変更リストがAまたはDの一行であること。(タグの作成と削除のみ許可)
    • /devs/NAME/ で始まらない場合、コミットできない。(NAMEは任意)
  • svn:mime-typeにencodingが含まれる場合、記載されたエンコードであること。
  • svn:eol-styleが有効な場合、改行コードが正しいこと。(Windowsばっかりなのでかなり強引な実装)

post-commitでは、

  • コミットログを指定のチケットへコメントとして貼り付ける。
  • fixed #999 の場合、カスタム属性のprogressを100にする。
  • refs #999 の場合、続けて 99% が記載されていれば、カスタム属性のprogressを記載の値にする。(記載が無いときは何もしない)
  • fixed #999 の場合、チケットアクションresolve(fixed)を実行する。
  • refs #999 の場合、statusがacceptedでは無い場合、チケットアクションacceptを実行する。

覚えてないのが、もうちょっとあるはずだ…。
リリース時には、レポート機能で対象のtargetやversionでチケットを取得し、変更一覧として保存する。そこからExcelVBAtracのXMLRPC機能を使いまして、コミット時にコメントに記録されたチェンジセット番号を収集してチケット毎の変更ファイル一覧作ったり、コメントやカスタム属性で記録された出荷情報を拾い上げたりします。
たとえば、カスタム属性で『エンドユーザに影響のある変更か?』を保持していて、販売店にバージョンアップの案内や変更点の説明文書に自動的に必要な定形ドキュメントを挿入したりですね。
もうちょっと色々とやりたいところですが、当面はこんなかんじで運用していますね。実際は直販ユーザとかもいるので、そっちの管理がいまいちうまくいってないところがあったりします。

Windows を再起動/シャットダウン時の待ち時間

夏ですね、雨ですね、雷ですね、停電ですね。
WindowsSQL ServerOracle といったサービスをインストールされている方はそれなりにいると思いますが、これらが稼働したまま再起動(またはシャットダウン)を実行して OS を終了した場合、これらのサービスが正しく終了しているかどうかについて、自身を持って答えられる方はどれぐらいおられるでしょうか?
別に SQL ServerOracle に限った話ではないのですが、OS 終了時にすべてのサービスは停止されます。SQL ServerOracle もサービスを終了しようとすると、チェックポイントで停止するようになっています。SQL Server の挙動については詳しく調べていないのですが、Oracle であればデフォルトで 9i までは shutdown normal が実行され、10g 以降は shutdown immediate が実行されるはずです。*1
私もそうですが…、ここまでは想像/理解しておられる人も多いのでは?と思います。このような仕組みがあるので、動いているサービスをあまり気にしないで OS の再起動やシャットダウンを実行することができます。しかし、サービスの管理画面から特定の Windows サービスを開始/停止したことがある人ならば、サービスの開始や停止が短時間で終わるとは限らないことをご存じのはずです。Oracle 9i の shutdown normal なんて、全トランザクションがコミット/ロールバックされるのを待機しますので、利用状況によってはかなりの時間がかかります。
しかしながら、OS は再起動やシャットダウンの要求に対してサービスの停止を無限に待つわけにもいきません。このため、一定時間が経過すると OS はサービスを構成するプロセスを強制的に終了して再起動やシャットダウンのシーケンスを進めるようになっています。
デフォルトでは、以下の時間だけ待機するようです。

この時間が経過してもサービスが終了しない場合、そのサービスにはブレーク信号が送信され、しばらく後にプロセスが破棄されます。この待機時間はレジストリの WaitToKillServiceTimeout に設定されています。
Windows Server 2008 R2Windows 7 については、デフォルトで 12 秒が設定されているのですが、2012/08/08 の最新アップデート時点*2では、不具合のため5秒でサービスを殺すようになっています。この問題の KB と HotFix は、http://support.microsoft.com/kb/2549760/en にあります。

SQL ServerOracle は当然ながら、いくつかのサービスは5秒という時間での正常停止は厳しいかと思います。個人用途の PC でも、メモリを利用したディスク I/O の高速化ツールなどが正常終了できずにファイルを壊しちゃったりとか、いろいろと面倒が発生しやすいポイントなので注意が必要ですね。

*1:10g 以降はレジストリで SID 毎に設定できます

*2:SP1 + Windows Update をすべて適用した状態

新時代の非同期

いまさらasyncっていうか、twitter経由ネタです。
id:ladybug:20110412 非同期呼び出しの名前 に書いていますが、.NET Framework では非同期の手法が世代交代しています。

  • .NET 1.0/1.1 の APM (Async Programming Model)
  • .NET 2.0 の EAP (Event-based Async Pattern)
  • .NET 3.0 の EAP 拡張(WPF 向け SynchronizationContext の追加)
  • .NET 4 の TPM (Task Programming Model)

そして、

  • .NET 5? の TAP (Task-based Async Pattern)

となるわけです。

続きを読む

[.NET] NuGet を使用したプロジェクトを共有する

NuGet は便利なのですが、NuGet を利用したプロジェクトをソース管理へ登録したり配布したりして、他人と共有する場合にどうすればよいでしょうか?
Package フォルダを含めて登録(配布)すれば問題ないのですが、それだと NuGet を使ってパッケージ管理を行っている利点が少し薄れますよね。それに、管理されているパッケージのバイナリをソース管理で再管理したり、それらのバイナリを配布物として配布するなんてのはナンセンスです。
依存関係というメタデータだけを登録(配布)しておいて、各自の環境でパッケージのダウンロードやアップデートを行ってもらうのが理想ですね。しかし、下手なことで定評のある私の検索能力では、よくまとまった記事等を発見することができなかったので、NuGet を利用したプロジェクトをソース管理に登録したり配布する際の手順をメモっておきます。

続きを読む

PowerShell で AOP

いや、あんまり AOP っぽいことはしないんですが...良いタイトルが思いつかなかったので。

最近の .NET Framework は DLR のような仕組みを取り入れつつありますが、.NET の世界の基本は強い型付けのあるクラス型OOPがベースになっています。もちろん、それは .NET 対応のプログラミング言語が必ずしもクラス型のOOPLでなければならないというわけではありませんが、型システムや標準ライブラリなどがそのように構築されていることにはかわりありません。
C# 3.0 で拡張メソッドが導入されるなど、CLR の機能拡張を伴わないプログラム言語レベルの拡張の仕組というのは色々とありますが、PowerShell でもそういった仕組みが準備されています。

PowerShell では、任意のオブジェクトに対してメンバを自由に追加することができるようになっています。たとえば、大量のファイルからいくつかのファイルをマーキングしておき、マーキングしたファイルだけを処理するような場合に使えます。

# SYSTEM32 の DLL 一覧を取得
PS > $files = Get-Item C:\Windows\System32\*.dll

# 名前が MS で始まるものと、6番目のファイルをマーキング
PS > $files |? { $.Name -Like "MS*" } | Add-Member NoteProperty SumIt $true
PS > Add-Member NoteProperty SumIt $true -in $files[5]

# マーキングしたファイルのサイズを集計
PS > $files |? { $_.SumIt } | measure -Sum -Ave -Min -Max Length
Count    : 14
Averate  : 629840
Maximum  : 17786368
Minimum  : 2048
Property : Length

NoteProperty は定数をメモするためのプロパティで、お手軽に使える便利なプロパティです。この例では SumIt という名前のプロパティを作成し、その値を $true に設定しています。すでに同じ名前のプロパティがある場合はメモプロパティの作成は失敗しますが、-Force を指定していると上書きすることもできるので、オブジェクトに何らかのメモを好きに貼り付けることができます。
似たようなものに、ScriptProperty があります。これは任意のスクリプトをプロパティとして登録できます。

# すべてのオブジェクトに Smaller プロパティを追加
PS > $files | Add-Member ScriptProperty Smaller { $this.Length -lt 1MB }
PS > $files | group Smaller
Count Name
----- -----
 1745 True
  261 False

$this はオブジェクト自身を表します。この Smaller プロパティはオブジェクト自身の Length が 1MB 未満の場合に $true になるので、1745 個の DLL が 1MB 未満であるということがわかります。

Add-Member では、様々なものを追加することができますが、とりあえずは NoteProperty と ScriptProperty の2つがあれば、PowerShellスクリプトを書くときにオブジェクトに関連付けて情報を保存するのに非常に便利になるはずです。

余談ですが、特定の .NET の型に NoteProperty や ScriptProperty を自動的に付与することもできます。そのためには XML で types.ps1xml というファイルを作成して Update-TypeData コマンドを使用するのですが、必要なオブジェクトだけ Add-Member すればいいんじゃないかな?と思います。興味がある人は help about update-typedata と help about_types でもどうぞ。

PowerShell から .NET のコード片を実行する

特定の .NET の型のメソッドの挙動を、ちらっと確認したい…そんな時にも PowerShell は便利です。
PowerShell がない頃はコマンドラインからメソッドの中身だけを書いてCodeDomCompilerを呼び出すようなコマンドライン アプリケーションを作っていましたが、PowerShell のおかげで楽ができるようになりました。前回の Add-Type コマンドは、アセンブリを読み込むだけではなくソースコードを指定して型(とメソッド)を追加することができます。
慣れてくれば、PowerShell 上からメソッドを呼び出して確認できるのですが、エスケープ表記の違いや変数の中身が .NET にわたるときの変換処理など、PowerShell になれないうちは全部を C#VB で書けるほうが便利ですよね。

PS > Add-Type @"
public class MyTest1
{
    public static object test1()
    {
        return 1;
    }
}
"@

PS > [MyTest1]::test1()
1

こんなかんじで、ささっと書いたソースを実行させてみることができます。ソースコードは文字列ではなくファイル名で与えることもできます。メソッドだけを定義する場合には型の名前を指定して

PS > Add-Type MyTest2 @"
public static object test2()
{
   return 1;
}
"@

といったかんじでメソッドの実装を与えます。ただし、-Namespace を使ってネームスペースを指定しないと、MyTest2 クラスのネームスペースが Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes という長ったらしいものになってしまうので、-Namespace は忘れないようにしましょう。

var 等のC# 3.0 の機能を有効にするためには -Language CSharpVersion3 を指定し、VB のソースを指定する場合には、-Language VisualBasic を指定します。F# は -Language オプションで指定できないため CodeDomProvider の作成が必要になります。

# まず、CodeDomProvider を読み込む
PS > Add-Type -Path FSharp.Compiler.CodeDom.dll

# CodeDomProvider をインスタンス化する
PS > $fp = New-Object Microsoft.FSharp.Compiler.CodeDom.FSharpCodeProvider

# F# コードをコンパイルする
PS > Add-Type "let ..." -CodeDomProvider $fp

コンパイルオプションは -CompilerParameters で指定できます。どんなオプションがあるかはコマンドライン コンパイラで確認してください。

PowerShell で .NET と親しくなるために

時間もネタもないまま仕事に没頭していましたので、唐突に殴り書きです。

PowerShell .NET Framework 上で動いているので、.NET と親和性が高いようになっています。結構な量のコマンドレットはあるのですが、それでも特定の事柄のために .NET の機能を直接呼び出すことで簡単に解決できることもあります。

特定のアセンブリPowerShell に読み込ませるには、Add-Type コマンドを使用します。たとえば、System.Windows.Forms.dll にある MessageBox クラスを使用してメッセージボックスを表示するには、

# System.Windows.Forms.dll を読み込む
PS > Add-Type -Assembly System.Windows.Forms

# MessageBox クラスの Show を呼び出す
PS > [Windows.Forms.MessageBox]::Show("選択してください", "こんにちは", "YesNoCancel")
No

こんなかんじになります。クラス名を指定するときはネームスペースの先頭の System だけは省略することができます。[Windows.Forms.MessageBox] は [System.Windows.Forms.MessageBox] と書いても一緒です。
この例のように、PowerShell から enum を与える場合、その名前を指定することで自動的に Enum.Parse() が呼び出されて .NET 側には enum が渡ります。もちろん、Enum 型を指定して [Windows.Forms.MessageBoxButtons]::YesNoCancel と記述してもかまいません。
メソッドについて調べたいときは、メソッド名だけを指定すればメソッドの情報が手に入ります。

PS > [Windows.Forms.MessageBox]::Show
MemberType           Method
OverloadDefinitions  { ... }
TypeNameOfValue      PSMethod
Value                static System.Windows...
Name                 Show
IsInstance           True

# オーバーロードの一覧を表示
PS > [Windows.Forms.MessageBox]::Show.OverloadDefinitions

新しくオブジェクトを作成するには、New-Object コマンドを使います。

# -Property オプションでオブジェクトイニシャライザっぽく書けます
PS > $form1 = New-Object System.Windows.Forms.Form -Property @{
    Text = "Form1";
    Size = New-Object System.Drawing.Size(400, 300);
}

# delegate の作成はスクリプトブロックを渡すだけです
PS > $form1.add_DoubleClick({
    param($sender, $e);

    # ダブルクリックすると OK と表示して終了する
    [Windows.Forms.MessageBox]::Show("ok");
    $sender.Close();
})

# WinForms のアプリケーションのメッセージ処理を開始する
PS > [Windows.Forms.Application]::Run($form1);

型を指定するの方法を使って型パラメータを引数にもできます。

# C# で言うところの List<int> を作成する
PS > $list = New-Object System.Collections.Generic.List[int]

ちょーっと殴り書きすぎました。ごめんなさい。