blob: 9a949ffbb9f1342e514717260acb5dc3b6a3dbbb [file] [log] [blame]
David Hendricks6583a812013-11-01 19:37:44 -07001#!/bin/sh
2#
3# This file is part of the coreboot project. It originated in the
4# flashrom project but has been heavily modified since then.
5#
6# Copyright (C) 2013 Stefan Tauner
7# Copyright (C) 2013 Google Inc.
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22#
23
24EXIT_SUCCESS=0
25EXIT_FAILURE=1
26
27# Make sure we don't get translated output
28export LC_ALL=C
29# nor local times or dates
30export TZ=UTC0
31
32# Helper functions
33git_has_local_changes() {
34 git update-index -q --refresh >/dev/null
35 ! git diff-index --quiet HEAD -- "$1"
36}
37
38git_last_commit() {
39 git log --pretty=format:"%h" -1 -- "$1"
40}
41
42git_is_file_tracked() {
43 git ls-files --error-unmatch -- "$1" >/dev/null 2>&1
44}
45
46is_file_tracked() {
47 git_is_file_tracked "$1"
48}
49
50# Tries to find a remote source for the changes committed locally.
51# This includes the URL of the remote repository including the last commit and a suitable branch name.
52# Takes one optional argument: the path to inspect
53git_url() {
54 # Note: This may not work as expected if multiple remotes are fetched from.
Patrick Georgif60fc822015-04-28 17:49:30 +020055 echo $(git remote -v | grep "^origin\>" | \
56 awk '/fetch/ {print $2; exit 0}' | sed "s,^.*@,,")
David Hendricks6583a812013-11-01 19:37:44 -070057}
58
59# Returns a string indicating where others can get the current source code (excluding uncommitted changes)
60# Takes one optional argument: the path to inspect
61scm_url() {
62 local url
63
64 url="$(git_url "$1")"
65
66 echo "${url}"
67}
68
69# Retrieve timestamp since last modification. If the sources are pristine,
70# then the timestamp will match that of the SCM's most recent modification
71# date.
72timestamp() {
73 local t
74
75 # date syntaxes are manifold:
76 # gnu date [-d input]... [+FORMAT]
77 # netbsd date [-ajnu] [-d date] [-r seconds] [+format] [[[[[[CC]yy]mm]dd]HH]MM[.SS]]
78 # freebsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...]
79 # dragonflybsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...]
80 # openbsd date [-aju] [-d dst] [-r seconds] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]] [...]
81 if git_is_file_tracked "$2" ; then
82 # are there local changes?
83 if git_has_local_changes "$2" ; then
84 t=$(date -u "${1}")
85 else
86 # No local changes, get date of the last commit
87 case $(uname) in
88 # Most BSD dates do not support parsing date values from user input with -d but all of
89 # them support parsing epoch seconds with -r. Thanks to git we can easily use that:
90 NetBSD|OpenBSD|DragonFly|FreeBSD)
91 t=$(date -u -r "$(git log --pretty=format:%ct -1 -- $2)" "$1" 2>/dev/null);;
92 *)
93 t=$(date -d "$(git log --pretty=format:%cD -1 -- $2)" -u "$1" 2>/dev/null);;
94 esac
95 fi
96 else
97 t=$(date -u "$1")
98 fi
99
100 if [ -z "$t" ]; then
101 echo "Warning: Could not determine timestamp." 2>/dev/null
102 fi
103 echo "${t}"
104}
105
106# Retrieve local SCM revision info. This is useful if we're working in a different SCM than upstream and/or
107# have local changes.
108local_revision() {
109 local r
110
111 if git_is_file_tracked "$1" ; then
112 r=$(git_last_commit "$1")
113
114 if git_has_local_changes "$1" ; then
115 r="$r-dirty"
116 fi
117 else
118 return ${EXIT_FAILURE}
119 fi
120
121 echo "${r}"
122}
123
David Hendricks1b6e7a62013-11-11 18:44:05 -0800124# Similar to local_revision but uses "git describe" instead of "git log" which
125# includes number of commits since most recent tag.
126tagged_revision() {
127 local r
128
129 if git_is_file_tracked "$1" ; then
130 r=$(git describe --tags --dirty)
131 else
132 return ${EXIT_FAILURE}
133 fi
134
135 echo "${r}"
136}
137
David Hendricks6583a812013-11-01 19:37:44 -0700138upstream_revision() {
139 local r=
140
141 r=$(git log remotes/origin/master -1 --format=format:%h)
142
143 if [ -z "$r" ]; then
144 r="unknown" # default to unknown
145 fi
146 echo "${r}"
147}
148
149show_help() {
150 echo "Usage:
151 ${0} <command> [path]
152
153Commands
154 -h or --help
155 this message
156 -l or --local
157 local revision information including an indicator for uncommitted changes
158 -u or --upstream
159 upstream revision
David Hendricks1b6e7a62013-11-11 18:44:05 -0800160 -T or --tags
161 similar to -l, but uses \"git describe\" to obtain revision info with tags
David Hendricks6583a812013-11-01 19:37:44 -0700162 -U or --url
163 URL associated with the latest commit
164 -d or --date
165 date of most recent modification
166 -t or --timestamp
167 timestamp of most recent modification
168"
169 return
170}
171
172check_action() {
173 if [ -n "$action" ]; then
174 echo "Error: Multiple actions given.">&2
175 exit ${EXIT_FAILURE}
176 fi
177}
178
179main() {
180 local query_path=
181 local action=
182
183 # The is the main loop
184 while [ $# -gt 0 ];
185 do
186 case ${1} in
187 -h|--help)
188 action=show_help;
189 shift;;
190 -l|--local)
191 check_action $1
192 action=local_revision
193 shift;;
David Hendricks1b6e7a62013-11-11 18:44:05 -0800194 -T|--tags)
195 check_action $1
196 action=tagged_revision
197 shift;;
David Hendricks6583a812013-11-01 19:37:44 -0700198 -u|--upstream)
199 check_action $1
200 action=upstream_revision
201 shift;;
202 -U|--url)
203 check_action $1
204 action=scm_url
205 shift;;
206 -d|--date)
207 check_action $1
208 action="timestamp +%Y-%m-%d" # refrain from suffixing 'Z' to indicate it's UTC
209 shift;;
210 -t|--timestamp)
211 check_action $1
212 action="timestamp +%Y-%m-%dT%H:%M:%SZ" # There is only one valid time format! ISO 8601
213 shift;;
214 -*)
215 show_help;
216 echo "Error: Invalid option: ${1}"
217 exit ${EXIT_FAILURE};;
218 *)
219 if [ -z "$query_path" ] ; then
220 if [ ! -e "$1" ] ; then
221 echo "Error: Path \"${1}\" does not exist.">&2
222 exit ${EXIT_FAILURE}
223 fi
224 query_path=$1
225 else
226 echo "Warning: Ignoring over-abundant paramter: \"${1}\"">&2
227 fi
228 shift;;
229 esac;
230 done
231
232 # default to current directory (usually equals the whole repository)
233 if [ -z "$query_path" ] ; then
234 query_path=.
235 fi
236 if ! is_file_tracked "$query_path" ; then
237 echo "Warning: Path \"${query_path}\" is not under version control.">&2
238 fi
239 if [ -z "$action" ] ; then
240 show_help
241 echo "Error: No actions specified"
242 exit ${EXIT_FAILURE}
243 fi
244
245 $action "$query_path"
246}
247
248main $@