#!/bin/bash #------------------------------------------------------------------------------ # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox # \\ / O peration | # \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. # \\/ M anipulation | #------------------------------------------------------------------------------- # License # This file is part of OpenFOAM. # # OpenFOAM 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. # # OpenFOAM 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 OpenFOAM. If not, see . # # Script # wmakeBuildInfo # # Description # Print the version used when building the project # # Environment # - WM_PROJECT_DIR # - WM_PROJECT_VERSION # - WM_DIR (unset defaults to WM_PROJECT_DIR/wmake) # # Note # Partial logic is also implemented in the bin/foamEtcFile # -show-api and -show-patch options. # Make sure that any changes here are also reflected there. # #------------------------------------------------------------------------------ # Locations rulesFile="${WM_DIR:-$WM_PROJECT_DIR/wmake}/rules/General/general" metaInfoDir="$WM_PROJECT_DIR/META-INFO" usage() { exec 1>&2 while [ "$#" -ge 1 ]; do echo "$1"; shift; done 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*) usage ;; -check) optCheck=true ;; -diff) optCheck=verbose ;; -dry-run) optDryRun=true ;; -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'" ;; esac shift done #------------------------------------------------------------------------------ if [ "$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 declare -A makeInfo declare -A metaInfo # # Populate makeInfo array # # - 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 [ "${#makeInfo[*]}" -eq 4 ] then ##echo "use cached value for make info" 1>&2 return 0 fi ##echo "get make info" 1>&2 local api patch build branch makeInfo=() # (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 "$metaInfoDir" ] then # (patch) from build-info - not from api-info patch="$(sed -ne 's@^patch *= *\([0-9][0-9]*\).*@\1@p' $metaInfoDir/build-info 2>/dev/null)" fi # Build info from git build="$(git --git-dir=$WM_PROJECT_DIR/.git log -1 --date='format:%y%m%d' --format='%h-%ad' 2>/dev/null)" # Branch info from git if [ -n "$build" ] then branch="$(git --git-dir=$WM_PROJECT_DIR/.git rev-parse --abbrev-ref HEAD 2>/dev/null)" fi makeInfo[api]="$api" makeInfo[patch]="${patch:-0}" # default is 0 makeInfo[branch]="$branch" makeInfo[build]="$build" } # # Populate metaInfo array # # - 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 [ "${#metaInfo[*]}" -eq 4 ] then ##echo "use cached value for meta info" 1>&2 return 0 fi ##echo "get meta info" 1>&2 local api patch build branch metaInfo=() if [ -d "$metaInfoDir" ] then # (api, patch) from api-info # (branch, build) from build-info api="$(sed -ne 's@^api *= *\([0-9][0-9]*\).*@\1@p' $metaInfoDir/api-info 2>/dev/null)" patch="$(sed -ne 's@^patch *= *\([0-9][0-9]*\).*@\1@p' $metaInfoDir/api-info 2>/dev/null)" branch="$(sed -ne 's@^branch *= *\([^ ]*\).*@\1@p' $metaInfoDir/build-info 2>/dev/null)" build="$(sed -ne 's@^build *= *\([^ ]*\).*@\1@p' $metaInfoDir/build-info 2>/dev/null)" fi metaInfo[api]="$api" metaInfo[patch]="${patch:-0}" # default is 0 metaInfo[branch]="$branch" metaInfo[build]="$build" } # # 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="${makeInfo[api]}" if [ -z "$api" ] then getMetaInfo api="${metaInfo[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 value="${metaInfo[patch]}" if [ -n "$value" ] then echo "$value" else return 1 fi } # Report make info reportMakeInfo() { getMakeInfo getMetaInfo local patch="${metaInfo[patch]}" # <- From meta-info only makeInfo[patch]="${patch:=0}" # Extra safety echo "make" for key in api patch branch build do echo " $key = ${makeInfo[$key]}" done } # Report meta info reportMetaInfo() { getMetaInfo local patch="${metaInfo[patch]}" # <- From meta-info only metaInfo[patch]="${patch:=0}" # Extra safety echo "meta" for key in api patch branch build do echo " $key = ${metaInfo[$key]}" done } # Test make vs meta info. # Return 0 for no differences, 1 otherwise # $1 == verbose, print as diff. Silent otherwise checkDiff() { local verbose="$1" local key diff getMakeInfo getMetaInfo for key in api patch branch build do if [ "${makeInfo[$key]}" != "${metaInfo[$key]}" ] then case "$key" in (branch | build) # Only trigger when make info (branch, build) are non-empty if [ -n "${makeInfo[$key]}" ] then diff="$diff $key" fi ;; (*) diff="$diff $key" ;; esac fi done if [ "$verbose" = verbose ] && [ -n "$diff" ] then echo "Differences" for key in $diff do echo "$key:" echo " make ${makeInfo[$key]}" echo " meta ${metaInfo[$key]}" done fi # No diffs, but never permit entirely empty values for build. test -z "$diff" || test -z "${makeInfo[build]}${metaInfo[build]}" } # # Update metaInfo (on disk) based on the makeInfo # performUpdate() { getMakeInfo getMetaInfo # Local copies of the make info local api="${makeInfo[api]}" local branch="${makeInfo[branch]}" local build="${makeInfo[build]}" local patch="${makeInfo[patch]}" # If any of the make-info are empty (bad), # use the meta-info to avoid spurious changes [ -n "$api" ] || api="${metaInfo[api]}" [ -n "$branch" ] || branch="${metaInfo[branch]}" [ -n "$build" ] || build="${metaInfo[build]}" # Fallback to WM_PROJECT_VERSION alone [ -n "$build" ] || build="${WM_PROJECT_VERSION:-unknown}" local outputFile # build-info outputFile="$metaInfoDir/build-info" if [ "$branch" != "${metaInfo[branch]}" ] || \ [ "$build" != "${metaInfo[build]}" ] || \ [ "$patch" != "${metaInfo[patch]}" ] then patch="${metaInfo[patch]}" # <- From meta-info only : "${patch:=0}" # Extra safety 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="$metaInfoDir/api-info" if [ "$api" != "${metaInfo[api]}" ] then patch="${metaInfo[patch]}" # <- From meta-info only : "${patch:=0}" # Extra safety 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 metaInfo (on disk) based on the makeInfo # This is the # 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="${makeInfo[api]}" local branch="${makeInfo[branch]}" local build="${makeInfo[build]}" local patch="${metaInfo[patch]}" # <- From meta-info only : "${patch:=0}" # Extra safety # 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="${metaInfo[api]}" api="${api:-0}" # integer value fi # branch/build could be missing for non-git if [ -z "$branch" ] then branch="${metaInfo[branch]}" branch="${branch:-unknown}" fi if [ -z "$build" ] then build="${metaInfo[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 } #------------------------------------------------------------------------------ # Dispatching 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 #------------------------------------------------------------------------------