4

これが一般的なことなのかどうかはわかりませんが、個人的にはコードをビルドした回数を常に記録しています。つまり、私が呼び出しmakeた回数とビルドが成功した回数の両方です。

私の現在の解決策

ファイルをパラメーターとして受け取り、それを開き、内部の数値を増やして上書きする単純なコードがあります。makeこのコードは、呼び出されたときに最初にコンパイルされます。

その直後にが呼び出され、ライブラリをビルドするため./increase_build build.txtに呼び出した回数が増えます。make

次に、コードをコンパイルして lib ファイルを作成します ( を使用ar cq ...)。その後、./increase_build libbuild.txt成功したビルドの数をインクリメントする が呼び出されます。最後に、テストがビルドされます。

これは、私の Makefile の 1 つの例です。

気になった理由

バージョン管理を使い始めるまで、これは常にうまくいきました。問題はないように思えました。私は自分のライブラリの唯一の作成者であり、機能を 1 つずつ追加しています。

しかし、ある日、ブランチとマージをテストしていたので (自分では git を使用し、仕事では svn を使用しています)、ブランチに 1 つの機能を追加し、master で何かを変更して、2 つをマージしました。ビルド カウント ファイルの値が異なるようになりました。

問題

問題は、ブランチの時点で、ビルド カウントが 100 であるとしましょう。その後、ブランチに何かを書くと、ビルド カウントが 110 になります。マスター ブランチに何かを書くと、ビルド カウントが 120 になります。 2 つ、1 つは 110 で、もう 1 つは 120 です (ちなみにこれは矛盾しています)。正しい解決策は、ビルドを 130 に設定することです。

ただし、ブランチが開始されたコミットに戻ることができません (読みたくありません)。それが 100 だったことがわかるので、100+(110-100)+(120-100) = 130 を計算します! これを自動化してほしい

質問

質問は明らかです。これを行うにはどうすればよいですか? バージョン管理を行っているときに、ビルド カウント (コミット カウントではない!) を追跡するにはどうすればよいですか? バージョン管理システムを変更すると、問題が新たに発生するため、バージョン管理の機能に基づく回答は必要ありません。

私ができることは、ビルドごとにビルドカウントファイルに1行追加することでした。データと時間で何かを言います。ビルド番号は、ビルド カウント ファイルの行数になります。また、正確に同時に実行された 2 つのブランチで 2 つのビルドを取得しない限り、ファイルのマージは 2 つの結合にすぎません。

私は疑問に思っていますが、これに対するより良い解決策はありますか?私が望むもの (ビルド数) は努力する価値がありますか?

PS なぜ私がビルド数と成功ビルド数の両方でそれを行うのか疑問に思っているなら、それは単なる個人的なものです。コードを書いているときに小さなタイプミスやエラーが発生した場合に、どの程度再構築されるかを確認するのが好きです。

編集:私は C と C++ でプログラミングしているので、どちらのソリューションでもうまくいきます。

4

4 に答える 4

2

ビルド番号は現在のブランチの機能ではないため、別の方法で追跡する必要があります。私は git を使用しませんが、SVN の場合、特定のブランチを特定のタグにコピーし、そのタグに固有のアーティファクトを追加することで特定のブランチを構築するシステムが動作しています (ビルド番号は、追加するもの)、ビルドが成功した場合にのみコミットします。

言い換えれば、ビルドのみを行う指定された場所 (SVN のタグ名、または別のリポジトリである可能性があります) があり、これがビルドする唯一の場所であり、ビルド番号情報が保存される場所です。と更新されました。ビルドスクリプトは次のようになります

# I don't know git -- this is all very much pseudocode

# Where did you commit the code you want to build?
source=git://server/path/to/my/branch

# Replace builddir tree with yours
git replace git://server/special/place/build/thisproject with code from $source

cd /tmp
git checkout git://sever/special/place/build/thisproject into new builddir
cd builddir

update local version-controlled file buildnumber+=1

if make
    # Build was successful
    git commit buildnumber
    copy build artefacts to where-ever
endif

cd /tmp
rm -rf /tmp/builddir      

競合状態があります。誰かがあなたのビルド リクエストの後にチェックインしたが、どういうわけか最初にサーバーに到達した場合、あなたは彼らのチェックインをビルドすることになります。

これは、Hudson/Jenkins のように指定されたビルド ホストを使用することで、おそらくもっと簡単にすることができます。

于 2011-10-14T14:27:00.610 に答える
1

ビルド ログ (ビルドごとに 1 行) を使用したソリューションはかなり賢いようです。ビルドを実行しているマシンの IP (または Mac アドレス) を追加してタイムスタンプを実行すると、行が重複するリスクがなくなります。ただし、VCS によっては、おそらくビルド ログ ファイルを手動でマージする必要があります。git を使用すると、マージが常に両方のバージョンを保持するように構成できます (最終的には行を日付順に並べ替えるなど)。

于 2011-10-10T13:37:42.490 に答える
1

それが最も実用的だと思われるので、私自身のアイデアの実装を回答として投稿して受け入れるつもりです。

だからここに解決策があります:

  • ビルドごとに、次のデータを含むビルド ファイルに 1 行追加します。
    • 日にち
    • 時間
    • 乱数
  • すべてのマージで、両方のビルド ファイルからの行を保持します
  • ビルド数は、ビルド ファイルの合計行数です。

ビルド ファイルの各行は一意である必要があります。日付と時刻は、それを非常にユニークなものにします。2 人のユーザーが同時に自分のブランチでビルドを発行することはほとんどありません。ただし、発生する可能性があります。したがって、乱数が生成され、その可能性を減らすために追加されます。

