在构建后事件期间确定程序集版本

问题描述 投票:52回答:10

假设我想创建一个随每个版本一起提供的静态文本文件。我希望使用版本的版本号(在AssemblyInfo.cs中指定)更新文件,但我不想手动执行此操作。

我希望我可以使用post-build事件并将版本号提供给批处理文件,如下所示:

call foo.bat $(AssemblyVersion)

但是我找不到任何合适的变量或宏来使用。

有没有办法实现这一点,我错过了?

c# .net visual-studio deployment visual-studio-2005
10个回答
16
投票

如果您更喜欢编写脚本,这些方法可能对您有用:

如果您使用的是构建后事件,则可以使用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

如果您正在使用预构建事件,则可以将其从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,一个正常工作。


0
投票

我寻找相同的功能,我在MSDN上找到了解决方案。 https://social.msdn.microsoft.com/Forums/vstudio/de-DE/e9485c92-98e7-4874-9310-720957fea677/assembly-version-in-post-build-event?forum=msbuild

$(ApplicationVersion)为我做了这份工作。

编辑:

好吧,我刚刚看到问题$(ApplicationVersion)不是来自AssemblyInfo.cs,它是项目属性中定义的PublishVersion。它仍然以一种简单的方式为我完成工作。所以也许有人也需要它。

另一种方案:

您可以在PostBuild上调用PowerShell脚本,在这里您可以直接从Assembly阅读AssemblyVersion。我用TargetDir作为参数调用脚本

PostBuild命令:

PowerShell -ExecutionPolicy Unrestricted $(ProjectDir)\somescript.ps1 -TargetDir $(TargetDir)

PowerShell脚本:

param(
    [string]$TargetDir
)

$Version = (Get-Command ${TargetDir}Example.exe).FileVersionInfo.FileVersion

这样您将从AssemblyInfo.cs获取版本


85
投票

如果(1)您不想下载或创建检索程序集版本的自定义可执行文件,并且(2)您不介意编辑Visual Studio项目文件,那么有一个简单的解决方案允许您使用宏看起来像这样:

@(目标 - > '%(版)')

@(VersionNumber)

要完成此任务,请卸载您的项目。如果某个项目定义了一个<PostBuildEvent>属性,请将其从项目中删除并暂时保存在其他位置(记事本?)。然后在项目的最后,就在结束标记之前,放置:

<Target Name="PostBuildMacros">
  <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
    <Output TaskParameter="Assemblies" ItemName="Targets" />
  </GetAssemblyIdentity>
  <ItemGroup>
    <VersionNumber Include="@(Targets->'%(Version)')"/>
  </ItemGroup>
</Target>
<PropertyGroup>
  <PostBuildEventDependsOn>
    $(PostBuildEventDependsOn);
    PostBuildMacros;
  </PostBuildEventDependsOn>    
  <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent>
</PropertyGroup>

此代码段中已包含一个示例<PostBuildEvent>。不用担心,您可以在重新加载项目后将其重置为真正的构建后事件。

现在按照承诺,使用此宏可以为您的post build事件提供程序集版本:

@(VersionNumber)

完成!


12
投票

作为一种解决方法,我编写了一个托管控制台应用程序,它将目标作为参数,并返回版本号。

我仍然有兴趣听一个更简单的解决方案 - 但我发布这个以防其他人发现它有用。

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 <target>");
        }
    }
}

7
投票

这个答案是布伦特阿里亚斯答案的一个小修改。他的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中测试):

<Target Name="PostBuildMacros">
  <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
    <Output TaskParameter="Assemblies" ItemName="Targets" />
  </GetAssemblyIdentity>
  <ItemGroup>
    <VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(\.0+)$&quot;, &quot;$1&quot;))" />
  </ItemGroup>
</Target>
<PropertyGroup>
  <PostBuildEventDependsOn>
    $(PostBuildEventDependsOn);
    PostBuildMacros;
  </PostBuildEventDependsOn>    
  <PostBuildEvent>echo HELLO, THE ASSEMBLY VERSION IS: @(VersionNumber)</PostBuildEvent>
