Программное добавление файлов в файловую систему в проекте установки .NET

Проблема: у нас есть процесс, который создает наш исполняемый файл. Перед запуском сборки проекта установки/развертывания я создаю файлы, которые необходимо включить в папку FileSystem/Common Documents проекта установки/развертывания. В случаях, когда имя файла всегда создается как одно и то же имя файла, это довольно просто; однако у меня есть случай, когда я не могу заранее определить имя файла, поскольку процесс может и будет создавать уникальное имя файла при каждом последующем запуске.

Вопрос: как программно добавлять файлы в папку FileSystem/Common Documents?

Мои исследования. Я изучил пользовательские действия, но не знаю, как сослаться на файловую систему проекта установки/развертывания, чтобы добавить эти файлы.

Дополнительная информация В рамках нашего ежедневного процесса сборки мы создаем http://lucene.apache.org/(Lucene) индексы, в которых файлы в формате *.cfs могут иметь другие имена файлов, чем в предыдущий день. Поскольку мы не хотим открывать файл vdproj в Visual Studio и заменять имя файла вручную с помощью редактора файловой системы, нам нужен более автоматизированный подход.

Наше решение В качестве решения я использовал http://www.ewaldhofman.nl/post/2011/04/06/Customize-Team-Build-2010-e28093-Part-16-Specify-the-relative-reference-path.aspx (Эвальд Хофман) — отличное руководство по TFS Team Build. В этом я воспроизвел его действия по извлечению и возврату, добавив при этом свое собственное пользовательское действие, которое открывает файл 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);
    }


person JDennis    schedule 16.05.2012    source источник
comment
Это не имеет никакого смысла. Если процесс создает файлы после его установки, что, конечно, очень часто, то вам не нужно ничего делать для этого в установщике.   -  person Hans Passant    schedule 16.05.2012
comment
@HansPassant Я думаю, ему нужно создать несколько файлов во время самого процесса сборки, и их следует добавить в проект установки.   -  person Adriano Repetti    schedule 16.05.2012
comment
Я не знаю ни одного способа сделать это. Я бы изменил проект установки на лету из вашего процесса (в конце концов, это всего лишь XML), прежде чем он будет построен (так что вы сохраните на своем сервере TFS чистую версию) самого проекта. .   -  person Adriano Repetti    schedule 16.05.2012
comment
@HansPassant: вышеупомянутые файлы создаются до сборки проекта установки/развертывания. Хотя редактор файловой системы позволяет мне легко добавлять файлы в проект установки/развертывания, где имя файла предопределено, сборка проекта установки/развертывания завершается ошибкой, если имена файлов не совпадают.   -  person JDennis    schedule 16.05.2012
comment
@Adriano Я рассматривал возможность редактирования файла vdproj перед сборкой. Насколько я могу судить, файл vdproj больше похож на JSON, чем на XML.   -  person JDennis    schedule 16.05.2012
comment
@Adriano Оказывается, csproj находится в XML, а vdproj - в JSON. Спасибо за ваш комментарий.   -  person JDennis    schedule 16.05.2012
comment
@JDennis JSON? Какой сюрприз! Хорошо знать...   -  person Adriano Repetti    schedule 16.05.2012
comment
@Adriano Оказывается, это довольно близко к JSON, но не к JSON. Спасибо еще раз. Я думаю, что я пойду с вашим предложением.   -  person JDennis    schedule 16.05.2012


Ответы (1)


Вам нужно добавить необходимую информацию в .V?PROJ (например, в C++ у вас есть расширение файла VDPROJ). Необходимая информация для добавления в раздел File файла установщика. Это не одноэтапный процесс, пожалуйста, просмотрите файл проекта установщика (файл VDPROJ) и поймите его.

person Jyoti Prakash Lal    schedule 31.07.2012
comment
К описанной мной проблеме было два требования. 1. Мне нужно было программно добавить файлы. 2. Добавляйте файлы без заданного имени. Уровень понимания файла VDPROJ не вызывает сомнений. Гибкость, которую обеспечивают файлы VDPROJ. Проще говоря... не все возможно в данной технологии. Переход на Wix был решением. - person JDennis; 22.04.2016