Определение версии сборки во время события после сборки
Предположим, я хотел создать статический текстовый файл, который поставляется с каждой версией. Я хочу, чтобы файл обновлялся с номером версии выпуска (как указано в AssemblyInfo.cs
), но я не хочу, чтобы это делать вручную.
Я надеялся, что смогу использовать событие post-build и передать номер версии в пакетный файл следующим образом:
call foo.bat $(AssemblyVersion)
Однако я не могу найти подходящую переменную или макрос для использования.
- ASP.NET MVC на IIS6
- .war vs .ear file
- Как развернуть SQL Server Compact Edition 4.0?
- Ошибка при развертывании артефакта в Nexus
- Как развернуть приложение JAX-RS?
Есть ли способ достичь этого, которого я пропустил?
- Универсальный ЭЛТ-модуль MSVC 2015 для локального развертывания приложений
- Каков наилучший способ использования веб-сервиса из VB6?
- Создание Windows Installer для программ на Java
- Сделать MSDeploy (Visual Studio) не удалять папку App_Data, но удалять все остальное
- Как изменить цвет фона в меню параметров?
- Как вручную установить веб-сервис на Tomcat 6?
- Лучшие практики ILMerge
- развертывание фреймворка zend на сервере
Если вы предпочитаете писать сценарии, эти методы могут также работать на вас:
Если вы используете событие post-build, вы можете использовать инструмент filever.exe, чтобы извлечь его из уже построенной сборки:
for /F "tokens=4" %%F in ('filever.exe /B /A /D bin\debug\myapp.exe') do ( set VERSION=%%F ) echo The version is %VERSION%
Найдите файл filever.exe здесь: http://support.microsoft.com/kb/913111
Если вы используете событие pre-build, вы можете извлечь его из файла AssemblyInfo.cs следующим образом:
set ASMINFO=Properties\AssemblyInfo.cs FINDSTR /C:"[assembly: AssemblyVersion(" %ASMINFO% | sed.exe "s/\[assembly: AssemblyVersion(\"/SET CURRENT_VERSION=/g;s/\")\]//g;s/\.\*//g" >SetCurrVer.cmd CALL SetCurrVer.cmd DEL SetCurrVer.cmd echo Current version is %CURRENT_VERSION%
Это использует инструмент командной строки unix sed, который вы можете скачать из многих мест, например здесь: http://unxutils.sourceforge.net/ – iirc, который работает нормально.
Если (1) вы не хотите загружать или создавать пользовательский исполняемый файл, который извлекает версию сборки, и (2) вы не возражаете редактировать файл проекта Visual Studio, тогда есть простое решение, позволяющее использовать макрос который выглядит следующим образом:
@ (Targets -> ‘% (Version)’)
@(VersionNumber)
Для этого выгрузите проект. Если проект где-то определяет свойство
$(PostBuildEventDependsOn); PostBuildMacros; echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)
В этом fragmentе уже есть пример
Теперь, как и было обещано, версия сборки доступна для вашего события post build с этим макросом:
@(VersionNumber)
Готово!
В качестве обходного пути я написал управляемое консольное приложение, которое принимает цель как параметр и возвращает номер версии.
Мне все еще интересно услышать более простое решение, но я отправляю его на тот случай, если кто-либо найдет его полезным.
using System; using System.IO; using System.Diagnostics; using System.Reflection; namespace Version { class GetVersion { static void Main(string[] args) { if (args.Length == 0 || args.Length > 1) { ShowUsage(); return; } string target = args[0]; string path = Path.IsPathRooted(target) ? target : Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + Path.DirectorySeparatorChar + target; Console.Write( Assembly.LoadFile(path).GetName().Version.ToString(2) ); } static void ShowUsage() { Console.WriteLine("Usage: version.exe "); } } }
Этот ответ является незначительной модификацией ответа Брент Ариас. Его PostBuildMacro отлично работал для меня до обновления версии Nuget.exe.
В последних выпусках Nuget обрезает несущественные части номера версии пакета, чтобы получить семантическую версию типа «1.2.3». Например, версия сборки «1.2.3.0» отформатирована Nuget.exe «1.2.3». И «1.2.3.1» отформатирован «1.2.3.1», как ожидалось.
Поскольку мне нужно вывести точное имя файла пакета, сгенерированное Nuget.exe, теперь я использую этот адаптированный макрос (протестирован в VS2015):
$(PostBuildEventDependsOn); PostBuildMacros; echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)
UPDATE 2017-05-24: Я исправил регулярное выражение таким образом: «1.2.0.0» будет переведен на «1.2.0», а не «1.2», как ранее закодировано.
И чтобы ответить на комментарий Ehryk Apr, вы можете адаптировать регулярное выражение, чтобы сохранить только часть номера версии. В качестве примера, чтобы сохранить «Major.Minor», замените:
От
Я думаю, что самое лучшее, что вы можете сделать, это посмотреть, как MSBuild и MsBuild Extension Pack вы сможете редактировать файл решения, чтобы происходило событие post build и записывалось в ваш тестовый файл.
Если это слишком сложно, вы можете просто создать небольшую программу, которая проверяет все сборки в вашем выходном каталоге и выполняет их в post build, вы можете передать в выходной каталог с использованием имени переменной … например, в событии post build. ..
AssemblyInspector.exe “$ (TargetPath)”
class Program { static void Main(string[] args) { var assemblyFilename = args.FirstOrDefault(); if(assemblyFilename != null && File.Exists(assemblyFilename)) { try { var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFilename); var name = assembly.GetName(); using(var file = File.AppendText("C:\\AssemblyInfo.txt")) { file.WriteLine("{0} - {1}", name.FullName, name.Version); } } catch (Exception ex) { throw; } } } }
Вы также можете передать местоположение текстового файла …
Я начал добавлять отдельный проект, который строит последний, и добавляет событие post build для этого проекта, который запускается сам. Затем я просто программным образом выполняю свои шаги для сборки сообщений.
Это делает намного проще делать такие вещи. Затем вы можете просто проверить атрибуты сборки любой сборки, которую хотите. Пока это работает довольно просто.
Из этого я понимаю …
Вам нужен генератор событий post build.
1. Шаг: Написание генератора
/* * Author: Amen RA * # Timestamp: 2013.01.24_02:08:03-UTC-ANKH * Licence: General Public License */ using System; using System.IO; namespace AppCast { class Program { public static void Main(string[] args) { // We are using two parameters. // The first one is the path of a build exe, ie: C:\pathto\nin\release\myapp.exe string exePath = args[0]; // The second one is for a file we are going to generate with that information string castPath = args[1]; // Now we use the methods below WriteAppCastFile(castPath, VersionInfo(exePath)); } public static string VersionInfo(string filePath) { System.Diagnostics.FileVersionInfo myFileVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(filePath); return myFileVersionInfo.FileVersion; } public static void WriteAppCastFile(string castPath, string exeVersion) { TextWriter tw = new StreamWriter(castPath); tw.WriteLine(@""); tw.WriteLine(@"
список- "); tw.WriteLine(@"
"); tw.Close(); } } }MyApp - New version! Release " + exeVersion + " is available. "); tw.WriteLine(@"" + exeVersion + " "); tw.WriteLine(@"http://www.example.com/pathto/updates/MyApp.exe "); tw.WriteLine(@"http://www.example.com/pathto/updates/MyApp_release_notes.html "); tw.WriteLine(@"/* * Author: Amen RA * # Timestamp: 2013.01.24_02:08:03-UTC-ANKH * Licence: General Public License */ using System; using System.IO; namespace AppCast { class Program { public static void Main(string[] args) { // We are using two parameters. // The first one is the path of a build exe, ie: C:\pathto\nin\release\myapp.exe string exePath = args[0]; // The second one is for a file we are going to generate with that information string castPath = args[1]; // Now we use the methods below WriteAppCastFile(castPath, VersionInfo(exePath)); } public static string VersionInfo(string filePath) { System.Diagnostics.FileVersionInfo myFileVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(filePath); return myFileVersionInfo.FileVersion; } public static void WriteAppCastFile(string castPath, string exeVersion) { TextWriter tw = new StreamWriter(castPath); tw.WriteLine(@""); tw.WriteLine(@"
- "); tw.WriteLine(@"
"); tw.Close(); } } }MyApp - New version! Release " + exeVersion + " is available. "); tw.WriteLine(@"" + exeVersion + " "); tw.WriteLine(@"http://www.example.com/pathto/updates/MyApp.exe "); tw.WriteLine(@"http://www.example.com/pathto/updates/MyApp_release_notes.html "); tw.WriteLine(@"
2. Шаг: использование его в качестве команды post build в нашей среде IDE
После того, как приложение работает удовлетворительно для вас:
В среде разработки IDE используйте следующую командную строку для событий пост-сборки.
C:\Projects\pathto\bin\Release\AppCast.exe "C:\Projects\pathto\bin\Release\MyApp.exe" "c:\pathto\www.example.com\root\pathto\updates\AppCast.xml"
Если у вас есть проект библиотеки, вы можете попробовать использовать утилиту WMIC (доступную в windowsх). Вот пример. Хорошо – вам не нужно использовать внешние инструменты.
SET pathFile=$(TargetPath.Replace("\", "\\")) FOR /F "delims== tokens=2" %%x IN ('WMIC DATAFILE WHERE "name='%pathFile%'" get Version /format:Textvaluelist') DO (SET dllVersion=%%x) echo Found $(ProjectName) version %dllVersion%
Мне нужно было именно это для автоматического помещения числа в файл readme в выходной папке. В конце концов, как показал Уинстон Смит, небольшой внешний инструмент – это очень хорошее решение, и у него есть то преимущество, что вы можете отформатировать его, как хотите.
Это приложение выводит форматированную версию на консоль. Я использовал его в своих событиях после сборки, чтобы создать файл readme, вызвав его с помощью >>
чтобы перенаправить свой вывод в файл readme.
public class GetVerNum { static void Main(String[] args) { if (args.Length == 0) return; try { FileVersionInfo ver = FileVersionInfo.GetVersionInfo(args[0]); String version = "v" + ver.FileMajorPart.ToString() + "." + ver.FileMinorPart; if (ver.FileBuildPart > 0 || ver.FilePrivatePart > 0) version += "." + ver.FileBuildPart; if (ver.FilePrivatePart > 0) version += "." + ver.FilePrivatePart; Console.Write(version); } catch { } } }
Мои события после сборки:
"$(ProjectDir)\Readme\readme-header.txt" "$(ProjectDir)\Readme\GetVersionNumber.exe" "$(TargetPath)" >>"$(ProjectDir)\Readme\readme-header.txt" echo by Nyerguds>>"$(ProjectDir)\Readme\readme-header.txt" echo Build date: %date% %time% >> "$(ProjectDir)\Readme\readme-header.txt" echo.>>"$(ProjectDir)\Readme\readme-header.txt" copy /b "$(ProjectDir)\Readme\readme-header.txt" + "$(ProjectDir)\Readme\readme-body.txt" "$(TargetDir)\$(ProjectName).txt"
Я поместил все файлы, генерирующие readme, в папку \ Readme \ моего проекта; приложение, содержащее вышеуказанный код, и «readme-body.txt», содержащий фактический материал readme.
- Первая строка: создайте файл readme-header.txt в папке \ Readme \ моего проекта и поместите в нее имя программы. (
это трюк, который я нашел здесь: пакет Windows: эхо без новой строки ). Вы также можете сохранить эту строку в другом текстовом файле и просто скопировать ее в «readme-header.txt». - Вторая строка: запустите приложение для получения номера версии с только что созданным exe-файлом в качестве параметра и добавьте его вывод в файл заголовка.
- Третья строка: добавить в файл заголовка любые другие вещи (в данном случае, кредиты). Это также добавляет разрыв строки до конца.
Эти три вместе дают вам файл «readme-header.txt» с «My Application v1.2.3 by Nyerguds», за которым следует разрыв строки. Затем я добавляю дату сборки и другую открытую строку и копирую файл заголовка и файл тела readme вместе с одним файлом в окончательной папке сборки. Обратите внимание, что я специально использую двоичную копию, иначе она дает нечетные результаты. Вы должны убедиться, что файл body не содержит отметки порядка байтов UTF-8 в начале, или вы получаете странные байты в конечном файле.