Quote values in the arch array in example PKGBUILD
[pacman-ng.git] / scripts / repo-add.sh.in
blob5454fb0cc299d62937d9ad47d11b135ba60e5ddc
1 #!/bin/bash
3 # repo-add - add a package to a given repo database file
4 # repo-remove - remove a package entry from a given repo database file
5 # @configure_input@
7 # Copyright (c) 2006-2008 Aaron Griffin <aaron@archlinux.org>
8 # Copyright (c) 2007-2008 Dan McGee <dan@archlinux.org>
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # gettext initialization
24 export TEXTDOMAIN='pacman'
25 export TEXTDOMAINDIR='@localedir@'
27 myver='@PACKAGE_VERSION@'
28 confdir='@sysconfdir@'
30 QUIET=0
31 REPO_DB_FILE=
32 LOCKFILE=
33 CLEAN_LOCK=0
34 startdir="$PWD"
36 # ensure we have a sane umask set
37 umask 0022
39 msg() {
40 local mesg=$1; shift
41 printf "==> ${mesg}\n" "$@" >&1
44 msg2() {
45 [ $QUIET -ne 0 ] && return
46 local mesg=$1; shift
47 printf " -> ${mesg}\n" "$@" >&1
50 warning() {
51 local mesg=$1; shift
52 printf "==> $(gettext "WARNING:") ${mesg}\n" "$@" >&2
55 error() {
56 local mesg=$1; shift
57 printf "==> $(gettext "ERROR:") ${mesg}\n" "$@" >&2
60 # print usage instructions
61 usage() {
62 printf "repo-add, repo-remove (pacman) %s\n\n" "$myver"
63 printf "$(gettext "Usage: repo-add [-q] <path-to-db> <package|delta> ...\n")"
64 printf "$(gettext "Usage: repo-remove [-q] <path-to-db> <packagename|delta> ...\n\n")"
65 printf "$(gettext "\
66 repo-add will update a package database by reading a package file.\n\
67 Multiple packages to add can be specified on the command line.\n\n")"
68 printf "$(gettext "\
69 repo-remove will update a package database by removing the package name\n\
70 specified on the command line from the given repo database. Multiple\n\
71 packages to remove can be specified on the command line.\n\n")"
72 printf "$(gettext "\
73 Use the -q/--quiet flag to minimize output to basic messages, warnings,\n\
74 and errors\n\n")"
75 echo "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0.pkg.tar.gz")"
76 echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")"
79 version() {
80 printf "repo-add, repo-remove (pacman) %s\n\n" "$myver"
81 printf "$(gettext "\
82 Copyright (C) 2006-2008 Aaron Griffin <aaron@archlinux.org>.\n\
83 Copyright (c) 2007-2008 Dan McGee <dan@archlinux.org>.\n\n\
84 This is free software; see the source for copying conditions.\n\
85 There is NO WARRANTY, to the extent permitted by law.\n")"
88 # write a list entry
89 # arg1 - Entry name
90 # arg2 - List
91 # arg3 - File to write to
92 write_list_entry() {
93 if [ -n "$2" ]; then
94 echo "%$1%" >>$3
95 echo -e $2 >>$3
99 find_pkgentry()
101 local pkgname=$1
102 local pkgentry
103 for pkgentry in $tmpdir/$pkgname*; do
104 name=${pkgentry##*/}
105 if [ "${name%-*-*}" = "$pkgname" ]; then
106 echo $pkgentry
107 return 0
109 done
110 return 1
113 # Get the package name from the delta filename
114 get_delta_pkgname() {
115 local tmp
117 tmp=${1##*/}
118 echo ${tmp%-*-*_to*}
121 # write a delta entry
122 # arg1 - path to delta file
123 db_write_delta()
125 deltafile="$1"
126 pkgname="$(get_delta_pkgname $deltafile)"
128 pkgentry=$(find_pkgentry $pkgname)
129 if [ -z "$pkgentry" ]; then
130 return 1
132 deltas="$pkgentry/deltas"
133 # create deltas file if it does not already exist
134 if [ ! -f "$deltas" ]; then
135 msg2 "$(gettext "Creating 'deltas' db entry...")"
136 echo -e "%DELTAS%" >>$deltas
138 # get md5sum and compressed size of package
139 md5sum="$(openssl dgst -md5 "$deltafile" | awk '{print $NF}')"
140 csize=$(@SIZECMD@ "$deltafile")
142 oldfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (source)" | sed 's/.*: *//')
143 newfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (output)" | sed 's/.*: *//')
145 if grep -q "$oldfile.*$newfile" $deltas; then
146 warning "$(gettext "An entry for '%s' already existed")" "$deltafile"
147 sed -i.backup "/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
148 msg2 "$(gettext "Removing existing entry '%s'...")" "$deltafile"
150 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
152 return 0
153 } # end db_write_delta
155 # remove a delta entry
156 # arg1 - path to delta file
157 db_remove_delta()
159 deltafile="$1"
160 filename=${deltafile##*/}
161 pkgname="$(get_delta_pkgname $deltafile)"
163 pkgentry=$(find_pkgentry $pkgname)
164 if [ -z "$pkgentry" ]; then
165 return 1
167 deltas="$pkgentry/deltas"
168 if [ ! -f "$deltas" ]; then
169 return 1
171 if grep -q "$filename" $deltas; then
172 sed -i.backup "/$filename/d" $deltas && rm -f $deltas.backup
173 msg2 "$(gettext "Removing existing entry '%s'...")" "$filename"
174 return 0
177 return 1
178 } # end db_remove_delta
180 # write an entry to the pacman database
181 # arg1 - path to package
182 db_write_entry()
184 # blank out all variables
185 local pkgfile="$1"
186 local pkgname pkgver pkgdesc csize size md5sum url arch builddate packager force \
187 _groups _licenses _replaces _depends _conflicts _provides _optdepends
189 local OLDIFS="$IFS"
190 # IFS (field separator) is only the newline character
191 IFS="
194 # read info from the zipped package
195 local line var val
196 for line in $(bsdtar -xOqf "$pkgfile" .PKGINFO |
197 grep -v '^#' | sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
198 # bash awesomeness here- var is always one word, val is everything else
199 var=${line%% *}
200 val=${line#* }
201 declare $var="$val"
202 case "$var" in
203 group) _groups="$_groups$group\n" ;;
204 license) _licenses="$_licenses$license\n" ;;
205 replaces) _replaces="$_replaces$replaces\n" ;;
206 depend) _depends="$_depends$depend\n" ;;
207 conflict) _conflicts="$_conflicts$conflict\n" ;;
208 provides) _provides="$_provides$provides\n" ;;
209 optdepend) _optdepends="$_optdepends$optdepend\n" ;;
210 esac
211 done
213 IFS=$OLDIFS
215 # get md5sum and compressed size of package
216 md5sum="$(openssl dgst -md5 "$pkgfile" | awk '{print $NF}')"
217 csize=$(@SIZECMD@ "$pkgfile")
219 # ensure $pkgname and $pkgver variables were found
220 if [ -z "$pkgname" -o -z "$pkgver" ]; then
221 error "$(gettext "Invalid package file '%s'.")" "$pkgfile"
222 return 1
225 cd "$tmpdir"
227 if [ -d "$pkgname-$pkgver" ]; then
228 warning "$(gettext "An entry for '%s' already existed")" "$pkgname-$pkgver"
231 # remove an existing entry if it exists, ignore failures
232 db_remove_entry "$pkgname"
234 # create package directory
235 mkdir "$pkgname-$pkgver"
236 cd "$pkgname-$pkgver"
238 # restore an eventual deltas file
239 [ -f "../$pkgname.deltas" ] && mv "../$pkgname.deltas" deltas
241 # create desc entry
242 msg2 "$(gettext "Creating 'desc' db entry...")"
243 echo -e "%FILENAME%\n$(basename "$1")\n" >>desc
244 echo -e "%NAME%\n$pkgname\n" >>desc
245 echo -e "%VERSION%\n$pkgver\n" >>desc
246 [ -n "$pkgdesc" ] && echo -e "%DESC%\n$pkgdesc\n" >>desc
247 write_list_entry "GROUPS" "$_groups" "desc"
248 [ -n "$csize" ] && echo -e "%CSIZE%\n$csize\n" >>desc
249 [ -n "$size" ] && echo -e "%ISIZE%\n$size\n" >>desc
251 # compute checksums
252 msg2 "$(gettext "Computing md5 checksums...")"
253 echo -e "%MD5SUM%\n$md5sum\n" >>desc
255 [ -n "$url" ] && echo -e "%URL%\n$url\n" >>desc
256 write_list_entry "LICENSE" "$_licenses" "desc"
257 [ -n "$arch" ] && echo -e "%ARCH%\n$arch\n" >>desc
258 [ -n "$builddate" ] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
259 [ -n "$packager" ] && echo -e "%PACKAGER%\n$packager\n" >>desc
260 write_list_entry "REPLACES" "$_replaces" "desc"
261 [ -n "$force" ] && echo -e "%FORCE%\n" >>desc
263 # create depends entry
264 msg2 "$(gettext "Creating 'depends' db entry...")"
265 # create the file even if it will remain empty
266 touch "depends"
267 write_list_entry "DEPENDS" "$_depends" "depends"
268 write_list_entry "CONFLICTS" "$_conflicts" "depends"
269 write_list_entry "PROVIDES" "$_provides" "depends"
270 write_list_entry "OPTDEPENDS" "$_optdepends" "depends"
272 cd "$startdir"
274 return 0
275 } # end db_write_entry
277 # remove existing entries from the DB
278 # arg1 - package name
279 db_remove_entry() {
280 local pkgname=$1
281 local notfound=1
282 local pkgentry=$(find_pkgentry $pkgname)
283 while [ -n "$pkgentry" ]; do
284 notfound=0
285 if [ -f "$pkgentry/deltas" ]; then
286 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
288 msg2 "$(gettext "Removing existing entry '%s'...")" \
289 "$(basename $pkgentry)"
290 rm -rf $pkgentry
291 pkgentry=$(find_pkgentry $pkgname)
292 done
293 return $notfound
294 } # end db_remove_entry
296 check_repo_db()
298 # check lock file
299 if ( set -o noclobber; echo "$$" > "$LOCKFILE") 2> /dev/null; then
300 CLEAN_LOCK=1
301 else
302 error "$(gettext "Failed to acquire lockfile: %s.")" "$LOCKFILE"
303 [ -f "$LOCKFILE" ] && error "$(gettext "Held by %s")" "$(cat $LOCKFILE)"
304 exit 1
307 if [ -f "$REPO_DB_FILE" ]; then
308 if ! bsdtar -tqf "$REPO_DB_FILE" '*/desc' 2>&1 >/dev/null; then
309 error "$(gettext "Repository file '%s' is not a proper pacman database.")" "$REPO_DB_FILE"
310 exit 1
312 msg "$(gettext "Extracting database to a temporary location...")"
313 bsdtar -xf "$REPO_DB_FILE" -C "$tmpdir"
314 else
315 case "$cmd" in
316 repo-remove)
317 error "$(gettext "Repository file '%s' was not found.")" "$REPO_DB_FILE"
318 exit 1
320 repo-add)
321 # check if the file can be created (write permission, directory existence, etc)
322 if ! touch "$REPO_DB_FILE"; then
323 error "$(gettext "Repository file '%s' could not be created.")" "$REPO_DB_FILE"
324 exit 1
326 rm -f "$REPO_DB_FILE"
328 esac
332 add()
334 if [ ! -f "$1" ]; then
335 error "$(gettext "File '%s' not found.")" "$1"
336 return 1
339 if [ "${1##*.}" == "delta" ]; then
340 deltafile=$1
341 msg "$(gettext "Adding delta '%s'")" "$deltafile"
342 if [ ! "$(type -p xdelta3)" ]; then
343 error "$(gettext "Cannot find the xdelta3 binary! Is xdelta3 installed?")"
344 exit 1
346 if db_write_delta "$deltafile"; then
347 return 0
348 else
349 return 1
353 pkgfile=$1
354 if ! bsdtar -tqf "$pkgfile" .PKGINFO 2>&1 >/dev/null; then
355 error "$(gettext "'%s' is not a package file, skipping")" "$pkgfile"
356 return 1
359 msg "$(gettext "Adding package '%s'")" "$pkgfile"
361 db_write_entry "$pkgfile"
364 remove()
366 if [ "${1##*.}" == "delta" ]; then
367 deltafile=$1
368 msg "$(gettext "Searching for delta '%s'...")" "$deltafile"
369 if db_remove_delta "$deltafile"; then
370 return 0
371 else
372 error "$(gettext "Delta matching '%s' not found.")" "$deltafile"
373 return 1
377 pkgname=$1
378 msg "$(gettext "Searching for package '%s'...")" "$pkgname"
380 if db_remove_entry "$pkgname"; then
381 rm -f "$tmpdir/$pkgname.deltas"
382 return 0
383 else
384 error "$(gettext "Package matching '%s' not found.")" "$pkgname"
385 return 1
389 trap_exit()
391 echo
392 error "$@"
393 exit 1
396 clean_up() {
397 local exit_code=$?
399 cd "$startdir"
400 [ -d "$tmpdir" ] && rm -rf "$tmpdir"
401 [ $CLEAN_LOCK -eq 1 -a -f "$LOCKFILE" ] && rm -f "$LOCKFILE"
403 exit $exit_code
406 # PROGRAM START
408 # determine whether we have gettext; make it a no-op if we do not
409 if [ ! $(type -t gettext) ]; then
410 gettext() {
411 echo "$@"
415 case "$1" in
416 -h|--help) usage; exit 0;;
417 -V|--version) version; exit 0;;
418 esac
420 # check for correct number of args
421 if [ $# -lt 2 ]; then
422 usage
423 exit 1
426 # figure out what program we are
427 cmd="$(basename $0)"
428 if [ "$cmd" != "repo-add" -a "$cmd" != "repo-remove" ]; then
429 error "$(gettext "Invalid command name '%s' specified.")" "$cmd"
430 exit 1
433 tmpdir=$(mktemp -d /tmp/repo-tools.XXXXXXXXXX) || (\
434 error "$(gettext "Cannot create temp directory for database building.")"; \
435 exit 1)
437 trap 'clean_up' EXIT
438 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
439 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
440 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
442 success=0
443 # parse arguments
444 for arg in "$@"; do
445 case "$arg" in
446 -q|--quiet) QUIET=1;;
448 -f|--force)
449 warning "$(gettext "the -f and --force options are no longer recognized")"
450 msg2 "$(gettext "use options=(force) in the PKGBUILD instead")"
454 if [ -z "$REPO_DB_FILE" ]; then
455 REPO_DB_FILE="$arg"
456 LOCKFILE="$REPO_DB_FILE.lck"
457 check_repo_db
458 else
459 case "$cmd" in
460 repo-add) add $arg && success=1 ;;
461 repo-remove) remove $arg && success=1 ;;
462 esac
465 esac
466 done
468 # if at least one operation was a success, re-zip database
469 if [ $success -eq 1 ]; then
470 msg "$(gettext "Creating updated database file '%s'")" "$REPO_DB_FILE"
472 case "$REPO_DB_FILE" in
473 *tar.gz) TAR_OPT="z" ;;
474 *tar.bz2) TAR_OPT="j" ;;
475 *tar.xz) TAR_OPT="J" ;;
476 *) warning "$(gettext "'%s' does not have a valid archive extension.")" \
477 "$REPO_DB_FILE" ;;
478 esac
480 filename=$(basename "$REPO_DB_FILE")
482 cd "$tmpdir"
483 if [ -n "$(ls)" ]; then
484 bsdtar -c${TAR_OPT}f "$filename" *
485 else
486 # the database will be moved to .old below, and there will be no new one to replace it
487 error "$(gettext "All packages have been removed from the database. Deleting '%s'.")" "$REPO_DB_FILE"
489 cd "$startdir"
491 [ -f "$REPO_DB_FILE" ] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
492 [ -f "$tmpdir/$filename" ] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
493 else
494 msg "$(gettext "No packages modified, nothing to do.")"
497 exit 0
498 # vim: set ts=2 sw=2 noet: