#!/bin/sh #------------------------------------------------------------------------------ # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox # \\ / O peration | # \\ / A nd | www.openfoam.com # \\/ M anipulation | #------------------------------------------------------------------------------ # Copyright (C) 2018-2020 OpenCFD Ltd. #------------------------------------------------------------------------------ # License # This file is part of OpenFOAM, distributed under GPL-3.0-or-later. # # Script # wmake/scripts/wmake-build-info # Backend for "wmake -build-info" # # Description # Print the api/version and other build information for the project. # # Environment # - WM_PROJECT_DIR # - 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 # # Note # When a 'debian/' directory exists, the '.git/' directory is most # likely from debian and not from OpenFOAM (ie, useless here). # This corresponds to an implicit '-no-git', 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" printHelp() { cat<&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*) printHelp ;; -cmp | -check) 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 ;; -no-git) unset FOAM_GIT_DIR ;; *) die "Unknown option/argument: '$1'" ;; esac shift done # 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" # Disable git queries for debian packaging (see notes above) if [ -d "$WM_PROJECT_DIR/debian" ] then unset FOAM_GIT_DIR fi #------------------------------------------------------------------------------ if [ "$optUpdate" = remove ] then if [ -f "$META_INFO/build-info" ] then echo "Removing project ${META_INFO##*/}/build-info" 1>&2 rm -f "$META_INFO/build-info" else echo "Already removed project ${META_INFO##*/}/build-info" 1>&2 fi exit 0 elif [ "$optFilter" = true ] then [ -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 else [ "$#" -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 # Populate make_* variables # # - 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() { if [ -n "$make_info" ] then ##echo "use cached value for make info" 1>&2 return 0 fi ##echo "get make info" 1>&2 local api patch build branch unset make_api make_patch make_branch make_build # (api) from WM_DIR/rules/General/general # - extract WM_VERSION = OPENFOAM= api="$(sed -ne '/^ *#/!{ /WM_VERSION.*OPENFOAM=/{ s@^.*OPENFOAM= *\([0-9][0-9]*\).*@\1@p; q }}' "$rulesFile" 2>/dev/null)" if [ -d "$META_INFO" ] 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)" fi # Build info from git. Use short date format (YYYY-MM-DD) and sed instead # of the newer --date='format:%y%m%d' if [ -d "$FOAM_GIT_DIR" ] then 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 fi make_api="$api" make_patch="${patch:-0}" # Default is 0 (unpatched) make_branch="$branch" make_build="$build" make_info=true } # Populate meta_* variables # # - 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() { if [ -n "$meta_info" ] then ##echo "use cached value for meta info" 1>&2 return 0 fi ##echo "get meta info" 1>&2 local api patch build branch unset meta_api meta_patch meta_branch meta_build if [ -d "$META_INFO" ] 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)" fi 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 # Local copy local api="${make_api}" if [ -z "$api" ] then getMetaInfo api="${meta_api}" 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 # Local copy local patch="${meta_patch}" if [ -n "$patch" ] then echo "$patch" else return 1 fi } # # Report make info # reportMakeInfo() { getMakeInfo getMetaInfo echo "make" echo " api = ${make_api}" echo " patch = ${meta_patch:-0}" # <- From meta-info only echo " branch = ${make_branch}" echo " build = ${make_build}" } # # Report meta info # reportMetaInfo() { getMetaInfo echo "meta" 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" ] then _reportDiff "api" "${make_api}" "${meta_api}" fi fi # patch if [ "${make_patch}" != "${meta_patch}" ] then 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 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 # performUpdate() { getMakeInfo getMetaInfo # Local copies of the make info 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}" local outputFile # build-info outputFile="$META_INFO/build-info" if [ "$branch" != "${meta_branch}" ] || \ [ "$build" != "${meta_build}" ] || \ [ "$patch" != "${meta_patch}" ] then 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}" ] then 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 copies of the make info 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="${meta_api}" api="${api:-0}" # integer value fi # branch/build could be missing for non-git if [ -z "$branch" ] then branch="${meta_branch}" branch="${branch:-unknown}" fi if [ -z "$build" ] then build="${meta_build}" # 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 } #------------------------------------------------------------------------------ # Dispatch 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 #------------------------------------------------------------------------------