NAntでClickOnceの発行を自動化する 2
前回
やっとこさMSBuildからClickOnceの発行をする方法がわかったので、調子に乗ってNAntのタスクにしてみた。
↓以下 ソース
using System; using System.IO; using System.Xml; using System.Xml.XPath; using System.Diagnostics; using NAnt.Core; using NAnt.Core.Attributes; namespace NAnt.VS2005Tasks { [TaskName("clickonce")] public class ClickOnceTask : Task { private string version; private string projectFile; private string configuration = "Release"; private XPathDocument document; private XPathNavigator navigator; private XmlNamespaceManager nsmgr; [TaskAttribute("version", Required=false)] public string Version { get { return version; } set { version = value; } } [TaskAttribute("projectfile", Required=true)] public string ProjectFile { get { return Path.Combine(Project.BaseDirectory, projectFile); } set { projectFile = value; } } [TaskAttribute("configuration", Required=false)] public string Configuration { get { return configuration; } set { if(!string.IsNullOrEmpty(value)) configuration = value; } } private string ProjectName { get { return Path.GetFileNameWithoutExtension(projectFile); } } public ClickOnceTask() { } private XPathNavigator SelectSingleNode(string xpath) { return navigator.SelectSingleNode(xpath, nsmgr); } private string GetPublishURL() { XPathNavigator matchNode = SelectSingleNode("//D:Project/D:PropertyGroup/D:PublishUrl"); if(matchNode == null) { throw new BuildException("プロジェクトファイルに[PublishUrl]要素が存在しません。"); } return matchNode.Value; } private string GetOutputPath(string configuration) { XPathNavigator matchNode = SelectSingleNode( string.Format("//D:Project/D:PropertyGroup[contains(@Condition, '{0}')]/D:OutputPath", configuration) ); if(matchNode == null) { throw new BuildException("指定したコンフィギュレーションに[OutputPath]要素が存在しません。"); } return Path.Combine(Project.BaseDirectory, matchNode.Value); } private void XCopy(string srcPath, string destPath) { Directory.CreateDirectory(destPath); foreach(string file in Directory.GetFiles(srcPath)) { File.Copy(file, Path.Combine(destPath, Path.GetFileName(file)), true ); } foreach(string dir in Directory.GetDirectories(srcPath)) { XCopy(dir, Path.Combine(destPath, Path.GetFileName(dir)) ); } } protected override void ExecuteTask() { string publishURL = GetPublishURL(); string outputPath = GetOutputPath(Configuration); ProcessStartInfo startInfo = new ProcessStartInfo( Path.Combine(Environment.GetEnvironmentVariable("windir"), @"Microsoft.NET\Framework\v2.0.50727\MSBuild.exe") ); startInfo.UseShellExecute = false; startInfo.RedirectStandardOutput = true; // 0: プロジェクトファイル名 // 1: コンフィギュレーション // 2: ログレベル startInfo.Arguments = string.Format("\"{0}\" /t:Publish /p:Configuration={1} /nologo /verbosity:{2}", ProjectFile, Configuration, Verbose ? "d" : "n" // d: 詳細 m: 普通 ); // 3: バージョン if(!string.IsNullOrEmpty(Version)) { startInfo.Arguments += string.Format(" /p:ApplicationVersion={0}", Version); } Process proc = Process.Start(startInfo); StreamReader stdout = proc.StandardOutput; // 順次出力 while(!stdout.EndOfStream) { Log(Level.Info, stdout.ReadLine()); } proc.WaitForExit(); XCopy( Path.Combine(outputPath, ProjectName + ".publish"), publishURL ); } protected override void InitializeTask(XmlNode taskNode) { base.InitializeTask(taskNode); if(!File.Exists(ProjectFile)) { throw new BuildException("プロジェクトファイルが存在しません。"); } document = new XPathDocument(ProjectFile); navigator = document.CreateNavigator(); nsmgr = new XmlNamespaceManager(navigator.NameTable); nsmgr.AddNamespace("D", "http://schemas.microsoft.com/developer/msbuild/2003"); } } }
使い方
ビルドファイル
<?xml version="1.0" encoding="shift-jis"?> <project xmlns="http://cozy/0.85/nant.xsd" name="ClickOnceApp" basedir="."default="publish"> <target name="publish"> <clickonce projectfile="ClickOnceApp.csproj" version="1.1.0.0" /> </target> </project>
ちなみに今回のソースをPopflyで公開してみたので、興味のある方はこれをインストールして、見てあげてください。
プロジェクト名は「NAnt-VS2005Tasks」です。