Improve getrevision.sh
- 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.
- use UTC dates and times only.
- 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.
Corresponding to flashrom svn r1727.
Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
diff --git a/Makefile b/Makefile
index 5410a71..f34ed1d 100644
--- a/Makefile
+++ b/Makefile
@@ -333,14 +333,13 @@
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..c05f59e 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 @@
# 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
+ local url=
- if [ -d ".svn" ] ; then
- url=$(svn_url)
- elif [ -d ".git" ] ; then
- url=$(git_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
+ local r=
- if [ -d ".git" ] ; then
- r=$(git_revision)
- fi
+ 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")
- echo ${r}
-}
+ 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
-# 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)
+ if git_has_local_changes "$1" ; then
+ r="$r-dirty"
+ fi
+ else
+ return ${EXIT_FAILURE}
fi
echo "${r}"
}
+# Get the upstream flashrom revision stored in SVN metadata.
+upstream_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
+}
-exit ${EXIT_SUCCESS}
+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"
+}
+
+main $@