ただし、問題が 1 つあります。でシードsrandするとtime(NULL)、両方のビルドがおそらく同時に行われるため、生成される数もたまたま同じになる可能性があります。したがって、乱数ジェネレーターには、clock()または のミリ秒部分などの別の数値をシードすることができますgettimeofday()。ランダムに生成されなくても、乱数の代わりにそれらの数値自体を配置できます。

それでも 2 行が同じ結果になった場合は、ダチョウのアルゴリズムを適用します。

アップデート:

私はそれを実装し、すべてが正常に動作します。最後に、clock_gettime(CLOCK_MONOTONIC, ...)この関数で得られたナノ秒を乱数として使用して印刷しました。私が使用しなかった理由はclock()、プログラムが非常に短いため、実行速度が の解像度よりも低く、結果としてclock()0 を取得し続けたからです。

アップデート:

これが私が書いた最終的なコードです (その一部は別の場所から盗用されています!)。-lrt一部のプラットフォームでは必要になる場合があります。

/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>

struct timespec
{
    long tv_sec;
    long tv_nsec;
};

/* Note: I copy-pasted this from internet (https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows/5404467#5404467)
 * I tweaked it to return nanoseconds instead of microseconds
 * It is much more complete than just finding tv_nsec, but I'm keeping it for possible future use. */
LARGE_INTEGER getFILETIMEoffset(void)
{
    SYSTEMTIME s;
    FILETIME f;
    LARGE_INTEGER t;

    s.wYear = 1970;
    s.wMonth = 1;
    s.wDay = 1;
    s.wHour = 0;
    s.wMinute = 0;
    s.wSecond = 0;
    s.wMilliseconds = 0;
    SystemTimeToFileTime(&s, &f);
    t.QuadPart = f.dwHighDateTime;
    t.QuadPart <<= 32;
    t.QuadPart |= f.dwLowDateTime;
    return t;
}

int clock_gettime(int X, struct timespec *tv)
{
    LARGE_INTEGER t;
    FILETIME f;
    double microseconds;
    static LARGE_INTEGER offset;
    static double frequencyToNanoseconds;
    static int initialized = 0;
    static BOOL usePerformanceCounter = 0;

    if (!initialized)
    {
        LARGE_INTEGER performanceFrequency;
        initialized = 1;
        usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
        if (usePerformanceCounter)
        {
            QueryPerformanceCounter(&offset);
            frequencyToNanoseconds = (double)performanceFrequency.QuadPart/1000000000.0;
        }
        else
        {
            offset = getFILETIMEoffset();
            frequencyToNanoseconds = 0.010;
        }
    }
    if (usePerformanceCounter)
        QueryPerformanceCounter(&t);
    else
    {
        GetSystemTimeAsFileTime(&f);
        t.QuadPart = f.dwHighDateTime;
        t.QuadPart <<= 32;
        t.QuadPart |= f.dwLowDateTime;
    }

    t.QuadPart -= offset.QuadPart;
    microseconds = (double)t.QuadPart/frequencyToNanoseconds;
    t.QuadPart = microseconds;
    tv->tv_sec = t.QuadPart/1000000000;
    tv->tv_nsec = t.QuadPart%1000000000;
    return 0;
}

#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 0       /* not used anyway */
#endif
#endif

int main(int argc, char **argv)
{
    time_t now_sec;
    struct tm *now;
    FILE *bout;
    struct timespec now_clk;
    if (argc < 2)
    {
        printf("Usage: %s build_file_name\n\n", argv[0]);;
        return EXIT_FAILURE;
    }
    bout = fopen(argv[1], "a");
    if (!bout)
    {
        printf("Could not open file: %s\n\n", argv[1]);
        return EXIT_FAILURE;
    }
    time(&now_sec);
    now = gmtime(&now_sec);
    fprintf(bout, "%02d/%02d/%04d %02d:%02d:%02d", now->tm_mday, now->tm_mon+1, now->tm_year+1900, now->tm_hour, now->tm_min, now->tm_sec);
    clock_gettime(CLOCK_MONOTONIC, &now_clk);
    fprintf(bout, " %ld\n", now_clk.tv_nsec);
    return EXIT_SUCCESS;
}

うまくいけば、これは誰かに役立つでしょう。

アップデート

これを約9か月使用した後、これは非常に便利であると言えます. いくつかの観察事項は次のとおりです。

  • Windows では、 の実装によって与えられる最後の要素clock_gettimeは非常に小さく、同じ値を持つ回数の半分です。それにもかかわらず、それでももう少しランダムになります。
  • Linux では、最後の要素はかなりランダムです。
  • マージできるように、ビルド ファイル内の行をコミットするためだけに、時々「ビルド」コミットを実行する必要がありました。ただし、これは で回避できますgit stash
  • これを使用すると、ほとんどの場合、マージ時に競合が発生しますが、それを解決するのは非常に簡単です (両方のファイルからの行が必要なため、差分マーカーを削除するだけです)。
  • wc -lあなたの友達です。
于 2011-10-14T13:09:24.393 に答える
-1

ブランチが離陸したコミットに戻ることはできません(読みたくありません)、それが100だったことがわかるので、計算します...これを自動にしたい

汚い考え:各ビルドは、バージョン管理されたファイル(または結果に応じてPASS / FAILのペアからの1つ)に文字列を追加します。ブランチごとにわずかに異なります。ブランチをマージするには、このシグナル ファイルを手動でマージする必要があります。文字列の装飾が異なるため、この作業が容易になります。wc -l 後で数字を数えます

于 2011-10-10T14:38:39.443 に答える