1#!/bin/bash 2# 3# Copyright 2012 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# Generate version information for the EC binary 8 9# Use this symbol as a separator to be able to reliably concatenate strings of 10# text. 11dc=$'\001' 12 13# Default marker to indicate 'dirty' repositories 14dirty_marker='+' 15 16# This function examines the state of the current directory and attempts to 17# extract its version information: the latest tag, if any, how many patches 18# are there since the latest tag, the top sha1, and if there are local 19# modifications. 20# 21# Local modifications are reported by concatenating the revision string and 22# the string '-dirty' using the $dc symbol as the separator. 23# 24# If there is no tags defined in this git repository, the base version is 25# considered to be 0.0. 26# 27# If current directory is not a git depository, this function prints out 28# "no_version" 29 30get_tree_version() { 31 local marker 32 local ghash 33 local numcommits 34 local tag 35 local vbase 36 local ver_branch 37 local ver_major 38 39 if ghash=`git rev-parse --short --verify HEAD 2>/dev/null`; then 40 if gdesc=`git describe --dirty --match='v*' 2>/dev/null`; then 41 IFS="-" fields=($gdesc) 42 tag="${fields[0]}" 43 IFS="." vernum=($tag) 44 numcommits=$((${vernum[2]}+${fields[1]:-0})) 45 ver_major="${vernum[0]}" 46 ver_branch="${vernum[1]}" 47 else 48 numcommits=`git rev-list HEAD | wc -l` 49 ver_major="v0" 50 ver_branch="0" 51 fi 52 # avoid putting the -dirty attribute if only the timestamp 53 # changed 54 git status > /dev/null 2>&1 55 56 if [ -n "$(git diff-index --name-only HEAD 2>/dev/null)" ]; then 57 marker="${dirty_marker}" 58 else 59 marker="-" 60 fi 61 vbase="${ver_major}.${ver_branch}.${numcommits}${marker}${ghash}" 62 else 63 # Fall back to the VCSID provided by the packaging system if available. 64 if ghash=${VCSID##*-}; then 65 vbase="1.1.9999-${ghash:0:7}" 66 else 67 # then ultimately fails to "no_version" 68 vbase="no_version" 69 fi 70 fi 71 if [[ "${marker}" == "${dirty_marker}" ]]; then 72 echo "${vbase}${dc}${marker}" 73 else 74 echo "${vbase}${dc}" 75 fi 76} 77 78 79main() { 80 local component 81 local dir_list 82 local gitdate 83 local most_recents 84 local most_recent_file 85 local root 86 local timestamp 87 local tool_ver 88 local values 89 local vbase 90 local ver 91 92 IFS="${dc}" 93 ver="${CR50_DEV:+DBG/}${CRYPTO_TEST:+CT/}${BOARD}_" 94 tool_ver="" 95 most_recents=() # Non empty if any of the component repos is 'dirty'. 96 dir_list=( . ) # list of component directories, always includes the EC tree 97 98 if [[ -n ${BOARD} ]]; then 99 case "${BOARD}" in 100 (cr50) 101 dir_list+=( ../../third_party/tpm2 ) 102 dir_list+=( ../pinweaver ) 103 ;; 104 (*_fp) 105 dir_list+=( ./private ) 106 ;; 107 (*) 108 # For private-crX boards add their git root and cryptoc. 109 for root in private-cr5*; do 110 if [[ -d "${root}/board/${BOARD}" ]]; then 111 dir_list+=( "${root}" ../../third_party/cryptoc ) 112 fi 113 done 114 ;; 115 esac 116 fi 117 # Create a combined version string for all component directories. 118 for git_dir in ${dir_list[@]}; do 119 pushd "${git_dir}" > /dev/null 120 component="$(basename "${git_dir}")" 121 values=( $(get_tree_version) ) 122 vbase="${values[0]}" # Retrieved version information. 123 if [[ -n "${values[1]}" ]]; then 124 # From each modified repo get the most recently modified file. 125 most_recent_file="$(git status --porcelain | \ 126 awk '$1 ~ /[M|A|?]/ {print $2}' | \ 127 xargs ls -t | head -1)" 128 most_recents+=("$(realpath "${most_recent_file}")") 129 fi 130 if [ "${component}" != "." ]; then 131 ver+=" ${component}:" 132 fi 133 ver+="${vbase}" 134 tool_ver+="${vbase}" 135 popd > /dev/null 136 done 137 138 # On some boards where the version number consists of multiple components we 139 # want to separate the first word of the version string as the version of the 140 # EC tree. 141 IFS=' ' first_word=(${ver}) 142 143 echo "/* This file is generated by util/getversion.sh */" 144 145 echo "/* Version string, truncated to 31 chars (+ terminating null = 32) */" 146 echo "#define CROS_EC_VERSION32 \"${first_word:0:31}\"" 147 148 echo "/* Version string for ectool. */" 149 echo "#define CROS_ECTOOL_VERSION \"${tool_ver}\"" 150 151 echo "/* Version string for stm32mon. */" 152 echo "#define CROS_STM32MON_VERSION \"${tool_ver}\"" 153 154 echo "/* Sub-fields for use in Makefile.rules and to form build info string" 155 echo " * in common/version.c. */" 156 echo "#define VERSION \"${ver}\"" 157 if [ "$REPRODUCIBLE_BUILD" = 1 ]; then 158 echo '#define BUILDER "reproducible@build"' 159 else 160 echo "#define BUILDER \"${USER}@`hostname`\"" 161 fi 162 163 if [[ ${#most_recents[@]} != 0 ]]; then 164 # There are modified files, use the timestamp of the most recent one as 165 # the build version timestamp. 166 most_recent_file="$(ls -t "${most_recents[@]}" | head -1)" 167 timestamp="$(stat -c '%y' "${most_recent_file}" | sed 's/\..*//')" 168 echo "/* Repo is dirty, using time of most recent file modification. */" 169 echo "#define DATE \"${timestamp}\"" 170 else 171 echo "/* Repo is clean, use the commit date of the last commit. */" 172 # If called from an ebuild we won't have a git repo, so redirect stderr 173 # to avoid annoying 'Not a git repository' errors. 174 gitdate="$( 175 for git_dir in "${dir_list[@]}"; do 176 git -C "${git_dir}" log -1 --format='%ct %ci' HEAD 2>/dev/null 177 done | sort | tail -1 | cut -d ' ' -f '2 3')" 178 echo "#define DATE \"${gitdate}\"" 179 fi 180} 181 182main 183