</PropertyGroup>

更新2017-05-24:我以这种方式纠正了正则表达式:“1.2.0.0”将被翻译为“1.2.0”而不是之前编码的“1.2”。


要回答Ehryk Apr的评论,您可以调整正则表达式以仅保留版本号的某些部分。作为保留“Major.Minor”的示例,替换:

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^(.+?)(\.0+)$&quot;, &quot;$1&quot;))" />

通过

<VersionNumber Include="$([System.Text.RegularExpressions.Regex]::Replace(&quot;%(Targets.Version)&quot;, &quot;^([^\.]+)\.([^\.]+)(.*)$&quot;, &quot;$1.$2&quot;))" />

1
投票

我认为您可以做的最好的事情是查看MSBuild和MsBuild Extension Pack,您应该能够编辑解决方案文件,以便发生后期构建事件并写入您的测试文件。

如果这太复杂了,那么您可以简单地创建一个小程序来检查输出目录中的所有程序集并在后构建时执行它,您可以使用变量名称传递输出目录...例如在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;
            }
        }
    }
}

你也可以传入文本文件位置...


1
投票

我已经开始添加一个单独的项目,该项目最后构建并向自己运行的项目添加一个post build事件。然后我只是在那里以编程方式执行我的后期构建步骤。

这使得做这样的事情变得容易多了。然后,您可以检查所需的任何程序集的程序集属性。到目前为止,它的工作非常棒。


1
投票

据我所知......

您需要一个生成器用于后期构建事件。

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, i.e.: 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(@"<?xml version=""1.0"" encoding=""utf-8""?>");
            tw.WriteLine(@"<item>");
            tw.WriteLine(@"<title>MyApp - New version! Release " + exeVersion + " is available.</title>");
            tw.WriteLine(@"<version>" + exeVersion + "</version>");
            tw.WriteLine(@"<url>http://www.example.com/pathto/updates/MyApp.exe</url>");
            tw.WriteLine(@"<changelog>http://www.example.com/pathto/updates/MyApp_release_notes.html</changelog>");
            tw.WriteLine(@"</item>");
            tw.Close();
        }
    }
}

2.步骤:在IDE中将其用作post build命令

应用程序运行满意之后:

在开发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"

1
投票

如果您有一个库项目,您可以尝试使用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%

0
投票

我需要将此数字自动放入输出文件夹中的自述文件中。最后,正如温斯顿史密斯所展示的那样,一个小型的外部工具是一个非常好的解决方案,并且它具有您可以根据需要进行格式化的优势。

此应用程序将格式化版本输出到控制台。我在后期构建事件中使用它来构建自述文件,方法是使用>>将其输出重定向到自述文件。

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 { }
    }
}

我的后期制作活动:

<nul set /p dummyset=My Application > "$(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-body.txt”。

  • 第一行:在我的项目的\ Readme \文件夹中创建“readme-header.txt”文件,并将程序名称放在其中。 (<nul set /p dummyset=是我在这里找到的一个技巧:Windows batch: echo without new line)。您也可以将此字符串存储在另一个文本文件中,然后将其复制到“readme-header.txt”。
  • 第二行:使用新生成的exe文件作为参数运行版本号检索应用程序,并将其输出添加到头文件中。
  • 第三行:将任何其他内容(在本例中为信用)添加到头文件中。这也为最后添加了换行符。

这三个一起给你一个“readme-header.txt”文件,其中包含“My Application v1.2.3 by Nyerguds”,然后是换行符。然后我添加构建日期和另一个打开的行,并将头文件和自述文件文件一起复制到最终构建文件夹中的一个文件。请注意,我特意使用二进制副本,否则它会产生奇怪的结果。您必须确保正文文件在开始时不包含UTF-8字节顺序标记,否则您将在最终文件中获得奇怪的字节。

© www.soinside.com 2019 - 2024. All rights reserved.