...

Text file src/github.com/pelletier/go-toml/v2/ci.sh

Documentation: github.com/pelletier/go-toml/v2

     1#!/usr/bin/env bash
     2
     3
     4stderr() {
     5    echo "$@" 1>&2
     6}
     7
     8usage() {
     9    b=$(basename "$0")
    10    echo $b: ERROR: "$@" 1>&2
    11
    12    cat 1>&2 <<EOF
    13
    14DESCRIPTION
    15
    16    $(basename "$0") is the script to run continuous integration commands for
    17    go-toml on unix.
    18
    19    Requires Go and Git to be available in the PATH. Expects to be ran from the
    20    root of go-toml's Git repository.
    21
    22USAGE
    23
    24    $b COMMAND [OPTIONS...]
    25
    26COMMANDS
    27
    28benchmark [OPTIONS...] [BRANCH]
    29
    30    Run benchmarks.
    31
    32    ARGUMENTS
    33
    34        BRANCH Optional. Defines which Git branch to use when running
    35               benchmarks.
    36
    37    OPTIONS
    38
    39        -d      Compare benchmarks of HEAD with BRANCH using benchstats. In
    40                this form the BRANCH argument is required.
    41
    42        -a      Compare benchmarks of HEAD against go-toml v1 and
    43                BurntSushi/toml.
    44
    45        -html   When used with -a, emits the output as HTML, ready to be
    46                embedded in the README.
    47
    48coverage [OPTIONS...] [BRANCH]
    49
    50    Generates code coverage.
    51
    52    ARGUMENTS
    53
    54        BRANCH  Optional. Defines which Git branch to use when reporting
    55                coverage. Defaults to HEAD.
    56
    57    OPTIONS
    58
    59        -d      Compare coverage of HEAD with the one of BRANCH. In this form,
    60                the BRANCH argument is required. Exit code is non-zero when
    61                coverage percentage decreased.
    62EOF
    63    exit 1
    64}
    65
    66cover() {
    67    branch="${1}"
    68    dir="$(mktemp -d)"
    69
    70    stderr "Executing coverage for ${branch} at ${dir}"
    71
    72    if [ "${branch}" = "HEAD" ]; then
    73	    cp -r . "${dir}/"
    74    else
    75	    git worktree add "$dir" "$branch"
    76    fi
    77
    78    pushd "$dir"
    79    go test -covermode=atomic  -coverpkg=./... -coverprofile=coverage.out.tmp ./...
    80    grep -Ev '(fuzz|testsuite|tomltestgen|gotoml-test-decoder|gotoml-test-encoder)' coverage.out.tmp > coverage.out
    81    go tool cover -func=coverage.out
    82    echo "Coverage profile for ${branch}: ${dir}/coverage.out" >&2
    83    popd
    84
    85    if [ "${branch}" != "HEAD" ]; then
    86	    git worktree remove --force "$dir"
    87    fi
    88}
    89
    90coverage() {
    91    case "$1" in
    92	-d)
    93	    shift
    94	    target="${1?Need to provide a target branch argument}"
    95
    96	    output_dir="$(mktemp -d)"
    97	    target_out="${output_dir}/target.txt"
    98	    head_out="${output_dir}/head.txt"
    99	    
   100	    cover "${target}" > "${target_out}"
   101	    cover "HEAD" > "${head_out}"
   102
   103	    cat "${target_out}"
   104	    cat "${head_out}"
   105
   106	    echo ""
   107
   108	    target_pct="$(tail -n2 ${target_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%.*/\1/')"
   109	    head_pct="$(tail -n2 ${head_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%/\1/')"
   110	    echo "Results: ${target} ${target_pct}% HEAD ${head_pct}%"
   111
   112	    delta_pct=$(echo "$head_pct - $target_pct" | bc -l)
   113	    echo "Delta: ${delta_pct}"
   114
   115	    if [[ $delta_pct = \-* ]]; then
   116		    echo "Regression!";
   117
   118            target_diff="${output_dir}/target.diff.txt"
   119            head_diff="${output_dir}/head.diff.txt"
   120            cat "${target_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${target_diff}"
   121            cat "${head_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${head_diff}"
   122
   123            diff --side-by-side --suppress-common-lines "${target_diff}" "${head_diff}"
   124		    return 1
   125	    fi
   126	    return 0
   127	    ;;
   128    esac
   129
   130    cover "${1-HEAD}"
   131}
   132
   133bench() {
   134    branch="${1}"
   135    out="${2}"
   136    replace="${3}"
   137    dir="$(mktemp -d)"
   138
   139    stderr "Executing benchmark for ${branch} at ${dir}"
   140
   141    if [ "${branch}" = "HEAD" ]; then
   142    	cp -r . "${dir}/"
   143    else
   144	    git worktree add "$dir" "$branch"
   145    fi
   146
   147    pushd "$dir"
   148
   149    if [ "${replace}" != "" ]; then
   150        find ./benchmark/ -iname '*.go' -exec sed -i -E "s|github.com/pelletier/go-toml/v2|${replace}|g" {} \;
   151        go get "${replace}"
   152    fi
   153
   154    export GOMAXPROCS=2
   155    go test '-bench=^Benchmark(Un)?[mM]arshal' -count=10 -run=Nothing ./... | tee "${out}"
   156    popd
   157
   158    if [ "${branch}" != "HEAD" ]; then
   159	    git worktree remove --force "$dir"
   160    fi
   161}
   162
   163fmktemp() {
   164    if mktemp --version &> /dev/null; then
   165	# GNU
   166        mktemp --suffix=-$1
   167    else
   168	# BSD
   169	mktemp -t $1
   170    fi
   171}
   172
   173benchstathtml() {
   174python3 - $1 <<'EOF'
   175import sys
   176
   177lines = []
   178stop = False
   179
   180with open(sys.argv[1]) as f:
   181    for line in f.readlines():
   182        line = line.strip()
   183        if line == "":
   184            stop = True
   185        if not stop:
   186            lines.append(line.split(','))
   187
   188results = []
   189for line in reversed(lines[2:]):
   190    if len(line) < 8 or line[0] == "":
   191        continue
   192    v2 = float(line[1])
   193    results.append([
   194        line[0].replace("-32", ""),
   195        "%.1fx" % (float(line[3])/v2),  # v1
   196        "%.1fx" % (float(line[7])/v2),  # bs
   197    ])
   198# move geomean to the end
   199results.append(results[0])
   200del results[0]
   201
   202
   203def printtable(data):
   204    print("""
   205<table>
   206    <thead>
   207        <tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
   208    </thead>
   209    <tbody>""")
   210
   211    for r in data:
   212        print("        <tr><td>{}</td><td>{}</td><td>{}</td></tr>".format(*r))
   213
   214    print("""     </tbody>
   215</table>""")
   216
   217
   218def match(x):
   219    return "ReferenceFile" in x[0] or "HugoFrontMatter" in x[0]
   220
   221above = [x for x in results if match(x)]
   222below = [x for x in results if not match(x)]
   223
   224printtable(above)
   225print("<details><summary>See more</summary>")
   226print("""<p>The table above has the results of the most common use-cases. The table below
   227contains the results of all benchmarks, including unrealistic ones. It is
   228provided for completeness.</p>""")
   229printtable(below)
   230print('<p>This table can be generated with <code>./ci.sh benchmark -a -html</code>.</p>')
   231print("</details>")
   232
   233EOF
   234}
   235
   236benchmark() {
   237    case "$1" in
   238    -d)
   239        shift
   240     	target="${1?Need to provide a target branch argument}"
   241
   242        old=`fmktemp ${target}`
   243        bench "${target}" "${old}"
   244
   245        new=`fmktemp HEAD`
   246        bench HEAD "${new}"
   247
   248        benchstat "${old}" "${new}"
   249        return 0
   250        ;;
   251    -a)
   252        shift
   253
   254        v2stats=`fmktemp go-toml-v2`
   255        bench HEAD "${v2stats}" "github.com/pelletier/go-toml/v2"
   256        v1stats=`fmktemp go-toml-v1`
   257        bench HEAD "${v1stats}" "github.com/pelletier/go-toml"
   258        bsstats=`fmktemp bs-toml`
   259        bench HEAD "${bsstats}" "github.com/BurntSushi/toml"
   260
   261        cp "${v2stats}" go-toml-v2.txt
   262        cp "${v1stats}" go-toml-v1.txt
   263        cp "${bsstats}" bs-toml.txt
   264
   265        if [ "$1" = "-html" ]; then
   266            tmpcsv=`fmktemp csv`
   267            benchstat -format csv go-toml-v2.txt go-toml-v1.txt bs-toml.txt > $tmpcsv
   268            benchstathtml $tmpcsv
   269        else
   270            benchstat go-toml-v2.txt go-toml-v1.txt bs-toml.txt
   271        fi
   272
   273        rm -f go-toml-v2.txt go-toml-v1.txt bs-toml.txt
   274        return $?
   275    esac
   276
   277    bench "${1-HEAD}" `mktemp`
   278}
   279
   280case "$1" in
   281    coverage) shift; coverage $@;;
   282    benchmark) shift; benchmark $@;;
   283    *) usage "bad argument $1";;
   284esac

View as plain text