- remove bashism. - simplify some git-related code. - improved parameter and error handling. - additional -d/--date action which is similar to the timestamp action. - support for an optional path parameter. - there is only one sane time format. - and only one sane date format too. - vastly improve git_url() to print the correct remote url and "nearest" branch. - remove username from repository URLs. - add "-dirty" to local revisions if there are uncommitted changes. - indicate in local revisions how many git-only commits were done since branching from upstream svn. - fix svn_revision() fallback to svn info and remove git-svn. - print leading r in script instead of hardcode it in the makefile; no more "0.9.7-runknown". - make retrieving the upstream revision work even in cloned git-svn repositories. - more abstractions and helper functions. - less fragmentation of actual functionality.
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- Makefile | 5 +- util/getrevision.sh | 341 +++++++++++++++++++++++++++++----------------------- 2 files changed, 195 insertions(+), 151 deletions(-)
diff --git a/Makefile b/Makefile index 023c41d..540e5da 100644 --- a/Makefile +++ b/Makefile @@ -322,14 +322,13 @@ LIB_OBJS = layout.o flashrom.o udelay.o programmer.o
CLI_OBJS = cli_classic.o cli_output.o print.o
-# Set the flashrom version string from the highest revision number -# of the checked out flashrom files. +# Set the flashrom version string from the highest revision number of the checked out flashrom files. # Note to packagers: Any tree exported with "make export" or "make tarball" # will not require subversion. The downloadable snapshots are already exported. SVNVERSION := $(shell ./util/getrevision.sh -u)
RELEASE := 0.9.7 -VERSION := $(RELEASE)-r$(SVNVERSION) +VERSION := $(RELEASE)-$(SVNVERSION) RELEASENAME ?= $(VERSION)
SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"' diff --git a/util/getrevision.sh b/util/getrevision.sh index 098f63e..3246b74 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 @@ -27,204 +28,248 @@ EXIT_FAILURE=1 # Make sure we don't get translated output export LC_ALL=C
-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 +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" }
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#*/}" }
scm_url() { - local url - - if [ -d ".svn" ] ; then - url=$(svn_url) - elif [ -d ".git" ] ; then - url=$(git_url) + local url= + + 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 "$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}" "$1") + fi + elif git_is_file_tracked "$2" ; then + # are there local changes? + if git_has_local_changes "$2" ; then + t=$(date "${1}") + else + # No local changes, get date of the last commit + t=$(date -d "$(git log --pretty=format:"%cD" -1 -- "$2")" "$1") + fi + else + t=$(date "$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" + shift;; + -t|--timestamp) + check_action $1 + action="timestamp +%Y-%m-%dT%H:%M:%S%z" # 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 $@