Update to helpm2pod from helpmessage2pod
[archives2git.git] / archives2git
blobe09feddf71eca9c91542df6163f94de6f10c9703
1 #!/bin/sh
2 # Copyright © 2013,2014 Géraud Meyer <graud@gmx.com>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 2 as
6 # published by the Free Software Foundation.
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 # for more details.
13 # You should have received a copy of the GNU General Public License along
14 # with this program. If not, see <http://www.gnu.org/licenses/>.
16 PROGRAM_NAME="archives2git"
17 PROGRAM_VERSION="0.1+"
18 help_message () {
19 cat <<HelpMessage
20 NAME
21 $PROGRAM_NAME - generate a Git history from a series of release tarballs
22 USAGE
23 $PROGRAM_NAME [<options>] [--] <archives_and_directories>
24 DESCRIPTION
25 $PROGRAM_NAME replaces the contents of a Git repository subdir with that of
26 an <archive> file (or of another <directory>) and commits the changes.
27 OPTIONS
28 --repo <work_tree_subdir>
29 --rename <sh_code>
30 How to rename the current \$file in the root directory.
31 --keep-filter <sh_code>
32 Decide whether to ignore the current \$file in the root directory.
33 --gitadd-arg <arg>
34 --date <sh_code>
35 Author date to use when commiting the current \$arch.
36 --author <sh_code>
37 --title <sh_code>
38 It can also expand to a body.
39 --body <message>
40 Appended to the title as a new paragraph.
41 --gitci-arg <arg>
42 --gitfilter <nl_separated_args>
43 --tag
44 --tagname <sh_code>
45 --command <sh_code>
46 Eval <sh_code> after having commited and tagged the current \$arch.
47 --debug
48 --help
49 --version
50 SHELL VARIABLES
51 The following shell variables are usable if appropriate in the shell code
52 snippets passed as command line options: \$arch, \$archdir, \$archname,
53 \$file, \$date, \$author, \$title, \$tagname.
54 ENVIRONMENT
55 GIT_AUTHOR_NAME
56 GIT_AUTHOR_EMAIL
57 GIT_COMMITTER_NAME
58 GIT_COMMITTER_EMAIL
59 FILES
60 ~/.archives2gitrc
61 An example file is distributed.
62 EXAMPLES
63 See the README.
64 SEE ALSO
65 git-commit-tree(1), git_load_dirs(1)
66 HelpMessage
69 # helper functions
70 get_version () {
71 _file=$1; shift
72 _base=$( printf "%s\n" "$_file" |
73 LC_ALL=C sed -e 's;\(\([0-9]\{1,\}\.\)\|[-_]\)[0-9]\{1,\}\([-_.]\{0,1\}\([0-9]\{1,\}\|[ab]\|alpha\|beta\|gamma\)\)*$;;' )
74 _version=${_file#"$_base"}
75 _version=${_version#"-"}; _version=${_version#"."}; _version=${_version#"_"}
76 printf "%s\n" "${_version}"
79 # default parameters
80 RENAME='' # $file $arch $archname
81 FILTER='false' # $file $arch $archname
82 DATE='' # $arch $archname
83 TITLE='echo "$arch"' # $arch $archname
84 BODY="" # message taken as is
85 ADDARGS=
86 CIARGS=
87 FILTERHEAD= # line separated arguments
88 TAG=
89 TAGDEF='printf version/; get_version "$archname"'
90 COMMAND=
91 # config (file, environment, command line)
92 [ -f "$HOME"/.archives2gitrc ] && . "$HOME"/.archives2gitrc
93 GIT_WORK_TREE=${GIT_WORK_TREE-.}
94 # may be a subdir of the top level
95 while [ $# -gt 0 ]
97 case $1 in
98 --repo)
99 shift; GIT_WORK_TREE=$1 ;;
100 --rename)
101 shift; RENAME=$1 ;;
102 --keep-filter)
103 shift; FILTER=$1 ;;
104 --gitadd-arg)
105 shift; ADDARGS="$ADDARGS $1" ;;
106 --date)
107 shift; DATE=$1 ;;
108 --author)
109 shift; AUTHOR=$1 ;;
110 --title)
111 shift; TITLE=$1 ;;
112 --body)
113 shift; BODY=$1 ;;
114 --gitci-arg)
115 shift; CIARGS="$CIARGS $1" ;;
116 --gitfilter)
117 shift; FILTERHEAD=$1 ;;
118 --tag)
119 TAG=$TAGDEF ;;
120 --tagname)
121 shift; TAG=$1 ;;
122 --command)
123 shift; COMMAND=$1 ;;
124 --debug)
125 set -x ;;
126 --help|-h)
127 help_message
128 exit ;;
129 --version)
130 echo "$PROGRAM_NAME version $PROGRAM_VERSION"
131 exit ;;
132 --?*)
133 echo >&2 "$PROGRAM_NAME: error: unknown option $1"
134 exit 255 ;;
136 shift; break ;;
138 break ;;
139 esac
140 shift
141 done
142 # setup
143 NL='
145 TMPDIR=$(mktemp -d) ||
147 echo >&2 "$PROGRAM_NAME: error: cannot create a temporary directory"
148 exit 253
150 WRKDIR=$(pwd)
151 # git repository check
152 cd "$GIT_WORK_TREE" &&
153 { test -d .git || git rev-parse --git-dir >/dev/null; } ||
155 echo >&2 "$PROGRAM_NAME: error: not in a git repository ($(pwd))"
156 exit 255
158 test -z "$(git status --porcelain)" &&
159 git update-index -q --refresh ||
161 echo >&2 "$PROGRAM_NAME: error: unstaged files or dirty index"
162 exit 254
165 # main
166 set -e
167 OLDIFS=$IFS
168 for arch
170 # put the files in the archive dir
171 cd "$WRKDIR"
172 if [ -d "$arch" ]
173 then
174 cp -R "$arch" "$TMPDIR"
175 else
176 aunpack -X "$TMPDIR" "$arch"
178 archdir=$TMPDIR
179 archname=$( printf "%s\n" "$arch" | LC_ALL=C sed \
180 -e 's;^\([^/]*/\)*\([^/]\{1,\}\)/\{0,1\}$;\2;' \
181 -e 's;\.\([Zz]\|lzo\|bz\|gz\|bz2\|xz\|lzma\|7z\|lz\|rz\|lrz\)$;;' \
182 -e 's;\.\(tar\|t[Zz]\|tzo\|tbz\|tgz\|tbz2\|txz\|t7z\|tlz\|lha\|lzh\|7z\|alz\|arj\|zip\|rar\|jar\|war\|ace\|cab\|a\|cpio\|shar\|rpm\|deb\)$;;' \
183 -e 's;\.\(orig\)$;;' )
184 # remove (almost) everything from the repository dir
185 cd "$GIT_WORK_TREE"
186 for file in * .*
188 [ -e "$file" ] || continue
189 [ x"$file" = x"." ] || [ x"$file" = x".." ] || [ x"$file" = x".git" ] && continue
190 eval "$FILTER" || { git rm -r "$file" || rm -R "$file"; }
191 done
192 # move the content of the temp dir to the repository and stage it
193 for file in "$archdir"/* "$archdir"/.*
195 [ -e "$file" ] || continue
196 file=${file#$archdir/}
197 [ x"$file" = x"." ] || [ x"$file" = x".." ] && continue
198 [ -n "$RENAME" ] && name=$(eval "$RENAME") || name=$file
199 if [ -n "$name" ]
200 then
201 [ ! -e ./"$name" ] || rm -R ./"$name"
202 # remove conflicting file (previously kept or renamed to the same name)
203 mv "$archdir"/"$file" ./"$name"
204 git add $ADDARGS ./"$name"
205 else
206 rm -R "$archdir"/"$file"
208 done
209 unset file
210 # commit, filter and clean up
211 date=$(eval "$DATE")
212 author=$(eval "$AUTHOR")
213 title=$(eval "$TITLE")
214 git commit ${AUTHOR:+--author "$author"} -m "$title"${BODY:+"$NL$NL$BODY"} ${DATE:+--date "$date"} $CIARGS
215 if [ -n "$FILTERHEAD" ]
216 then
217 IFS=$NL
218 git filter-branch $FILTERHEAD -- HEAD^..HEAD
219 rm -R "$(git rev-parse --git-dir)"/refs/original/
220 IFS=$OLDIFS
222 if [ -n "$TAG" ]
223 then
224 tagmessage=$(eval "$TAG" | LC_ALL=C tail -n +2)
225 tagname=$(eval "$TAG" | LC_ALL=C head -1)
226 git tag ${tagmessage:+-m "$tagmessage"} "$tagname"
228 if [ -n "$COMMAND" ]
229 then
230 eval "$COMMAND"
232 unset title date author tagname tagmessage
233 done
235 # cleanup
236 rmdir "$TMPDIR"