問題: 在生成我們的可執行文件的過程中。在運行setup/deploy項目的構建之前,我會構建需要包含在setup/deploy項目的FileSystem/Common Documents文件夾中的文件。在文件名始終以相同文件名創建的情況下,這非常簡單;但是,我有一種情況,我無法預先確定文件名,因爲進程可以並且會在每次連續運行時創建唯一的文件名。以編程方式將文件添加到.NET安裝項目中的文件系統
問題: 如何以編程方式將文件添加到FileSystem/Common Documents Folder?
我的研究: 我特地到自定義操作,但我不確定如何引用設置的文件系統/部署的項目,所以我可以添加這些文件。
進一步詳細 作爲我們每日構建過程的一部分,我們創建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(埃瓦爾德福滿)目前關於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);
}
這沒有任何意義。如果進程在*安裝後創建文件*,當然很常見,那麼您無需在安裝程序中爲此做任何事情。 –
@HansPassant我猜他需要在構建過程中創建一些文件,並將它們添加到安裝項目中。 –
我不知道有任何方法可以做到這一點。我會在你的過程中立即修改安裝項目(畢竟它只是XML),然後它將會被構建(所以你會在你的TFS服務器上保留一個_clean_版本)。 –