1#!/bin/bash 2 3# 4# Copyright 2011-2016 Nest Labs Inc. All Rights Reserved. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19# 20# Description: 21# This file attempts to find and generate a package version 22# including, if necessary, the number of commits from the last 23# GIT tag and the current GIT hash corresponding to HEAD for the 24# current branch. 25# 26# This is largely cobbled together from similar scripts in other 27# packages that are maintained in GIT (linux, u-boot, parted, etc.). 28# 29# This can produce version information such as: 30# 31# 1.0.1 32# 1.0.1-dirty 33# 1.0.1-00032-gab50dbb 34# 1.0.1-00032-gab50dbb-dirty 35# 36 37# Constants 38 39ROOTDIR=${PREFIX}/ 40 41BINDIR=${ROOTDIR}bin 42DATADIR=${ROOTDIR}share 43DEVICEDIR=${ROOTDIR}dev 44CONFDIR=${ROOTDIR}etc 45LIBDIR=${ROOTDIR}lib 46LIBEXECDIR=${ROOTDIR}libexec 47VARDIR=${ROOTDIR}var 48LOGDIR=${VARDIR}/log 49MANDIR=${ROOTDIR}man 50SBINDIR=${ROOTDIR}sbin 51 52USRDIR=${ROOTDIR}usr 53USRBINDIR=${USRDIR}/bin 54USRDATADIR=${USRDIR}/share 55USRLIBDIR=${USRDIR}/lib 56USRLIBEXECDIR=${USRDIR}/libexec 57USRSBINDIR=${USRDIR}/sbin 58 59AWK=${USRBINDIR}/awk 60BASENAME=${USRBINDIR}/basename 61CAT=${BINDIR}/cat 62ECHO="${BINDIR}/echo" 63NULL=${DEVICEDIR}/null 64PRINTF=${USRBINDIR}/printf 65RM=${BINDIR}/rm 66SED=${BINDIR}/sed 67 68VERSION="" 69 70# 71# usage <status> 72# 73# Description: 74# This routine prints out the proper command line usage for this 75# program and then exits with the specified status. 76# 77# Input(s): 78# status - Exit status to exit the program with. 79# 80# Returns: 81# This subroutine does not return. 82# 83usage() { 84 local name=`${BASENAME} ${0}` 85 86 ${ECHO} "Usage: ${name} [options] [ <project root> ]" 87 88 if [ ${1} -ne 0 ]; then 89 ${ECHO} "Try '${name} -h' for more information." 90 fi 91 92 if [ ${1} -ne 1 ]; then 93${CAT} << EOF 94 -b, --build-version=VERSION Specify VERSION as the build version to generate 95 extra build information against. 96 -h, --help Print this help, then exit. 97EOF 98 fi 99 100 exit ${1} 101} 102 103# 104# gitversion <string> <directory> <version> 105# 106# Description: 107# This routine prints out any GIT version information appended to the 108# end of the package version, including the number of commits from 109# the last GIT tag and the current GIT hash corresponding to HEAD 110# for the current branch. 111# 112# Input(s): 113# string - The current version string which may be empty. 114# directory - The current directory. 115# version - The optional current package version. 116# 117# Returns: 118# N/A 119# 120gitversion() { 121 local string="${1}" 122 local dir="${2}" 123 local version="${3}" 124 local head 125 local exact 126 local dtag 127 local gitversion 128 129 # Retrieve the shortened, unique GIT hash associated with the 130 # 'HEAD' GIT object 131 132 head=`test -d .git && git rev-parse --verify --short HEAD 2> ${NULL}` 133 134 # If we found a hash, we are actually in a GIT repository; continue. 135 136 if [ -n "${head}" ]; then 137 # Check to see if we have a position in GIT that is 138 # exactly at an existing tag (e.g. 1.0.2). If we are, 139 # just use it and add a dirty qualifier. Otherwise, 140 # work through the logic to determine how far off the 141 # tag the tree is. 142 143 exact="`git describe --exact-match 2> ${NULL}`" 144 145 if [ -z "${exact}" ] || [ -n "${version}" ] && [ "${version}" != "${exact}" ]; then 146 dtag="`git describe 2> ${NULL}`" 147 148 # If we are n commits away from a tag, then 149 # print n and a shortened version of the 150 # hash. Otherwise, just print the hash. 151 # 152 # If we are at an exact version, then there 153 # won't be a delta or a hash, just use the 154 # exact tag. 155 156 if [ -n "${dtag}" ]; then 157 if [ "${dtag}" == "${exact}" ]; then 158 gitversion="${dtag}" 159 else 160 gitversion=`${PRINTF} "${dtag}" | ${AWK} -F '-' '{printf("%s-%05d-%s", $(NF-2),$(NF-1),$(NF))}' 2> ${NULL}` 161 fi 162 163 else 164 gitversion=`${PRINTF} "g${head}"` 165 166 fi 167 168 else 169 gitversion="${exact}" 170 171 fi 172 173 # Update the index if we are in a writable directory 174 # so that we can successfully check for a dirty (has 175 # uncommitted changes or unresolved merges) tree. 176 177 if [ -w "${dir}" ]; then 178 git update-index --refresh --unmerged > ${NULL} 179 fi 180 181 # Now check for such a dirty tree and add to the "string" 182 # if we found one. 183 184 if git diff-index --name-only HEAD | read dummy; then 185 if [ -n "${gitversion}" ]; then 186 gitversion="${gitversion}-dirty" 187 else 188 gitversion="dirty" 189 fi 190 fi 191 192 else 193 gitversion="${version}" 194 195 fi 196 197 if [ -n "${string}" ] && [ -n "${gitversion}" ]; then 198 string="${string}-${gitversion}" 199 else 200 string="${gitversion}" 201 fi 202 203 ${PRINTF} "${string}" 204} 205 206# 207# Main Program Body 208# 209 210while [ ${#} -gt 0 ]; do 211 if [ ${1:0:1} == "-" ]; then 212 if [ "${1}" == "-h" ] || [ "${1}" == "--help" ]; then 213 usage 0 214 215 elif [ "${1}" == "-b" ] || [ "${1}" == "--build-version" ]; then 216 version="${2}" 217 shift 2 218 219 else 220 ${ECHO} "Unknown argument '${1}'." 221 usage 1 222 223 fi 224 225 else 226 break 227 228 fi 229done 230 231if [ ${#} -gt 1 ]; then 232 usage 1 233elif [ ${#} -eq 1 ]; then 234 tree="${1}" 235else 236 tree="." 237fi 238 239if [ "${tree}" != "." ]; then 240 cd "${tree}" 241fi 242 243VERSION="`gitversion \"${VERSION}\" . ${version}`" 244 245${PRINTF} "${VERSION}" 246