diff options
Diffstat (limited to 'util/getrevision.sh')
| -rwxr-xr-x | util/getrevision.sh | 349 | 
1 files changed, 201 insertions, 148 deletions
| diff --git a/util/getrevision.sh b/util/getrevision.sh index 098f63e9..c05f59e6 100755 --- a/util/getrevision.sh +++ b/util/getrevision.sh @@ -1,10 +1,11 @@ -#!/bin/bash +#!/bin/sh  #  # This file is part of the flashrom project.  #  # Copyright (C) 2005 coresystems GmbH <stepan@coresystems.de>  # Copyright (C) 2009,2010 Carl-Daniel Hailfinger  # Copyright (C) 2010 Chromium OS Authors +# Copyright (C) 2013 Stefan Tauner  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License as published by @@ -26,205 +27,257 @@ EXIT_FAILURE=1  # Make sure we don't get translated output  export LC_ALL=C +# nor local times or dates +export TZ=UTC0 -svn_revision() { -	svnversion -cn . 2>/dev/null | \ -		sed -e "s/.*://" -e "s/\([0-9]*\).*/\1/" | \ -		grep "[0-9]" || -	svn info . 2>/dev/null | \ -		awk '/^Revision:/ {print $$2 }' | \ -		grep "[0-9]" || -	git svn info . 2>/dev/null | \ -		awk '/^Revision:/ {print $$2 }' | \ -		grep "[0-9]" || -	echo '' +# Helper functions +# First argument is the path to inspect (usually optional; w/o it the whole repository will be considered) +svn_has_local_changes() { +	svn status "$1" | egrep '^ *[ADMR] *' >/dev/null  } -svn_url() { -	echo $(svn info 2>/dev/null | -	       grep URL: | -		   sed 's/.*URL:[[:blank:]]*//' | -		   grep ^. -	      ) +git_has_local_changes() { +	git update-index -q --refresh >/dev/null +	! git diff-index --quiet HEAD -- "$1"  } -svn_timestamp() { -	local date_format="+%Y-%m-%d %H:%M:%S" -	local timestamp - -	# are there local changes in the client? -	if svn status | egrep '^ *[ADMR] *' > /dev/null ; then -		timestamp=$(date "${date_format} +") -	else -		# No local changes, get date of the last log record. -		local last_commit_date=$(svn info | grep '^Last Changed Date:' | awk '{print $4" "$5" "$6}') -		timestamp=$(date --utc --date "${last_commit_date}" \ -			        "${date_format} UTC") -	fi - -	echo "${timestamp}" +git_last_commit() { +	git log --pretty=format:"%h" -1 -- "$1"  } -git_revision() { -	echo $(git log --oneline | head -1 | awk '{print $1}') +svn_is_file_tracked() { +	svn info "$1" >/dev/null 2>&1  } -# Retrieve svn revision using git log data (for git mirrors) -gitsvn_revision() { -	local r - -	git log| -		grep git-svn-id| -		sed 's/.*git-svn-id:[[:blank:]]*\([^@]\+\)@[0-9]\+[[:blank:]]\+\([^[:blank:]]\+\)/\1 \2/'| -		sort| -		uniq| -		read url uuid - -	r=$(git log --grep="git-svn-id.*$uuid"| grep git-svn-id | \ -		sed 's/.*@//;s/[[:blank:]].*//'| \ -		sort -n | \ -		tail -1) - -	echo "${r}" +git_is_file_tracked() { +	git ls-files --error-unmatch -- "$1" >/dev/null 2>&1  } -git_timestamp() { -	local date_format="+%b %d %Y %H:%M:%S" -	local timestamp - -	# are there local changes in the client? -	if git status | \ -	   egrep '^# Change(s to be committed|d but not updated):$' > /dev/null -	then -		timestamp=$(date "${date_format} +") -	else -		# No local changes, get date of the last log record. -		local last_commit_date=$(git log | head -3 | grep '^Date:' | \ -		                         awk '{print $3" "$4" "$6" "$5" "$7}') -		timestamp=$(date --utc --date "${last_commit_date}" \ -		            "${date_format} UTC") -	fi - -	echo "${timestamp}" +is_file_tracked() { +	svn_is_file_tracked "$1" || git_is_file_tracked "$1"  } +# Tries to find a remote source for the changes committed locally. +# This includes the URL of the remote repository including the last commit and a suitable branch name. +# Takes one optional argument: the path to inspect  git_url() { -	# Only the first line of `git remote' is considered. -	echo $(git remote show origin 2>/dev/null | -	       grep 'Fetch URL:' | -	       sed 's/.*URL:[[:blank:]]*//' | -	       grep ^. -	      ) +	last_commit=$(git_last_commit "$1") +	# get all remote branches containing the last commit (excluding origin/HEAD and git-svn branches/tags) +	branches=$(git branch -r --contains $last_commit | sed '/\//!d;/.*->.*/d;s/[\t ]*//') +	if [ -z "$branches" ] ; then +		echo "No remote branch contains a suitable commit">&2 +		return +	fi + +	# find "nearest" branch +	local mindiff=9000 +	local target= +	for branch in $branches ; do +		curdiff=$(git rev-list --count $last_commit..$branch) +		if [ $curdiff -ge $mindiff ] ; then +			continue +		fi +		mindiff=$curdiff +		target=$branch +	done + +	echo "$(git ls-remote --exit-code --get-url ${target%/*}) ${target#*/}"  } +# Returns a string indicating where others can get the current source code (excluding uncommitted changes) +# Takes one optional argument: the path to inspect  scm_url() { -	local url - -	if [ -d ".svn" ] ; then -		url=$(svn_url) -	elif [ -d ".git" ] ; then -		url=$(git_url) +	local url= + +	# for a primitive VCS like subversion finding the URL is easy: there is only one upstream host +	if svn_is_file_tracked "$1" ; then +		url="$(svn info "$1" 2>/dev/null | +		       grep URL: | +		       sed 's/.*URL:[[:blank:]]*//;s/:\/\/.*@/:\/\//' | +		       grep ^.)" +	elif git_is_file_tracked "$1" ; then +		url="$(git_url "$1")" +	else +		return ${EXIT_FAILURE}  	fi  	echo "${url}"  }  # Retrieve timestamp since last modification. If the sources are pristine, -# then the timestamp will match that of the SCM's more recent modification +# then the timestamp will match that of the SCM's most recent modification  # date.  timestamp() {  	local t -	if [ -d ".svn" ] ; then -		t=$(svn_timestamp) -	elif [ -d ".git" ] ; then -		t=$(git_timestamp) +	if svn_is_file_tracked "$2" ; then +		if svn_has_local_changes "$2"; then +			t=$(date -u "$1") +		else +			# No local changes, get date of the last log record. +			local last_commit_date="$(svn info "$2" | \ +						  grep '^Last Changed Date:' | \ +						  awk '{print $4" "$5" "$6}')" +			t=$(date -d "${last_commit_date}" -u "$1") +		fi +	elif git_is_file_tracked "$2" ; then +		# are there local changes? +		if git_has_local_changes "$2" ; then +			t=$(date -u "${1}") +		else +			# No local changes, get date of the last commit +			t=$(date -d "$(git log --pretty=format:"%cD" -1 -- "$2")" -u "$1") +		fi +	else +		t=$(date -u "$1")  	fi -	echo ${t} +	echo "${t}"  } -# Retrieve local SCM revision info. This is useful if we're working in -# a even different SCM than upstream. -# -# If local copy is svn, then there is nothing to do here. -# If local copy is git, then retrieve useful git revision info +# Retrieve local SCM revision info. This is useful if we're working in a different SCM than upstream and/or +# have local changes.  local_revision() { -	local r - -	if [ -d ".git" ] ; then -		r=$(git_revision) +	local r= + +	if svn_is_file_tracked "$1" ; then +		r=$(svn_has_local_changes "$1" && echo "dirty") +	elif git_is_file_tracked "$1" ; then +		r=$(git_last_commit "$1") + +		local svn_base=$(git log --grep git-svn-id -1 --format='%h') +		if [ "$svn_base" != "" ] ; then +			local diff_to_svn=$(git rev-list --count ${svn_base}..${r}) +			if [ "$diff_to_svn" -gt 0 ] ; then +				r="$r-$diff_to_svn" +			fi +		fi + +		if git_has_local_changes "$1" ; then +			r="$r-dirty" +		fi +	else +		return ${EXIT_FAILURE}  	fi -	echo ${r} +	echo "${r}"  }  # Get the upstream flashrom revision stored in SVN metadata. -# -# If the local copy is svn, then use svnversion -# If the local copy is git, then scrape upstream revision from git logs  upstream_revision() { -	local r - -	if [ -d ".svn" ] ; then -		r=$(svn_revision) -	elif [ -d ".git" ] ; then -		r=$(gitsvn_revision) +	local r= + +	if svn_is_file_tracked "$1" ; then +		r=$(svn info "$1" 2>/dev/null | \ +		    grep "Last Changed Rev:" | \ +		    sed -e "s/^Last Changed Rev: *//" -e "s/\([0-9]*\).*/r\1/" | \ +		    grep "r[0-9]") +	elif git_is_file_tracked "$1" ; then +		# If this is a "native" git-svn clone we could use git svn log: +		# git svn log --oneline -1 | sed 's/^r//;s/[[:blank:]].*//' or even git svn find-rev +		# but it is easier to just grep for the git-svn-id unconditionally +		r=$(git log --grep git-svn-id -1 -- "$1" | \ +		    grep git-svn-id | \ +		    sed 's/.*@/r/;s/[[:blank:]].*//')  	fi +	if [ -z "$r" ]; then +		r="unknown" # default to unknown +	fi  	echo "${r}"  }  show_help() {  	echo "Usage: -	${0} <option> +	${0} <command> [path] -Options +Commands      -h or --help -        Display this message. -    -u or --upstream -        upstream flashrom revision +        this message      -l or --local -        local revision (if different from upstream) +        local revision information including an indicator for uncommitted changes +    -u or --upstream +        upstream revision +    -U or --url +        URL associated with the latest commit +    -d or --date +        date of most recent modification      -t or --timestamp          timestamp of most recent modification -    -U or --url -        url associated with local copy of flashrom -	" +"  	return  } -if [ ! -n "${1}" ] -then -	show_help; -	echo "No options specified"; -	exit ${EXIT_SUCCESS} -fi - -# The is the main loop -while [[ ${1} = -* ]]; -do -	case ${1} in -	-h|--help) -		show_help; -		shift;; -	-u|--upstream) -		echo "$(upstream_revision)"; -		shift;; -	-l|--local) -		echo "$(local_revision)"; -		shift;; -	-t|--timestamp) -		echo "$(timestamp)"; -		shift;; -	-U|--url) -		echo "$(scm_url)"; -		shift;; -	*) -		show_help; -		echo "invalid option: ${1}" +check_action() { +	if [ -n "$action" ]; then +		echo "Error: Multiple actions given.">&2  		exit ${EXIT_FAILURE} -	esac; -done +	fi +} + +main() { +	local query_path= +	local action= + +	# The is the main loop +	while [ $# -gt 0 ]; +	do +		case ${1} in +		-h|--help) +			action=show_help; +			shift;; +		-l|--local) +			check_action $1 +			action=local_revision +			shift;; +		-u|--upstream) +			check_action $1 +			action=upstream_revision +			shift;; +		-U|--url) +			check_action $1 +			action=scm_url +			shift;; +		-d|--date) +			check_action $1 +			action="timestamp +%Y-%m-%d" # refrain from suffixing 'Z' to indicate it's UTC +			shift;; +		-t|--timestamp) +			check_action $1 +			action="timestamp +%Y-%m-%dT%H:%M:%SZ" # There is only one valid time format! ISO 8601 +			shift;; +		-*) +			show_help; +			echo "Error: Invalid option: ${1}" +			exit ${EXIT_FAILURE};; +		*) +			if [ -z "$query_path" ] ; then +				if [ ! -e "$1" ] ; then +					echo "Error: Path \"${1}\" does not exist.">&2 +					exit ${EXIT_FAILURE} +				fi +				query_path=$1 +			else +				echo "Warning: Ignoring over-abundant paramter: \"${1}\"">&2 +			fi +			shift;; +		esac; +	done + +	# default to current directory (usually equals the whole repository) +	if [ -z "$query_path" ] ; then +		query_path=. +	fi +	if ! is_file_tracked "$query_path" ; then +		echo "Warning: Path \"${query_path}\" is not under version control.">&2 +	fi +	if [ -z "$action" ] ; then +		show_help +		echo "Error: No actions specified" +		exit ${EXIT_FAILURE} +	fi + +	$action "$query_path" +} -exit ${EXIT_SUCCESS} +main $@ | 
