Skip to content
Snippets Groups Projects
wmake-build-info 15.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #------------------------------------------------------------------------------
    # =========                 |
    # \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    #  \\    /   O peration     |
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
    #   \\  /    A nd           | www.openfoam.com
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
    #------------------------------------------------------------------------------
    
    #     Copyright (C) 2018-2020 OpenCFD Ltd.
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
    #------------------------------------------------------------------------------
    
    #     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
    
    #     wmake/scripts/wmake-build-info
    #     Backend for "wmake -build-info"
    
    #     Print the api/version and other build information for the project.
    
    #     - WM_PROJECT_VERSION
    
    #     - WM_DIR              (unset defaults to WM_PROJECT_DIR/wmake)
    #
    
    # Files
    #     - META-INFO/{api-info,build-info}
    #     - wmake/rules/General/general
    #     - debian : implicitly disables git queries
    #
    
    #     There is a corner case when obtaining build information from git.
    #     It is possible that OpenFOAM has been imported into a debian form,
    #     in which case the '.git/' directory is most from debian and cannot
    #     be used to obtain an OpenFOAM sha1 value.
    #
    #     Ad hoc logic (slightly messy):
    #     1) Have an 'openfoam.debian/' directory.
    #        Assume that debian control has been added to OpenFOAM.
    #        Can use git to obtain build information.
    #     2) Have a 'debian/' directory only.
    #        Assume OpenFOAM has been added into a debian project.
    #        Treat as '-no-git', which which has no effect
    #        when building from pristine sources.
    
    #
    # SeeAlso
    #     META-INFO/README.md for other routines that also use META-INFO.
    
    #
    #------------------------------------------------------------------------------
    # Locations
    rulesFile="${WM_DIR:-$WM_PROJECT_DIR/wmake}/rules/General/general"
    
    META_INFO="$WM_PROJECT_DIR/META-INFO"
    FOAM_GIT_DIR="$WM_PROJECT_DIR/.git"
    
    Usage: ${0##*/} [OPTION]
           ${0##*/} [-update] -filter FILE
    options:
    
      -cmp, -check  Compare make and meta information (exit 0 for no changes)
    
      -diff         Display differences between make and meta information
                    (exit code 0 for no changes)
      -dry-run      In combination with -update
    
      -filter FILE  Filter @API@, @BUILD@ tags in file with make information
    
      -no-git       Disable use of git for obtaining information
    
      -remove       Remove meta-info build information and exit
    
      -update       Update meta-info from make information
      -query        Report make-info and meta-info
      -query-make   Report make-info values (api, branch, build)
      -query-meta   Report meta-info values (api, branch, build)
      -show-api     Print api value from wmake/rules, or meta-info and exit
      -show-patch   Print patch value from meta-info and exit
      -help         Print the usage
    
    
    Query/manage status of {api,branch,build} information.
    
    Default without any arguments is the same as '-query-make'.
    
    USAGE
        exit 1
    }
    
    # Report error and exit
    die()
    {
        exec 1>&2
        echo
        echo "Error encountered:"
        while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
        echo
        echo "See '${0##*/} -help' for usage"
        echo
        exit 1
    }
    
    #------------------------------------------------------------------------------
    # Parse arguments and options
    #------------------------------------------------------------------------------
    unset optCheck optDryRun optUpdate optQuery optFilter
    
    while [ "$#" -gt 0 ]
    do
        case "$1" in
        -h | -help*)
    
            optCheck=true
            ;;
        -diff)
            optCheck=verbose
            ;;
        -dry-run)
            optDryRun=true
            ;;
    
        -remove)
            optUpdate=remove
            break # Stop now
            ;;
    
        -update)
            optUpdate=true
            ;;
        -query)
            optQuery="make:meta"
            ;;
        -query-make | -query-meta)
            optQuery="$optQuery:${1##*-}"
            ;;
        -show-api)
            optQuery="api"
            ;;
        -show-patch)
            optQuery="patch"
            ;;
        -filter)
            optFilter=true
            shift # Stop here, a file name follows
            break
            ;;
    
            die "Unknown option/argument: '$1'"
    
    # Check environment variables
    [ -d "$WM_PROJECT_DIR" ] || \
        die "Bad or unset environment variable: \$WM_PROJECT_DIR"
    
    
    [ -d "$META_INFO" ] || \
        die "No ${META_INFO##*/}/ directory for project"
    
    # Debian handling (see notes above)
    # - disable git queries if debian project and not internal "debianization"
    if [ -d "$WM_PROJECT_DIR/debian" ] \
    && [ ! -e "$WM_PROJECT_DIR/openfoam.debian" ]
    
    then
        unset FOAM_GIT_DIR
    fi
    
    #------------------------------------------------------------------------------
    
    
    if [ "$optUpdate" = remove ]
    
        if [ -f "$META_INFO/build-info" ]
    
            echo "Removing project ${META_INFO##*/}/build-info" 1>&2
    
            rm -f "$META_INFO/build-info"
    
            echo "Already removed project ${META_INFO##*/}/build-info" 1>&2
    
        [ -f "$1" ] || {
            echo "Error in ${0##*/}: file not found '$1'" 1>&2
            exit 2
        }
    
        # Disable other methods that generate output to stdout
        unset optCheck optQuery
    
        [ "$#" -eq 0 ] || die "Unexpected option/arguments $*"
    
    
        # Nothing specified? Default to -query-make
        if [ -z "$optCheck$optUpdate$optQuery" ]
        then
            optQuery="make"
        fi
    
    fi
    
    
    #------------------------------------------------------------------------------
    
    
    # Variables - for portability, avoiding bash associative arrays
    unset make_info meta_info
    
    #
    #  - api    : from rules/General/general
    #  - patch  : cached value from previous make
    #  - branch : from git
    #  - build  : from git
    #
    # Failure modes:
    # - No api information (can't find file etc).
    #   -> FATAL: should never happen.
    #
    # - No git installed or no git repo
    #   -> branch and build are populated as empty strings
    #
    # - Working on detached head.
    #   -> branch has value "HEAD" instead of something more readable.
    getMakeInfo()
    {
    
        then
            ##echo "use cached value for make info" 1>&2
            return 0
        fi
        ##echo "get make info" 1>&2
    
    
        unset make_api make_patch make_branch make_build
    
    
        # (api) from WM_DIR/rules/General/general
        # - extract WM_VERSION = OPENFOAM=<digits>
    
    
        api="$(sed -ne '/^ *#/!{ /WM_VERSION.*OPENFOAM=/{ s@^.*OPENFOAM= *\([0-9][0-9]*\).*@\1@p; q }}' "$rulesFile" 2>/dev/null)"
    
        then
            # (patch) from build-info - not from api-info
    
            patch="$(sed -ne 's@^patch *= *\([0-9][0-9]*\).*@\1@p' "$META_INFO/build-info" 2>/dev/null)"
    
        # Build info from git. Use short date format (YYYY-MM-DD) and sed instead
        # of the newer --date='format:%y%m%d'
    
            build="$(git --git-dir="$FOAM_GIT_DIR" log -1 --date=short --format='%h=%ad' 2>/dev/null|sed 's/-//g;s/=/-/')"
    
            # Branch info from git
            if [ -n "$build" ]
            then
                branch="$(git --git-dir="$FOAM_GIT_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null)"
            fi
    
        make_api="$api"
        make_patch="${patch:-0}"  # Default is 0 (unpatched)
        make_branch="$branch"
        make_build="$build"
        make_info=true
    
    #
    #  - api    : from META-INFO/api-info
    #  - patch  : from META-INFO/api-info
    #  - branch : from META-INFO/build-info
    #  - build  : from META-INFO/build-info
    #
    # Failure modes:
    # - Directory, file or entry not found.
    #   -> corresponding entries are empty strings
    getMetaInfo()
    {
    
        then
            ##echo "use cached value for meta info" 1>&2
            return 0
        fi
        ##echo "get meta info" 1>&2
    
    
        unset meta_api meta_patch meta_branch meta_build
    
        then
            # (api, patch) from api-info
            # (branch, build) from build-info
    
    
            api="$(sed -ne 's@^api *= *\([0-9][0-9]*\).*@\1@p' "$META_INFO/api-info" 2>/dev/null)"
            patch="$(sed -ne 's@^patch *= *\([0-9][0-9]*\).*@\1@p' "$META_INFO/api-info" 2>/dev/null)"
            branch="$(sed -ne 's@^branch *= *\([^ ]*\).*@\1@p' "$META_INFO/build-info" 2>/dev/null)"
            build="$(sed -ne 's@^build *= *\([^ ]*\).*@\1@p' "$META_INFO/build-info" 2>/dev/null)"
    
        meta_api="$api"
        meta_patch="${patch:-0}"  # Default is 0 (unpatched)
        meta_branch="$branch"
        meta_build="$build"
        meta_info=true
    
    }
    
    
    # Get api from rules/General/general
    #
    # Failure modes:
    # - No api information (can't find file etc).
    #   -> Fatal for building, but could be OK for a stripped down version
    #
    # Fallback. Get from api-info
    getApi()
    {
    
        getMakeInfo
    
            getMetaInfo
    
        fi
    
        if [ -n "$api" ]
        then
            echo "$api"
        else
            return 1
        fi
    }
    
    
    # Get patch from meta-info / api-info
    #
    # Failure modes:
    # - No patch information (can't find file etc).
    getPatchLevel()
    {
    
        getMetaInfo
    
        getMakeInfo
        getMetaInfo
    
        echo "    api = ${make_api}"
        echo "    patch = ${meta_patch:-0}"  # <- From meta-info only
        echo "    branch = ${make_branch}"
        echo "    build = ${make_build}"
    
        getMetaInfo
    
        echo "    api = ${meta_api}"
        echo "    patch = ${meta_patch:-0}"  # <- From meta-info only
        echo "    branch = ${meta_branch}"
        echo "    build = ${meta_build}"
    }
    
    
    # Report diff between make and meta info (single key).
    # Set diff_header prior to the first call.
    # $1 == key
    # $2 == make value
    # $3 == meta value
    unset diff_header
    _reportDiff()
    {
        if [ -n "$diff_header" ]
        then
            echo "$diff_header"
            unset diff_header
        fi
        echo "$1:"
        echo "    make $2"
        echo "    meta $3"
    
    }
    
    
    # Test make vs meta info.
    # Return 0 for no differences, 1 otherwise
    # $1 == verbose, print as diff. Silent otherwise
    checkDiff()
    {
    
        local diff verbose
    
        if [ "$1" = "verbose" ]
        then
            diff_header="Differences"
            verbose=true
        fi
    
        getMakeInfo
        getMetaInfo
    
        # api
        if [ "${make_api}" != "${meta_api}" ]
        then
            diff=true
    
            if [ -n "$verbose" ]
    
                _reportDiff "api" "${make_api}" "${meta_api}"
    
        # patch
        if [ "${make_patch}" != "${meta_patch}" ]
    
            diff=true
    
            if [ -n "$verbose" ]
            then
                _reportDiff "patch" "${make_patch}" "${meta_patch}"
            fi
        fi
    
        # branch - only test when make info is non-empty
        if [ -n "${make_branch}" ] && [ "${make_branch}" != "${meta_branch}" ]
        then
            diff=true
    
            if [ -n "$verbose" ]
            then
                _reportDiff "branch" "${make_branch}" "${meta_branch}"
            fi
        fi
    
        # build - only test when make info is non-empty
        if [ -n "${make_build}" ] && [ "${make_build}" != "${meta_build}" ]
        then
            diff=true
    
            if [ -n "$verbose" ]
            then
                _reportDiff "build" "${make_build}" "${meta_build}"
            fi
    
        # No diffs, but never permit entirely empty values for build.
    
        test -z "$diff" || test -z "${make_build}${meta_build}"
    
    # Update meta info (on disk) based on the make info
    
        getMakeInfo
        getMetaInfo
    
        local api="${make_api}"
        local branch="${make_branch}"
        local build="${make_build}"
        local patch="${make_patch}"
    
    
        # If any of the make-info are empty (bad),
        # use the meta-info to avoid spurious changes
    
        [ -n "$api" ] || api="${meta_api}"
        [ -n "$branch" ] || branch="${meta_branch}"
        [ -n "$build" ] || build="${meta_build}"
    
        # Fallback to WM_PROJECT_VERSION alone
        [ -n "$build" ] || build="${WM_PROJECT_VERSION:-unknown}"
    
    
        outputFile="$META_INFO/build-info"
    
        if [ "$branch" != "${meta_branch}" ] || \
           [ "$build" != "${meta_build}" ] || \
           [ "$patch" != "${meta_patch}" ]
    
            patch="${meta_patch:-0}"        # <- From meta-info only
    
    
            if [ -n "$optDryRun" ]
            then
                echo "dry-run (update) ${outputFile##*/} branch=${branch}" 1>&2
                echo "dry-run (update) ${outputFile##*/} build=${build}" 1>&2
                echo "dry-run (update) ${outputFile##*/} patch=${patch}" 1>&2
            else
                echo "branch=${branch}" >| "$outputFile"
                echo "build=${build}"   >> "$outputFile"
                echo "patch=${patch}"   >> "$outputFile"
            fi
        fi
    
    
        # api-info
    
        outputFile="$META_INFO/api-info"
    
        if [ "$api" != "${meta_api}" ]
    
            patch="${meta_patch:-0}"        # <- From meta-info only
    
    
            if [ -n "$optDryRun" ]
            then
                echo "dry-run (update) ${outputFile##*/} api=${api}" 1>&2
                echo "dry-run (update) ${outputFile##*/} patch=${patch}" 1>&2
            else
                echo "api=${api}"     >| "$outputFile"
                echo "patch=${patch}" >> "$outputFile"
            fi
        fi
    
        return 0
    }
    
    
    #
    
    # Update meta info (on disk) based on the make info
    
    #
    performFiltering()
    {
        local input="$1"
    
        [ -f "$input" ] || {
            echo "Error in ${0##*/}: file not found '$1'" 1>&2
            exit 2
        }
    
    
        getMakeInfo
        getMetaInfo
    
        local api="${make_api}"
        local branch="${make_branch}"
        local build="${make_build}"
        local patch="${meta_patch:-0}"  # <- From meta-info only
    
    
    
        # If any of the make-info are empty (bad),
        # conjure up something from the meta-info
    
        # api is not normally needed (available directly from -Ddefine)
        # but we may wish to filter other types of files
    
        if [ -z "$api" ]
        then
    
            api="${api:-0}"  # integer value
        fi
    
        # branch/build could be missing for non-git
        if [ -z "$branch" ]
        then
    
            # Fallback to WM_PROJECT_VERSION
            build="${build:-${WM_PROJECT_VERSION:-unknown}}"
    
        fi
    
        sed \
            -e 's!@API@!'"${api}"'!g' \
            -e 's!@PATCH@!'"${patch:-0}"'!g' \
            -e 's!@BRANCH@!'"${branch}"'!g' \
            -e 's!@BUILD@!'"${build}"'!g' \
            -e 's!@VERSION@!'"${WM_PROJECT_VERSION}"'!g' \
            "$input"
    
        return 0
    }
    
    
    #------------------------------------------------------------------------------
    
    
    
    if [ -n "$optCheck" ]
    then
        checkDiff $optCheck
        exit $?
    elif [ "$optQuery" = api ]
    then
        # Show API and exit
        getApi
        exit $?
    elif [ "$optQuery" = patch ]
    then
        # Show patch level and exit
        getPatchLevel
        exit $?
    else
        # Other queries
        case "$optQuery" in (*make*) reportMakeInfo ;; esac
        case "$optQuery" in (*meta*) reportMetaInfo ;; esac
    fi
    
    [ -n "$optUpdate" ] && performUpdate
    
    if [ -n "$optFilter" ]
    then
        # Perform filter on file
        performFiltering "$1"
    fi
    
    exit 0  # clean exit
    
    #------------------------------------------------------------------------------