問題: 実行可能ファイルをビルドするプロセスがあります。セットアップ/デプロイ プロジェクトのビルドを実行する前に、セットアップ/デプロイ プロジェクトの FileSystem/Common Documents フォルダーに含める必要があるファイルをビルドします。ファイル名が常に同じファイル名として作成される場合、これは非常に簡単です。ただし、プロセスが連続して実行されるたびに一意のファイル名を作成できるため、ファイル名を事前に決定できない場合があります。
質問: FileSystem/Common Documents フォルダにファイルをプログラムで追加するにはどうすればよいですか?
私の調査: カスタム アクションを調べましたが、これらのファイルを追加できるように、セットアップ/展開プロジェクトのファイル システムを参照する方法が不明です。
詳細 毎日のビルド プロセスの一環として、http://lucene.apache.org/ (Lucene) インデックスを作成します。このインデックスでは、*.cfs 形式のファイルに前日とは異なるファイル名を付けることができます。Visual Studio で vdproj ファイルを開き、ファイル システム エディターを使用して手動でファイル名を置き換えたくないため、より自動化されたアプローチが必要でした。
私たちのソリューション ソリューション として、http://www.ewaldhofman.nl/post/2011/04/06/Customize-Team-Build-2010-e28093-Part-16-Specify-the-relative-reference-path を使用しました。 aspx (Ewald Hofman の) TFS チーム ビルドに関する優れたチュートリアル。ここでは、vdproj ファイルを開き、事前に生成された Lucene インデックス ファイル名に従ってファイルを編集する独自のカスタム アクティビティを追加しながら、彼のチェックアウト アクティビティとチェックイン アクティビティを複製しました。
コード例
protected override void Execute(CodeActivityContext context)
{
string fileFullName = context.GetValue(this.FileFullName);
string dropFolder = context.GetValue(this.DropLocation);
string[] indexerNames = context.GetValue(this.LuceneIndexes);
try
{
//read the vdproj file into memory
string text = File.ReadAllText(fileFullName);
//for each lucene index folder
foreach (string index in indexerNames)
{
//traversing twice so that the lucene index and spell index can be handled
//these are subfolder names we use to segregate our normal lucene index from our spelling indexes.
foreach (string subFolderInLuceneIndex in new string[] { "en_US_9", "en_US_9_sp" })
{
//retrieve all the files in folder \\[DropFolder]\[index]\[subFolderInLuceneIndex]\*.cfs
foreach (string file in Directory.GetFiles(System.IO.Path.Combine(dropFolder, index, subFolderInLuceneIndex), "*.cfs"))
{
FileInfo cfsFile = new FileInfo(file);
context.TrackBuildMessage(string.Format("Exiting file in lucene index directory: {0}", cfsFile.FullName));
string fileNamePattern = ".+.cfs";
string div = Dividor(4);
//matching pattern for sourcepath ie("SourcePath" = "8:\\\\...\\[index]\\[subFolderInLuceneIndex]\\_0.cfs")
string sourcePattern = string.Format("(\".+{1}{0}{2}{0}{3})", div, index, subFolderInLuceneIndex, fileNamePattern);
//matching pattern for targetname ie("TargetName" = "8:_0.cfs")
string targetPattern = string.Format("(\"TargetName\"\\s=\\s\"8:{0})", fileNamePattern);
StringBuilder sb = new StringBuilder();
sb.Append(sourcePattern);
sb.Append("(.+\\r\\n.+)"); //carriage return between targetpattern and sourcepattern
sb.AppendFormat(targetPattern);
//(.+[index]\\\\[subFolderInLuceneIndex].+.cfs)(.+\r\n.+)(TargetName.+8:.+.cfs)
MatchCollection matches = Regex.Matches(text, sb.ToString(), RegexOptions.Multiline);
//if more than one match exists, a problem with the setup and deployment file exists
if (matches.Count != 1)
{
throw new Exception("There should exist one and only one match.");
}
else
{
foreach (Match match in matches)
{
string newText = text;
string existingPattern = match.Value;
if (match.Groups != null)
{
//if the value found using the match doesn't contain the filename, insert the filename
//into the text
if (!match.Value.Contains(cfsFile.Name))
{
//matched by sourcePattern
string sourceValue = match.Groups[1].Value;
//matched by targetPattern
string targetNameValue = match.Groups[3].Value;
int idIndex = targetNameValue.IndexOf("8:") + 2;
//get the old *.cfs file name
string oldFileName = targetNameValue.Substring(idIndex, targetNameValue.Length - idIndex);
//replace old cfs file name with new cfs file name in the target pattern
string newTargetNameValue = Regex.Replace(targetNameValue, oldFileName, cfsFile.Name);
//replace old cfs file name with new cfs file name in the source pattern
string newSourceValue = Regex.Replace(sourceValue, oldFileName, cfsFile.Name);
//construct the new text that will be written to the file
StringBuilder newSb = new StringBuilder();
newSb.Append(newSourceValue);
//account for the quote, carriage return and tabs. this ensures we maintain proper
//formatting for a vdproj file
newSb.Append("\"\r\n\t\t\t");
newSb.AppendFormat(newTargetNameValue);
newText = Regex.Replace(text, sb.ToString(), newSb.ToString(), RegexOptions.Multiline);
File.WriteAllText(fileFullName, newText);
context.TrackBuildMessage(string.Format("Text {0} replaced with {1}.", oldFileName, cfsFile.Name));
}
else
{
context.TrackBuildMessage("No change applied for current file.");
}
}
}
}
}
}
}
}
catch (Exception ex)
{
context.TrackBuildError(ex.ToString());
throw ex;
}
}
private static string Dividor(int n)
{
return new String('\\', n);
}