2010-02-11 63 views
47

比方说,我想创建一个静态文本文件附带的每个版本。我想要的文件与释放(如AssemblyInfo.cs指定)的版本号更新,但我不希望有手动执行此操作。确定组件版本

我希望我可以用一个生成后事件和饲料的版本号这样一个批处理文件:

call foo.bat $(AssemblyVersion) 

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

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

+0

读取一个最最适合你所有的答案。 'PostBuildEventDependsOn'是最高投票和最简单的。 (注意粘贴' – OzBob 2015-09-21 07:43:36

回答

15

如果你喜欢这些脚本方法也可能会为你工作:

如果您使用的是生成后事件,您可以使用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文件作为跟随S:

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% 

它使用sed的UNIX命令行工具,你可以从很多地方,比如在这里下载:http://unxutils.sourceforge.net/ - IIRC一个好的工作。

+0

我使用Pre-Build事件。现在,我有了Properties \ AssemblyInfo。cs或链接到%SolutionDir%\ GlobalAssemblyInfo.cs。如何检测AssemblyVersion是否位于Properties \ AssemblyInfo.cs或%SolutionDir%\ GlobalAssemblyInfo.cs中,然后获取版本......? – Kiquenet 2011-11-11 08:54:39

+0

也许你可以使用“IF [NOT] EXIST filename命令”功能?键入“if /?”在文档和一些示例的命令提示符下。 – Tuinstoelen 2011-11-11 13:24:10

1

我认为你能做的最好的事情是看看的MSBuild和MsBuild Extension Pack,使得后生成事件发生,并写入到您的测试文件,你应该能够编辑你的解决方案文件。

如果这太复杂了,那么您可以简单地创建一个小程序来检查您输出目录中的所有程序集,并在后期构建中执行它,您可以使用变量名称传递输出目录...例如后生成事件...

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

你也可以通过在文本文件中的位置......

11

作为一种变通方法我已经写了一个管理控制台应用程序,它采取目标作为参数,并返回版本号。

我仍然有兴趣听到一个简单的解决方案 - 但我张贴这种的情况下,任何人发现它是有用的。

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(); 

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

时特殊的'25'Unicode技巧是的,我确实发现这个很有用,谢谢。我不想使用unix工具,也不想使用MSBuild,所以我使用类似于这是由Winston和Rohan在这里提供的在一个项目的postbuild事件中,我使用2个参数调用这段代码,程序集的TargetPath以及程序集打包的安装项目的路径在安装程序的后期构建事件中,我调用msiinfo将版本数据移动到MSI,以便消费者可以看到他们正在加载的版本。谢谢。 – TonyG 2011-08-06 00:53:35

+0

这应该是可以接受的解决方案,因为filever似乎获取文件版本而不是内部程序集版本。我为我的应用程序使用汇编版本,因为它很容易自动增加。 – transistor1 2012-10-17 19:46:42

+0

这个命令行非常方便,我可以用它来更新安装程序的版本号,以匹配它正在安装的应用程序的版本。一行可以将版本号放入环境变量 – 2013-09-05 16:45:35

1

我已经开始增加一个独立的项目,最后建立并添加后生成事件到运行本身的项目。然后,我只是在那里以编程方式执行我的构建后步骤。

它使人们更方便做这样的东西。然后你可以检查你想要的组件的组件属性。到目前为止它的工作非常棒。

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

使用它作为一个后生成命令的申请后为您令人满意的运行:

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

如果(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>已经在它。不用担心,重新加载项目后,您可以将其重置为真正的构建后事件。

如今如许,大会版本可与此宏您后生成事件:

@(VersionNumber) 

完成!

+1

它输出的组装版本是:(版本)对我来说 – 2013-10-23 14:32:52

+1

它也适用于我。问题在于'25'通过Visual Studio中的后期编辑编辑器潜入,如果你编辑csproj @(目标 - >'%25(版本)'),你会看到它。当25被删除时,它就像一个魅力... – jmelhus 2013-12-03 18:25:24

+0

优秀的,找到了25偷偷摸摸(WTH是这样呢?)我有一个很好的自动化包构建。现在我只需要在释放模式下构建时有条件地触发,而且我们是金手指。谢谢! – 2014-01-28 19:23:49

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-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字节顺序标记,否则在最终文件中会出现奇怪的字节。

4

这个答案是布伦特阿里亚斯答案的一个小修改。他的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产生的确切包文件名,我现在用这个adaptated宏(在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> 

UPDATE 2017年5月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;))" />