2010-02-11 8 views
47

Angenommen, ich wollte eine statische Textdatei erstellen, die mit jedem Release ausgeliefert wird. Ich möchte, dass die Datei mit der Versionsnummer des Releases aktualisiert wird (wie in AssemblyInfo.cs angegeben), aber ich möchte das nicht manuell machen müssen.Ermitteln der Assemblyversion während eines Post-Build-Ereignisses

Ich hatte gehofft, ich einen Post-Build-Ereignis verwenden könnte und die Versionsnummer zu einer Batch-Datei wie folgt füttern:

call foo.bat $(AssemblyVersion) 

Allerdings kann ich jede geeignete Variable oder Makro zu verwenden, nicht finden.

Gibt es eine Möglichkeit, dies zu erreichen, die ich verpasst habe?

+0

lesen alle Antworten für die eine, die Ihnen am besten geeignet ist. Das 'PostBuildEventDependsOn' ist das am höchsten gewählte und einfachste. (Achten Sie auf den speziellen '25' Unicode-Trick beim Einfügen ' – OzBob

Antwort

15

Wenn Sie diese Methoden scripting auch lieber für Sie arbeiten könnte:

Wenn Sie die Post-Build-Ereignis verwenden, können Sie das Filever.exe Tool verwenden sie aus dem bereits eingebauten Baugruppe greifen :

for /F "tokens=4" %%F in ('filever.exe /B /A /D bin\debug\myapp.exe') do (
    set VERSION=%%F 
) 
echo The version is %VERSION% 

Get Filever.exe von hier: http://support.microsoft.com/kb/913111

Wenn Sie die Pre-Build-Ereignis verwenden, können Sie es aus der Datei AssemblyInfo.cs nehmen, wie folgt 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% 

Dies verwendet das Unix-Kommandozeilen-Tool sed, die man aus vielen Orten herunterladen kann, wie hier: http://unxutils.sourceforge.net/ - iirc dass man ok funktioniert.

+0

Ich benutze Pre-Build Event. Jetzt habe ich Properties \ AssemblyInfo.cs oder verknüpfen Sie mit% SolutionDir% \ GlobalAssemblyInfo.cs. Wie kann ich feststellen, ob AssemblyVersion in Properties \ AssemblyInfo.cs oder in% SolutionDir% \ GlobalAssemblyInfo.cs ist, und dann die Version abrufen ... ?? – Kiquenet

+0

Vielleicht können Sie die Funktion "IF [NOT] EXIST Dateiname Befehl" verwenden? Tippen Sie "wenn /?" an einer Eingabeaufforderung für Dokumentation und einige Beispiele. – Tuinstoelen

1

Ich denke, das Beste, was Sie tun können, ist MSBuild und MsBuild Extension Pack Sie sollten in der Lage sein, Ihre Lösungsdatei zu bearbeiten, so dass ein Post-Build-Ereignis auftritt und in Ihre Testdatei schreibt.

Wenn dies zu kompliziert ist, dann könnten Sie einfach ein kleines Programm erstellen, das alle Assemblies in Ihrem Ausgabeverzeichnis prüft und es bei der Erstellung ausführt, Sie könnten das Ausgabeverzeichnis mit dem Variablennamen übergeben ... zum Beispiel in der event 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; 
      } 
     } 
    } 
} 

Sie auch in der Textdatei Ort passieren könnte ...

11

Zur Umgehung des Problems habe ich geschrieben ein verwaltete Konsolenanwendung, die das Ziel übernimmt als Parameter und gibt die Versionsnummer zurück.

Ich bin immer noch daran interessiert, eine einfachere Lösung zu hören - aber ich bin dieses Posting falls jemand anderes es nützlich findet.

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

Ja, ich fand das nützlich, danke. Ich möchte keine Unix-Tools verwenden und ich möchte MSBuild nicht verwenden, also habe ich ähnlichen Code verwendet Dies wird hier von Winston und Rohan bereitgestellt. Im postbuild-Ereignis eines Projekts rufe ich diesen Code mit zwei Argumenten auf, dem TargetPath der Assembly und dem Pfad zum Setup-Projekt, in dem die Assembly gepackt ist. Im Post-Build-Ereignis des Setups Ich rufe msiinfo auf, um die Versionsdaten in die MSI zu verschieben, damit die Verbraucher die Version sehen können, die sie laden Danke, – TonyG

+0

Dies sollte wahrscheinlich die akzeptierte Lösung sein, da Filever die Dateiversion und nicht die interne Assemblyversion zu bekommen scheint. Ich verwende die Assembly-Version für meine App, weil sie einfach automatisch inkrementiert werden kann – transistor1

+0

Diese Befehlszeile ist ziemlich praktisch, ich kann sie verwenden, um die Versionsnummer eines Installationsprogramms zu aktualisieren, damit es der Version der App entspricht, die es installiert. Eine Zeile kann die Versionsnummer in eine Umgebungsvariable setzen –

1

Ich habe begonnen, ein separates Projekt hinzuzufügen, das zuletzt erstellt und ein Postbuild-Ereignis zu dem Projekt hinzufügt, das selbst ausgeführt wird. Dann führe ich meine Post-Build-Schritte programmatisch dort durch.

Es macht es viel einfacher, so etwas zu tun. Dann können Sie einfach die Baugruppenattribute der von Ihnen gewünschten Baugruppe prüfen. Bis jetzt funktioniert es ziemlich gut.

1

Von, was ich verstehe ...

Sie benötigen einen Generator für Veranstaltungen Post-Build.

1. Schritt: Schreiben eines Generator

/* 
* 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. Schritt: Mit ihm als Post Build-Befehl in unserem IDE

Nach der Anwendung läuft satisfyingly für Sie:

Verwenden Sie in Ihrer Entwicklungs-IDE die folgende Befehlszeile für Post-Build-Ereignisse.

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

Wenn (1) Sie nicht wollen, eine benutzerdefinierte ausführbare Datei, die die Assembly Version abruft und (2) es Ihnen nichts ausmacht Bearbeiten der Visual Studio-Projektdatei, dann herunterladen oder erstellen gibt es eine einfache Lösung das Sie erlaubt, einen Makro zu verwenden, die wie folgt aussieht:

@ (Targets -> '% (Version)')

@(VersionNumber) 

um dies zu erreichen, entladen Ihr Projekt. Wenn das Projekt irgendwo eine < Eigenschaft PostBuildEvent > definiert, schneiden Sie es aus dem Projekt und speichern Sie es woanders vorübergehend (Notizblock?). Dann am Ende des Projektes, kurz vor dem End-Tag, legen Sie diese:

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

Dieser Code-Schnipsel hat ein Beispiel <Postbuildevent> schon drin. Keine Sorge, Sie können es auf Ihr echtes Post-Build-Ereignis zurücksetzen, nachdem Sie das Projekt erneut geladen haben.

Nun, wie versprochen, ist die Montage Version zu Ihrem Beitrag Buildereignis mit diesem Makro zur Verfügung:

@(VersionNumber) 

Fertig!

+1

Es gibt die Assembly-Version ist: (Version) für mich –

+1

Es hat auch für mich. Problem war, dass '25' über den Post-Build-Editor in Visual Studio eingeschleust wurde, Sie werden es sehen, wenn Sie csproj @ (Targets -> '% 25 (Version)') bearbeiten. Es funktioniert wie ein Zauber, wenn 25 entfernt wird ... – jmelhus

+0

Ausgezeichnet, nachdem ich die 25 gefunden habe, die sich eingeschlichen haben (WTH ist das überhaupt?) Ich habe ein schön automatisiertes Paket gebaut. Jetzt muss ich es nur noch bedingungslos aktivieren, wenn ich im Release-Modus baue und wir sind golden. Vielen Dank! –

0

Ich brauchte genau das für die automatische Eingabe der Nummer in die Readme-Datei im Ausgabeordner. Am Ende, wie Winston Smith gezeigt hat, ist ein kleines externes Tool eine sehr gute Lösung dafür, und es hat den Vorteil, dass Sie es beliebig formatieren können.

Diese App gibt die formatierte Version an die Konsole aus. Ich habe es in meinen Post-Build-Ereignissen verwendet, um die Readme-Datei zu erstellen, indem ich sie mit >> anrief, um ihre Ausgabe in die Readme-Datei umzuleiten.

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

Meine Post-Build-Ereignisse:

<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" 

Ich habe alle die Readme-verwandte Themen im Ordner meines Projektes \ Readme \ erzeugen; die App, die den obigen Code enthält, und die "readme-body.txt", die das eigentliche Readme-Zeug enthält.

  • Erste Zeile: Erstellen Sie die Datei "readme-header.txt" im Ordner \ Readme \ meines Projekts und geben Sie den Programmnamen ein. (Die <nul set /p dummyset= ist ein Trick, den ich hier gefunden habe: Windows batch: echo without new line). Sie könnten diese Zeichenfolge auch in einer anderen Textdatei speichern und diese stattdessen in "readme-header.txt" kopieren.
  • Zweite Zeile: Führen Sie die App zum Abrufen der Versionsnummer mit der frisch generierten EXE-Datei als Parameter aus und fügen Sie ihre Ausgabe zur Header-Datei hinzu.
  • Dritte Zeile: Fügen Sie der Header-Datei weitere Daten hinzu (in diesem Fall Credits). Dies fügt auch einen Zeilenumbruch zum Ende hinzu.
  • Diese drei zusammen geben Ihnen eine "readme-header.txt" -Datei mit "Meine Anwendung v1.2.3 von Nyerguds", gefolgt von einem Zeilenumbruch, darin. Dann füge ich das Erstellungsdatum und eine andere offene Zeile hinzu und kopiere die Header-Datei und die Readme-Body-Datei zusammen in eine Datei im endgültigen Erstellungsordner. Beachten Sie, dass ich speziell Binärkopie verwende, andernfalls gibt es ungerade Ergebnisse. Sie müssen sicherstellen, dass die Body-Datei am Anfang keine UTF-8-Byte-Reihenfolge enthält, oder Sie erhalten merkwürdige Bytes in Ihrer endgültigen Datei.

    4

    Diese Antwort ist eine geringfügige Änderung der Antwort von Brent Arias. Sein PostBuildMacro funktionierte für mich bis zu einem Versionsupdate von Nuget.exe ziemlich gut.

    In den letzten Versionen schneidet Nuget nicht signifikante Teile der Paketversionsnummer ab, um eine semantische Version wie "1.2.3" zu erhalten. Zum Beispiel wird die Assembly-Version "1.2.3.0" von Nuget.exe "1.2.3" formatiert. Und "1.2.3.1" ist wie erwartet "1.2.3.1" formatiert.

    Wie ich die genauen Paket Dateinamen von Nuget.exe erzeugt ableiten muß, verwende ich jetzt diesen Adaptated Makro (in VS2015 getestet):

    <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.05.24: ich korrigierte die Regex auf diese Weise: "1.2.0.0" wird in "1.2.0" übersetzt und nicht "1.2" wie zuvor codiert.


    Und auf einen Kommentar von Ehryk April zu beantworten, können Sie die regex passen nur einen Teil der Versionsnummer zu halten. Als Beispiel „major.minor“ zu halten, ersetzen:

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

    von

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