web-dev-qa-db-ja.com

ビルド後のイベント中にアセンブリバージョンを決定する

各リリースに付属する静的テキストファイルを作成したいとします。ファイルをリリースのバージョン番号(AssemblyInfo.cs)、しかし、私はこれを手動で行う必要はありません。

ビルド後のイベントを使用して、バージョン番号を次のようなバッチファイルにフィードできることを望んでいました。

call foo.bat $(AssemblyVersion)

ただし、使用する適切な変数またはマクロが見つかりません。

私が見逃したこれを達成する方法はありますか?

52
Winston Smith

これらのメソッドのスクリプト作成を希望する場合は、次の方法も有効です。

ビルド後イベントを使用している場合、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。

16
Tuinstoelen

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

できた!

86
Brent Arias

回避策として、ターゲットをパラメーターとして受け取り、バージョン番号を返す管理コンソールアプリケーションを作成しました。

私はまだ簡単な解決策を聞くことに興味があります-しかし、私は他の誰かがそれを役に立つと思う場合にこれを投稿しています。

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>");
        }
    }
}
12
Winston Smith

この回答は、Brent Ariasの回答を少し修正したものです。彼の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>

PDATE 2017-05-24:この方法で正規表現を修正しました。「1.2.0.0」は、以前にコーディングした「1.2」ではなく「1.2.0」に変換されます。


また、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;))" />
7
Eric Boumendil

私が理解していることから...

ビルド後のイベントにはジェネレーターが必要です。

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"
1
Amen Ra

ライブラリプロジェクトがある場合は、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%
1
DolceVita

最後にビルドする別のプロジェクトを追加し、それ自体を実行するプロジェクトにビルド後イベントを追加し始めました。次に、そこでポストビルド手順をプログラムで実行します。

これにより、このようなことが簡単になります。次に、必要なアセンブリのアセンブリ属性を検査できます。これまでのところ、それは非常に素晴らしい働きをしています。

1
Joshua Evensen

できる最善のことは、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;
            }
        }
    }
}

テキストファイルの場所を渡すこともできます...

1
Rohan West

出力フォルダーのreadmeファイルに自動的に番号を入れるために、これがまさに必要でした。最終的に、Winston Smithが示したように、小さな外部ツールはそのための非常に優れたソリューションであり、必要に応じてフォーマットできるという利点があります。

このアプリは、フォーマットされたバージョンをコンソールに出力します。ビルド後のイベントでそれを使用して、>>で呼び出して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 { }
    }
}

ビルド後のイベント:

<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 \フォルダーに入れました。上記のコードを含むアプリ、および実際のreadmeを含む「readme-body.txt」。

  • 最初の行:プロジェクトの\ Readme \フォルダーに「readme-header.txt」ファイルを作成し、その中にプログラム名を入れます。 (<nul set /p dummyset=は私がここで見つけたトリックです: Windowsバッチ:改行なしのエコー )。この文字列を別のテキストファイルに保存し、代わりに「readme-header.txt」にコピーすることもできます。
  • 2行目:新しく生成されたexeファイルをパラメーターとして使用してバージョン番号取得アプリを実行し、その出力をヘッダーファイルに追加します。
  • 3行目:ヘッダーファイルに他のもの(この場合はクレジット)を追加します。これにより、最後に改行が追加されます。

これら3つを合わせると、「My Application v1.2.3 by Nyerguds」を含む「readme-header.txt」ファイルが作成され、その後に改行が続きます。次に、ビルド日付と別の開いている行を追加し、ヘッダーファイルとreadme本文ファイルを一緒に最終ビルドフォルダーの1つのファイルにコピーします。特にバイナリコピーを使用していることに注意してください。ボディファイルの先頭にUTF-8バイトオーダーマークが含まれていないことを確認する必要があります。そうしないと、最終ファイルに奇妙なバイトが入ります。

0
Nyerguds

同じ機能を探して、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スクリプトを呼び出すことができます。ここでは、アセンブリから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からバージョンを取得できます。

0
Momo