makepkg: use printf when writing pkginfo
[pacman-ng.git] / scripts / repo-add.sh.in
blob7bde6007f5c2ba5ccd7e0bcc9cbd3742b2113154
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 )) && 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")"
140 md5sum="${md5sum##* }"
141 csize=$(@SIZECMD@ "$deltafile")
143 oldfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (source)" | sed 's/.*: *//')
144 newfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (output)" | sed 's/.*: *//')
146 if grep -q "$oldfile.*$newfile" $deltas; then
147 warning "$(gettext "An entry for '%s' already existed")" "$deltafile"
148 sed -i.backup "/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
149 msg2 "$(gettext "Removing existing entry '%s'...")" "$deltafile"
151 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
153 return 0
154 } # end db_write_delta
156 # remove a delta entry
157 # arg1 - path to delta file
158 db_remove_delta()
160 deltafile="$1"
161 filename=${deltafile##*/}
162 pkgname="$(get_delta_pkgname $deltafile)"
164 pkgentry=$(find_pkgentry $pkgname)
165 if [[ -z $pkgentry ]]; then
166 return 1
168 deltas="$pkgentry/deltas"
169 if [[ ! -f $deltas ]]; then
170 return 1
172 if grep -q "$filename" $deltas; then
173 sed -i.backup "/$filename/d" $deltas && rm -f $deltas.backup
174 msg2 "$(gettext "Removing existing entry '%s'...")" "$filename"
175 return 0
178 return 1
179 } # end db_remove_delta
181 # write an entry to the pacman database
182 # arg1 - path to package
183 db_write_entry()
185 # blank out all variables
186 local pkgfile="$1"
187 local pkgname pkgver pkgdesc csize size md5sum url arch builddate packager force \
188 _groups _licenses _replaces _depends _conflicts _provides _optdepends
190 local OLDIFS="$IFS"
191 # IFS (field separator) is only the newline character
192 IFS="
195 # read info from the zipped package
196 local line var val
197 for line in $(bsdtar -xOqf "$pkgfile" .PKGINFO |
198 grep -v '^#' | sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
199 # bash awesomeness here- var is always one word, val is everything else
200 var=${line%% *}
201 val=${line#* }
202 declare $var="$val"
203 case "$var" in
204 group) _groups="$_groups$group\n" ;;
205 license) _licenses="$_licenses$license\n" ;;
206 replaces) _replaces="$_replaces$replaces\n" ;;
207 depend) _depends="$_depends$depend\n" ;;
208 conflict) _conflicts="$_conflicts$conflict\n" ;;
209 provides) _provides="$_provides$provides\n" ;;
210 optdepend) _optdepends="$_optdepends$optdepend\n" ;;
211 esac
212 done
214 IFS=$OLDIFS
216 # get md5sum and compressed size of package
217 md5sum="$(openssl dgst -md5 "$pkgfile")"
218 md5sum="${md5sum##* }"
219 csize=$(@SIZECMD@ "$pkgfile")
221 # ensure $pkgname and $pkgver variables were found
222 if [[ -z $pkgname || -z $pkgver ]]; then
223 error "$(gettext "Invalid package file '%s'.")" "$pkgfile"
224 return 1
227 cd "$tmpdir"
229 if [[ -d $pkgname-$pkgver ]]; then
230 warning "$(gettext "An entry for '%s' already existed")" "$pkgname-$pkgver"
233 # remove an existing entry if it exists, ignore failures
234 db_remove_entry "$pkgname"
236 # create package directory
237 mkdir "$pkgname-$pkgver"
238 cd "$pkgname-$pkgver"
240 # restore an eventual deltas file
241 [[ -f ../$pkgname.deltas ]] && mv "../$pkgname.deltas" deltas
243 # create desc entry
244 msg2 "$(gettext "Creating 'desc' db entry...")"
245 echo -e "%FILENAME%\n$(basename "$1")\n" >>desc
246 echo -e "%NAME%\n$pkgname\n" >>desc
247 [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc
248 echo -e "%VERSION%\n$pkgver\n" >>desc
249 [[ -n $pkgdesc ]] && echo -e "%DESC%\n$pkgdesc\n" >>desc
250 write_list_entry "GROUPS" "$_groups" "desc"
251 [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc
252 [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc
254 # compute checksums
255 msg2 "$(gettext "Computing md5 checksums...")"
256 echo -e "%MD5SUM%\n$md5sum\n" >>desc
258 [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc
259 write_list_entry "LICENSE" "$_licenses" "desc"
260 [[ -n $arch ]] && echo -e "%ARCH%\n$arch\n" >>desc
261 [[ -n $builddate ]] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
262 [[ -n $packager ]] && echo -e "%PACKAGER%\n$packager\n" >>desc
263 write_list_entry "REPLACES" "$_replaces" "desc"
264 [[ -n $force ]] && echo -e "%FORCE%\n" >>desc
266 # create depends entry
267 msg2 "$(gettext "Creating 'depends' db entry...")"
268 # create the file even if it will remain empty
269 touch "depends"
270 write_list_entry "DEPENDS" "$_depends" "depends"
271 write_list_entry "CONFLICTS" "$_conflicts" "depends"
272 write_list_entry "PROVIDES" "$_provides" "depends"
273 write_list_entry "OPTDEPENDS" "$_optdepends" "depends"
275 cd "$startdir"
277 return 0
278 } # end db_write_entry
280 # remove existing entries from the DB
281 # arg1 - package name
282 db_remove_entry() {
283 local pkgname=$1
284 local notfound=1
285 local pkgentry=$(find_pkgentry $pkgname)
286 while [[ -n $pkgentry ]]; do
287 notfound=0
288 if [[ -f $pkgentry/deltas ]]; then
289 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
291 msg2 "$(gettext "Removing existing entry '%s'...")" \
292 "$(basename $pkgentry)"
293 rm -rf $pkgentry
294 pkgentry=$(find_pkgentry $pkgname)
295 done
296 return $notfound
297 } # end db_remove_entry
299 check_repo_db()
301 # check lock file
302 if ( set -o noclobber; echo "$$" > "$LOCKFILE") 2> /dev/null; then
303 CLEAN_LOCK=1
304 else
305 error "$(gettext "Failed to acquire lockfile: %s.")" "$LOCKFILE"
306 [[ -f $LOCKFILE ]] && error "$(gettext "Held by process %s")" "$(cat $LOCKFILE)"
307 exit 1
310 if [[ -f $REPO_DB_FILE ]]; then
311 # there are two situations we can have here- a DB with some entries,
312 # or a DB with no contents at all.
313 if ! bsdtar -tqf "$REPO_DB_FILE" '*/desc' >/dev/null 2>&1; then
314 # check empty case
315 if [[ -n $(bsdtar -tqf "$REPO_DB_FILE" '*' 2>/dev/null) ]]; then
316 error "$(gettext "Repository file '%s' is not a proper pacman database.")" "$REPO_DB_FILE"
317 exit 1
320 msg "$(gettext "Extracting database to a temporary location...")"
321 bsdtar -xf "$REPO_DB_FILE" -C "$tmpdir"
322 else
323 case "$cmd" in
324 repo-remove)
325 error "$(gettext "Repository file '%s' was not found.")" "$REPO_DB_FILE"
326 exit 1
328 repo-add)
329 # check if the file can be created (write permission, directory existence, etc)
330 if ! touch "$REPO_DB_FILE"; then
331 error "$(gettext "Repository file '%s' could not be created.")" "$REPO_DB_FILE"
332 exit 1
334 rm -f "$REPO_DB_FILE"
336 esac
340 add()
342 if [[ ! -f $1 ]]; then
343 error "$(gettext "File '%s' not found.")" "$1"
344 return 1
347 if [[ ${1##*.} == "delta" ]]; then
348 deltafile=$1
349 msg "$(gettext "Adding delta '%s'")" "$deltafile"
350 if ! type xdelta3 &>/dev/null; then
351 error "$(gettext "Cannot find the xdelta3 binary! Is xdelta3 installed?")"
352 exit 1
354 if db_write_delta "$deltafile"; then
355 return 0
356 else
357 return 1
361 pkgfile=$1
362 if ! bsdtar -tqf "$pkgfile" .PKGINFO >/dev/null 2>&1; then
363 error "$(gettext "'%s' is not a package file, skipping")" "$pkgfile"
364 return 1
367 msg "$(gettext "Adding package '%s'")" "$pkgfile"
369 db_write_entry "$pkgfile"
372 remove()
374 if [[ ${1##*.} == "delta" ]]; then
375 deltafile=$1
376 msg "$(gettext "Searching for delta '%s'...")" "$deltafile"
377 if db_remove_delta "$deltafile"; then
378 return 0
379 else
380 error "$(gettext "Delta matching '%s' not found.")" "$deltafile"
381 return 1
385 pkgname=$1
386 msg "$(gettext "Searching for package '%s'...")" "$pkgname"
388 if db_remove_entry "$pkgname"; then
389 rm -f "$tmpdir/$pkgname.deltas"
390 return 0
391 else
392 error "$(gettext "Package matching '%s' not found.")" "$pkgname"
393 return 1
397 trap_exit()
399 echo
400 error "$@"
401 exit 1
404 clean_up() {
405 local exit_code=$?
407 cd "$startdir"
408 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
409 (( CLEAN_LOCK )) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
411 exit $exit_code
414 # PROGRAM START
416 # determine whether we have gettext; make it a no-op if we do not
417 if ! type gettext &>/dev/null; then
418 gettext() {
419 echo "$@"
423 case "$1" in
424 -h|--help) usage; exit 0;;
425 -V|--version) version; exit 0;;
426 esac
428 # figure out what program we are
429 cmd="$(basename $0)"
430 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
431 error "$(gettext "Invalid command name '%s' specified.")" "$cmd"
432 exit 1
435 tmpdir=$(mktemp -d /tmp/repo-tools.XXXXXXXXXX) || (\
436 error "$(gettext "Cannot create temp directory for database building.")"; \
437 exit 1)
439 trap 'clean_up' EXIT
440 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
441 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
442 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
444 success=0
445 # parse arguments
446 for arg in "$@"; do
447 case "$arg" in
448 -q|--quiet) QUIET=1;;
450 if [[ -z $REPO_DB_FILE ]]; then
451 REPO_DB_FILE="$arg"
452 LOCKFILE="$REPO_DB_FILE.lck"
453 check_repo_db
454 else
455 case "$cmd" in
456 repo-add) add $arg && success=1 ;;
457 repo-remove) remove $arg && success=1 ;;
458 esac
461 esac
462 done
464 # if at least one operation was a success, re-zip database
465 if (( success )); then
466 msg "$(gettext "Creating updated database file '%s'")" "$REPO_DB_FILE"
468 case "$REPO_DB_FILE" in
469 *tar.gz) TAR_OPT="z" ;;
470 *tar.bz2) TAR_OPT="j" ;;
471 *tar.xz) TAR_OPT="J" ;;
472 *) warning "$(gettext "'%s' does not have a valid archive extension.")" \
473 "$REPO_DB_FILE" ;;
474 esac
476 filename=$(basename "$REPO_DB_FILE")
478 cd "$tmpdir"
479 if [[ -n $(ls) ]]; then
480 bsdtar -c${TAR_OPT}f "$filename" *
481 else
482 # we have no packages remaining? zip up some emptyness
483 warning "$(gettext "No packages remain, creating empty database.")"
484 bsdtar -c${TAR_OPT}f "$filename" -T /dev/null
486 cd "$startdir"
488 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
489 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
490 ln -sf "$REPO_DB_FILE" "${REPO_DB_FILE%.tar.*}"
491 else
492 msg "$(gettext "No packages modified, nothing to do.")"
493 exit 1
496 exit 0
497 # vim: set ts=2 sw=2 noet: