Only check diskspace availability if needs more than zero
[pacman-ng.git] / scripts / repo-add.sh.in
blobd09d1b482c0730de17f3fb3f0e392b6fa18a355c
1 #!@BASH_SHELL@
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 DELTA=0
32 REPO_DB_FILE=
33 LOCKFILE=
34 CLEAN_LOCK=0
35 startdir="$PWD"
37 # ensure we have a sane umask set
38 umask 0022
40 msg() {
41 (( QUIET )) && return
42 local mesg=$1; shift
43 printf "==> ${mesg}\n" "$@" >&1
46 msg2() {
47 (( QUIET )) && return
48 local mesg=$1; shift
49 printf " -> ${mesg}\n" "$@" >&1
52 warning() {
53 local mesg=$1; shift
54 printf "==> $(gettext "WARNING:") ${mesg}\n" "$@" >&2
57 error() {
58 local mesg=$1; shift
59 printf "==> $(gettext "ERROR:") ${mesg}\n" "$@" >&2
62 # print usage instructions
63 usage() {
64 printf "repo-add, repo-remove (pacman) %s\n\n" "$myver"
65 printf "$(gettext "Usage: repo-add [-d] [-q] <path-to-db> <package|delta> ...\n")"
66 printf "$(gettext "Usage: repo-remove [-q] <path-to-db> <packagename|delta> ...\n\n")"
67 printf "$(gettext "\
68 repo-add will update a package database by reading a package file.\n\
69 Multiple packages to add can be specified on the command line.\n\n")"
70 printf "$(gettext "\
71 repo-remove will update a package database by removing the package name\n\
72 specified on the command line from the given repo database. Multiple\n\
73 packages to remove can be specified on the command line.\n\n")"
74 printf "$(gettext "\
75 Use the -q/--quiet flag to minimize output to basic messages, warnings,\n\
76 and errors\n\n")"
77 printf "$(gettext "\
78 Use the -d/--delta flag to automatically generate and add a delta file\n\
79 between the old entry and the new one, if the old package file is found\n\
80 next to the new one.\n\n")"
81 echo "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0.pkg.tar.gz")"
82 echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")"
85 version() {
86 printf "repo-add, repo-remove (pacman) %s\n\n" "$myver"
87 printf "$(gettext "\
88 Copyright (C) 2006-2008 Aaron Griffin <aaron@archlinux.org>.\n\
89 Copyright (c) 2007-2008 Dan McGee <dan@archlinux.org>.\n\n\
90 This is free software; see the source for copying conditions.\n\
91 There is NO WARRANTY, to the extent permitted by law.\n")"
94 # write a list entry
95 # arg1 - Entry name
96 # arg2 - List
97 # arg3 - File to write to
98 write_list_entry() {
99 if [[ -n $2 ]]; then
100 echo "%$1%" >>$3
101 echo -e $2 >>$3
105 find_pkgentry()
107 local pkgname=$1
108 local pkgentry
109 for pkgentry in $tmpdir/$pkgname*; do
110 name=${pkgentry##*/}
111 if [[ ${name%-*-*} = $pkgname ]]; then
112 echo $pkgentry
113 return 0
115 done
116 return 1
119 # Get the package name from the delta filename
120 get_delta_pkgname() {
121 local tmp
123 tmp=${1##*/}
124 echo ${tmp%-*-*_to*}
127 # write a delta entry
128 # arg1 - path to delta file
129 db_write_delta()
131 deltafile="$1"
132 pkgname="$(get_delta_pkgname $deltafile)"
134 pkgentry=$(find_pkgentry $pkgname)
135 if [[ -z $pkgentry ]]; then
136 error "$(gettext "No database entry for package '%s'.")" "$pkgname"
137 return 1
139 deltas="$pkgentry/deltas"
140 if [[ ! -f $deltas ]]; then
141 echo -e "%DELTAS%" >$deltas
143 # get md5sum and compressed size of package
144 md5sum="$(openssl dgst -md5 "$deltafile")"
145 md5sum="${md5sum##* }"
146 csize=$(@SIZECMD@ "$deltafile")
148 oldfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (source)" | sed 's/.*: *//')
149 newfile=$(xdelta3 printhdr $deltafile | grep "XDELTA filename (output)" | sed 's/.*: *//')
151 if grep -q "$oldfile.*$newfile" $deltas; then
152 sed -i.backup "/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
154 msg2 "$(gettext "Adding 'deltas' entry : %s -> %s")" "$oldfile" "$newfile"
155 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
157 return 0
158 } # end db_write_delta
160 # remove a delta entry
161 # arg1 - path to delta file
162 db_remove_delta()
164 deltafile="$1"
165 filename=${deltafile##*/}
166 pkgname="$(get_delta_pkgname $deltafile)"
168 pkgentry=$(find_pkgentry $pkgname)
169 if [[ -z $pkgentry ]]; then
170 return 1
172 deltas="$pkgentry/deltas"
173 if [[ ! -f $deltas ]]; then
174 return 1
176 if grep -q "$filename" $deltas; then
177 sed -i.backup "/$filename/d" $deltas && rm -f $deltas.backup
178 msg2 "$(gettext "Removing existing entry '%s'...")" "$filename"
179 return 0
182 return 1
183 } # end db_remove_delta
185 # write an entry to the pacman database
186 # arg1 - path to package
187 db_write_entry()
189 # blank out all variables
190 local pkgfile="$1"
191 local pkgname pkgver pkgdesc epoch csize size md5sum url arch builddate packager force \
192 _groups _licenses _replaces _depends _conflicts _provides _optdepends
194 local OLDIFS="$IFS"
195 # IFS (field separator) is only the newline character
196 IFS="
199 # read info from the zipped package
200 local line var val
201 for line in $(bsdtar -xOqf "$pkgfile" .PKGINFO |
202 grep -v '^#' | sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
203 # bash awesomeness here- var is always one word, val is everything else
204 var=${line%% *}
205 val=${line#* }
206 declare $var="$val"
207 case "$var" in
208 group) _groups="$_groups$group\n" ;;
209 license) _licenses="$_licenses$license\n" ;;
210 replaces) _replaces="$_replaces$replaces\n" ;;
211 depend) _depends="$_depends$depend\n" ;;
212 conflict) _conflicts="$_conflicts$conflict\n" ;;
213 provides) _provides="$_provides$provides\n" ;;
214 optdepend) _optdepends="$_optdepends$optdepend\n" ;;
215 esac
216 done
218 IFS=$OLDIFS
220 # get md5sum and compressed size of package
221 md5sum="$(openssl dgst -md5 "$pkgfile")"
222 md5sum="${md5sum##* }"
223 csize=$(@SIZECMD@ "$pkgfile")
225 # ensure $pkgname and $pkgver variables were found
226 if [[ -z $pkgname || -z $pkgver ]]; then
227 error "$(gettext "Invalid package file '%s'.")" "$pkgfile"
228 return 1
231 cd "$tmpdir"
233 if [[ -d $pkgname-$pkgver ]]; then
234 warning "$(gettext "An entry for '%s' already existed")" "$pkgname-$pkgver"
235 else
236 if [ $DELTA -eq 1 ]; then
237 pkgentry=$(find_pkgentry $pkgname)
238 if [ -n "$pkgentry" ]; then
239 local oldfilename=$(grep -A1 FILENAME $pkgentry/desc | tail -n1)
240 local oldfile="$(dirname $1)/$oldfilename"
245 # remove an existing entry if it exists, ignore failures
246 db_remove_entry "$pkgname"
248 # create package directory
249 mkdir "$pkgname-$pkgver"
250 cd "$pkgname-$pkgver"
252 # restore an eventual deltas file
253 [[ -f ../$pkgname.deltas ]] && mv "../$pkgname.deltas" deltas
255 # create desc entry
256 msg2 "$(gettext "Creating 'desc' db entry...")"
257 echo -e "%FILENAME%\n$(basename "$1")\n" >>desc
258 echo -e "%NAME%\n$pkgname\n" >>desc
259 [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc
260 echo -e "%VERSION%\n$pkgver\n" >>desc
261 [[ -n $pkgdesc ]] && echo -e "%DESC%\n$pkgdesc\n" >>desc
262 write_list_entry "GROUPS" "$_groups" "desc"
263 [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc
264 [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc
266 # compute checksums
267 msg2 "$(gettext "Computing md5 checksums...")"
268 echo -e "%MD5SUM%\n$md5sum\n" >>desc
270 [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc
271 write_list_entry "LICENSE" "$_licenses" "desc"
272 [[ -n $arch ]] && echo -e "%ARCH%\n$arch\n" >>desc
273 [[ -n $builddate ]] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
274 [[ -n $packager ]] && echo -e "%PACKAGER%\n$packager\n" >>desc
275 write_list_entry "REPLACES" "$_replaces" "desc"
276 # remain backward-compatible for now; put a force entry in the database
277 if [[ -n $epoch ]]; then
278 echo -e "%EPOCH%\n#epoch\n" >>desc
279 echo -e "%FORCE%\n" >>desc
281 [[ -n $force ]] && echo -e "%FORCE%\n" >>desc
283 # create depends entry
284 msg2 "$(gettext "Creating 'depends' db entry...")"
285 # create the file even if it will remain empty
286 touch "depends"
287 write_list_entry "DEPENDS" "$_depends" "depends"
288 write_list_entry "CONFLICTS" "$_conflicts" "depends"
289 write_list_entry "PROVIDES" "$_provides" "depends"
290 write_list_entry "OPTDEPENDS" "$_optdepends" "depends"
292 cd "$startdir"
294 # create a delta file
295 if [ -n "$oldfilename" -a -f "$oldfile" ]; then
296 delta=$(pkgdelta -q $oldfile $1)
297 if [ -f "$delta" ]; then
298 db_write_delta $delta
299 else
300 warning "$(gettext "Old package file not found : %s")" "$oldfilename"
304 return 0
305 } # end db_write_entry
307 # remove existing entries from the DB
308 # arg1 - package name
309 db_remove_entry() {
310 local pkgname=$1
311 local notfound=1
312 local pkgentry=$(find_pkgentry $pkgname)
313 while [[ -n $pkgentry ]]; do
314 notfound=0
315 if [[ -f $pkgentry/deltas ]]; then
316 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
318 msg2 "$(gettext "Removing existing entry '%s'...")" \
319 "$(basename $pkgentry)"
320 rm -rf $pkgentry
321 pkgentry=$(find_pkgentry $pkgname)
322 done
323 return $notfound
324 } # end db_remove_entry
326 check_repo_db()
328 # check lock file
329 if ( set -o noclobber; echo "$$" > "$LOCKFILE") 2> /dev/null; then
330 CLEAN_LOCK=1
331 else
332 error "$(gettext "Failed to acquire lockfile: %s.")" "$LOCKFILE"
333 [[ -f $LOCKFILE ]] && error "$(gettext "Held by process %s")" "$(cat $LOCKFILE)"
334 exit 1
337 if [[ -f $REPO_DB_FILE ]]; then
338 # there are two situations we can have here- a DB with some entries,
339 # or a DB with no contents at all.
340 if ! bsdtar -tqf "$REPO_DB_FILE" '*/desc' >/dev/null 2>&1; then
341 # check empty case
342 if [[ -n $(bsdtar -tqf "$REPO_DB_FILE" '*' 2>/dev/null) ]]; then
343 error "$(gettext "Repository file '%s' is not a proper pacman database.")" "$REPO_DB_FILE"
344 exit 1
347 msg "$(gettext "Extracting database to a temporary location...")"
348 bsdtar -xf "$REPO_DB_FILE" -C "$tmpdir"
349 else
350 case "$cmd" in
351 repo-remove)
352 error "$(gettext "Repository file '%s' was not found.")" "$REPO_DB_FILE"
353 exit 1
355 repo-add)
356 # check if the file can be created (write permission, directory existence, etc)
357 if ! touch "$REPO_DB_FILE"; then
358 error "$(gettext "Repository file '%s' could not be created.")" "$REPO_DB_FILE"
359 exit 1
361 rm -f "$REPO_DB_FILE"
363 esac
367 add()
369 if [[ ! -f $1 ]]; then
370 error "$(gettext "File '%s' not found.")" "$1"
371 return 1
374 if [[ ${1##*.} == "delta" ]]; then
375 deltafile=$1
376 msg "$(gettext "Adding delta '%s'")" "$deltafile"
377 if ! type xdelta3 &>/dev/null; then
378 error "$(gettext "Cannot find the xdelta3 binary! Is xdelta3 installed?")"
379 exit 1
381 if db_write_delta "$deltafile"; then
382 return 0
383 else
384 return 1
388 pkgfile=$1
389 if ! bsdtar -tqf "$pkgfile" .PKGINFO >/dev/null 2>&1; then
390 error "$(gettext "'%s' is not a package file, skipping")" "$pkgfile"
391 return 1
394 msg "$(gettext "Adding package '%s'")" "$pkgfile"
396 db_write_entry "$pkgfile"
399 remove()
401 if [[ ${1##*.} == "delta" ]]; then
402 deltafile=$1
403 msg "$(gettext "Searching for delta '%s'...")" "$deltafile"
404 if db_remove_delta "$deltafile"; then
405 return 0
406 else
407 error "$(gettext "Delta matching '%s' not found.")" "$deltafile"
408 return 1
412 pkgname=$1
413 msg "$(gettext "Searching for package '%s'...")" "$pkgname"
415 if db_remove_entry "$pkgname"; then
416 rm -f "$tmpdir/$pkgname.deltas"
417 return 0
418 else
419 error "$(gettext "Package matching '%s' not found.")" "$pkgname"
420 return 1
424 trap_exit()
426 echo
427 error "$@"
428 exit 1
431 clean_up() {
432 local exit_code=$?
434 cd "$startdir"
435 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
436 (( CLEAN_LOCK )) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
438 exit $exit_code
441 # PROGRAM START
443 # determine whether we have gettext; make it a no-op if we do not
444 if ! type gettext &>/dev/null; then
445 gettext() {
446 echo "$@"
450 case "$1" in
451 -h|--help) usage; exit 0;;
452 -V|--version) version; exit 0;;
453 esac
455 # figure out what program we are
456 cmd="$(basename $0)"
457 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
458 error "$(gettext "Invalid command name '%s' specified.")" "$cmd"
459 exit 1
462 tmpdir=$(mktemp -d /tmp/repo-tools.XXXXXXXXXX) || (\
463 error "$(gettext "Cannot create temp directory for database building.")"; \
464 exit 1)
466 trap 'clean_up' EXIT
467 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
468 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
469 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
471 success=0
472 # parse arguments
473 for arg in "$@"; do
474 case "$arg" in
475 -q|--quiet) QUIET=1;;
476 -d|--delta) DELTA=1;;
478 if [[ -z $REPO_DB_FILE ]]; then
479 REPO_DB_FILE="$arg"
480 LOCKFILE="$REPO_DB_FILE.lck"
481 check_repo_db
482 else
483 case "$cmd" in
484 repo-add) add $arg && success=1 ;;
485 repo-remove) remove $arg && success=1 ;;
486 esac
489 esac
490 done
492 # if at least one operation was a success, re-zip database
493 if (( success )); then
494 msg "$(gettext "Creating updated database file '%s'")" "$REPO_DB_FILE"
496 case "$REPO_DB_FILE" in
497 *tar.gz) TAR_OPT="z" ;;
498 *tar.bz2) TAR_OPT="j" ;;
499 *tar.xz) TAR_OPT="J" ;;
500 *) warning "$(gettext "'%s' does not have a valid archive extension.")" \
501 "$REPO_DB_FILE" ;;
502 esac
504 filename=$(basename "$REPO_DB_FILE")
506 cd "$tmpdir"
507 if [[ -n $(ls) ]]; then
508 bsdtar -c${TAR_OPT}f "$filename" *
509 else
510 # we have no packages remaining? zip up some emptyness
511 warning "$(gettext "No packages remain, creating empty database.")"
512 bsdtar -c${TAR_OPT}f "$filename" -T /dev/null
514 cd "$startdir"
516 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
517 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
518 dblink="${REPO_DB_FILE%.tar.*}"
519 target=${REPO_DB_FILE##*/}
520 ln -sf "$target" "$dblink" 2>/dev/null || \
521 ln -f "$target" "$dblink" 2>/dev/null || \
522 cp "$REPO_DB_FILE" "$dblink"
523 else
524 msg "$(gettext "No packages modified, nothing to do.")"
525 exit 1
528 exit 0
529 # vim: set ts=2 sw=2 noet: