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
7 # Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
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.
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.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # gettext initialization
23 export TEXTDOMAIN
='pacman'
24 export TEXTDOMAINDIR
='@localedir@'
26 myver
='@PACKAGE_VERSION@'
27 confdir
='@sysconfdir@'
38 # ensure we have a sane umask set
44 printf "==> ${mesg}\n" "$@" >&1
50 printf " -> ${mesg}\n" "$@" >&1
55 printf "==> $(gettext "WARNING
:") ${mesg}\n" "$@" >&2
60 printf "==> $(gettext "ERROR
:") ${mesg}\n" "$@" >&2
63 # print usage instructions
66 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
67 if [[ $cmd == "repo-add" ]] ; then
68 printf "$(gettext "Usage
: repo-add
[options
] <path-to-db
> <package|delta
> ...
\n")"
70 repo-add will update a package database by reading a package
file.
\n\
71 Multiple packages to add can be specified on the
command line.
\n\n")"
72 printf "$(gettext "Options
:\n")"
73 printf "$(gettext " -d, --delta generate and add delta
for package update
\n")"
74 printf "$(gettext " -f, --files update database
's file list\n")"
75 elif [[ $cmd == "repo-remove" ]] ; then
76 printf "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n\n")"
78 repo-remove will update a package database by removing the package name\n\
79 specified on the command line from the given repo database. Multiple\n\
80 packages to remove can be specified on the command line.\n\n")"
81 printf "$(gettext "Options:\n")"
83 printf "$(gettext " -q, --quiet minimize output\n")"
84 printf "$(gettext " -s, --sign sign database with GnuPG after update\n")"
85 printf "$(gettext " -k, --key <key> use the specified key to sign the database\n")"
86 printf "$(gettext " -v, --verify verify database's signature before update
\n")"
87 printf "$(gettext "\n\
88 See
%s
(8) for more details and descriptions of the available options.
\n\n")" $cmd
89 if [[ $cmd == "repo-add" ]] ; then
90 echo "$(gettext "Example
: repo-add
/path
/to
/repo.db.
tar.gz pacman-3.0
.0-1-i686.pkg.
tar.gz
")"
91 elif [[ $cmd == "repo-remove" ]] ; then
92 echo "$(gettext "Example
: repo-remove
/path
/to
/repo.db.
tar.gz kernel26
")"
98 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
100 Copyright
(c
) 2006-2011 Pacman Development Team
<pacman-dev@archlinux.org
>\n\n\
101 This is free software
; see the
source for copying conditions.
\n\
102 There is NO WARRANTY
, to the extent permitted by law.
\n")"
108 # arg3 - File to write to
120 for pkgentry
in $tmpdir/$pkgname*; do
122 if [[ ${name%-*-*} = $pkgname ]]; then
130 # Get the package name from the delta filename
131 get_delta_pkgname
() {
138 # write a delta entry
139 # arg1 - path to delta file
143 pkgname
="$(get_delta_pkgname $deltafile)"
145 pkgentry
=$
(find_pkgentry
$pkgname)
146 if [[ -z $pkgentry ]]; then
147 error
"$(gettext "No database entry
for package
'%s'.
")" "$pkgname"
150 deltas
="$pkgentry/deltas"
151 if [[ ! -f $deltas ]]; then
152 echo -e "%DELTAS%" >$deltas
154 # get md5sum and compressed size of package
155 md5sum="$(openssl dgst -md5 "$deltafile")"
156 md5sum="${md5sum##* }"
157 csize
=$
(@SIZECMD@
"$deltafile")
159 oldfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (source)" |
sed 's/.*: *//')
160 newfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (output)" |
sed 's/.*: *//')
162 if grep -q "$oldfile.*$newfile" $deltas; then
163 sed -i.backup
"/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
165 msg2
"$(gettext "Adding
'deltas' entry
: %s
-> %s
")" "$oldfile" "$newfile"
166 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
169 } # end db_write_delta
171 # remove a delta entry
172 # arg1 - path to delta file
176 filename
=${deltafile##*/}
177 pkgname
="$(get_delta_pkgname $deltafile)"
179 pkgentry
=$
(find_pkgentry
$pkgname)
180 if [[ -z $pkgentry ]]; then
183 deltas
="$pkgentry/deltas"
184 if [[ ! -f $deltas ]]; then
187 if grep -q "$filename" $deltas; then
188 sed -i.backup
"/$filename/d" $deltas && rm -f $deltas.backup
189 msg2
"$(gettext "Removing existing entry
'%s'...
")" "$filename"
194 } # end db_remove_delta
197 if ! type -p gpg
>/dev
/null
; then
198 error
"$(gettext "Cannot
find the gpg binary
! Is gnupg installed?
")"
199 exit 1 # $E_MISSING_PROGRAM
203 # sign the package database once repackaged
205 (( ! SIGN
)) && return
208 msg
"$(gettext "Signing database...
")"
211 if [[ -n $GPGKEY ]]; then
212 SIGNWITHKEY
="-u ${GPGKEY}"
214 gpg
--detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev
/null || ret
=$?
217 msg2
"$(gettext "Created signature
file %s.
")" "$dbfile.sig"
219 warning
"$(gettext "Failed to sign package database.
")"
223 # verify the existing package database signature
225 (( ! VERIFY
)) && return
228 msg
"$(gettext "Verifying database signature...
")"
230 if [[ ! -f $dbfile.sig
]]; then
231 warning
"$(gettext "No existing signature found
, skipping verification.
")"
234 gpg
--verify "$dbfile.sig" || ret
=$?
236 msg2
"$(gettext "Database signature
file verified.
")"
238 error
"$(gettext "Database signature was NOT valid
!")"
243 # write an entry to the pacman database
244 # arg1 - path to package
247 # blank out all variables
249 local pkgname pkgver pkgdesc csize size url arch builddate packager \
250 _groups _licenses _replaces _depends _conflicts _provides _optdepends \
251 md5sum sha256sum pgpsig
254 # IFS (field separator) is only the newline character
258 # read info from the zipped package
260 for line
in $
(bsdtar
-xOqf "$pkgfile" .PKGINFO |
261 grep -v '^#' |
sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
262 # bash awesomeness here- var is always one word, val is everything else
267 group
) _groups
="$_groups$group\n" ;;
268 license
) _licenses
="$_licenses$license\n" ;;
269 replaces
) _replaces
="$_replaces$replaces\n" ;;
270 depend
) _depends
="$_depends$depend\n" ;;
271 conflict
) _conflicts
="$_conflicts$conflict\n" ;;
272 provides
) _provides
="$_provides$provides\n" ;;
273 optdepend
) _optdepends
="$_optdepends$optdepend\n" ;;
279 csize
=$
(@SIZECMD@
"$pkgfile")
282 msg2
"$(gettext "Computing checksums...
")"
283 md5sum="$(openssl dgst -md5 "$pkgfile")"
284 md5sum="${md5sum##* }"
285 sha256sum
="$(openssl dgst -sha256 "$pkgfile")"
286 sha256sum
="${sha256sum##* }"
288 # compute base64'd PGP signature
289 if [[ -f "$pkgfile.sig" ]]; then
290 pgpsig
=$
(openssl base64
-in "$pkgfile.sig" |
tr -d '\n')
293 # ensure $pkgname and $pkgver variables were found
294 if [[ -z $pkgname ||
-z $pkgver ]]; then
295 error
"$(gettext "Invalid package
file '%s'.
")" "$pkgfile"
299 pushd "$tmpdir" >/dev
/null
300 if [[ -d $pkgname-$pkgver ]]; then
301 warning
"$(gettext "An entry
for '%s' already existed
")" "$pkgname-$pkgver"
304 pkgentry
=$
(find_pkgentry
$pkgname)
305 if [[ -n $pkgentry ]]; then
306 local oldfilename
=$
(grep -A1 FILENAME
$pkgentry/desc |
tail -n1)
307 local oldfile
="$(dirname $1)/$oldfilename"
312 # remove an existing entry if it exists, ignore failures
313 db_remove_entry
"$pkgname"
315 # create package directory
316 mkdir
"$pkgname-$pkgver"
317 pushd "$pkgname-$pkgver" >/dev
/null
319 # restore an eventual deltas file
320 [[ -f ..
/$pkgname.deltas
]] && mv "../$pkgname.deltas" deltas
323 msg2
"$(gettext "Creating
'%s' db entry...
")" 'desc'
324 echo -e "%FILENAME%\n$(basename "$1")\n" >>desc
325 echo -e "%NAME%\n$pkgname\n" >>desc
326 [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc
327 echo -e "%VERSION%\n$pkgver\n" >>desc
328 [[ -n $pkgdesc ]] && echo -e "%DESC%\n$pkgdesc\n" >>desc
329 write_list_entry
"GROUPS" "$_groups" "desc"
330 [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc
331 [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc
334 echo -e "%MD5SUM%\n$md5sum\n" >>desc
335 echo -e "%SHA256SUM%\n$sha256sum\n" >>desc
338 [[ -n $pgpsig ]] && echo -e "%PGPSIG%\n$pgpsig\n" >>desc
340 [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc
341 write_list_entry
"LICENSE" "$_licenses" "desc"
342 [[ -n $arch ]] && echo -e "%ARCH%\n$arch\n" >>desc
343 [[ -n $builddate ]] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
344 [[ -n $packager ]] && echo -e "%PACKAGER%\n$packager\n" >>desc
345 write_list_entry
"REPLACES" "$_replaces" "desc"
347 # create depends entry
348 msg2
"$(gettext "Creating
'%s' db entry...
")" 'depends'
349 # create the file even if it will remain empty
351 write_list_entry
"DEPENDS" "$_depends" "depends"
352 write_list_entry
"CONFLICTS" "$_conflicts" "depends"
353 write_list_entry
"PROVIDES" "$_provides" "depends"
354 write_list_entry
"OPTDEPENDS" "$_optdepends" "depends"
359 # create files file if wanted
360 if (( WITHFILES
)); then
361 msg2
"$(gettext "Creating
'%s' db entry...
")" 'files'
362 local files_path
="$tmpdir/$pkgname-$pkgver/files"
363 echo "%FILES%" >$files_path
364 bsdtar
--exclude='.*' -tf "$pkgfile" >>$files_path
367 # create a delta file
369 if [[ -n $oldfilename ]]; then
370 if [[ -f $oldfile ]]; then
371 delta
=$
(pkgdelta
-q $oldfile $1)
372 if [[ -f $delta ]]; then
373 db_write_delta
$delta
376 warning
"$(gettext "Old package
file not found
: %s
")" "$oldfilename"
382 } # end db_write_entry
384 # remove existing entries from the DB
385 # arg1 - package name
389 local pkgentry
=$
(find_pkgentry
$pkgname)
390 while [[ -n $pkgentry ]]; do
392 if [[ -f $pkgentry/deltas
]]; then
393 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
395 msg2
"$(gettext "Removing existing entry
'%s'...
")" \
396 "$(basename $pkgentry)"
398 pkgentry
=$
(find_pkgentry
$pkgname)
401 } # end db_remove_entry
406 if ( set -o noclobber
; echo "$$" > "$LOCKFILE") 2> /dev
/null
; then
409 error
"$(gettext "Failed to acquire lockfile
: %s.
")" "$LOCKFILE"
410 [[ -f $LOCKFILE ]] && error
"$(gettext "Held by process
%s
")" "$(cat $LOCKFILE)"
414 if [[ -f $REPO_DB_FILE ]]; then
415 # there are two situations we can have here- a DB with some entries,
416 # or a DB with no contents at all.
417 if ! bsdtar
-tqf "$REPO_DB_FILE" '*/desc' >/dev
/null
2>&1; then
419 if [[ -n $
(bsdtar
-tqf "$REPO_DB_FILE" '*' 2>/dev
/null
) ]]; then
420 error
"$(gettext "Repository
file '%s' is not a proper pacman database.
")" "$REPO_DB_FILE"
424 verify_signature
"$REPO_DB_FILE"
425 msg
"$(gettext "Extracting database to a temporary location...
")"
426 bsdtar
-xf "$REPO_DB_FILE" -C "$tmpdir"
430 error
"$(gettext "Repository
file '%s' was not found.
")" "$REPO_DB_FILE"
434 # check if the file can be created (write permission, directory existence, etc)
435 if ! touch "$REPO_DB_FILE"; then
436 error
"$(gettext "Repository
file '%s' could not be created.
")" "$REPO_DB_FILE"
439 rm -f "$REPO_DB_FILE"
447 if [[ ! -f $1 ]]; then
448 error
"$(gettext "File
'%s' not found.
")" "$1"
452 if [[ ${1##*.} == "delta" ]]; then
454 msg
"$(gettext "Adding delta
'%s'")" "$deltafile"
455 if ! type xdelta3
&>/dev
/null
; then
456 error
"$(gettext "Cannot
find the xdelta3 binary
! Is xdelta3 installed?
")"
459 if db_write_delta
"$deltafile"; then
467 if ! bsdtar
-tqf "$pkgfile" .PKGINFO
>/dev
/null
2>&1; then
468 error
"$(gettext "'%s' is not a package
file, skipping
")" "$pkgfile"
472 msg
"$(gettext "Adding package
'%s'")" "$pkgfile"
474 db_write_entry
"$pkgfile"
479 if [[ ${1##*.} == "delta" ]]; then
481 msg
"$(gettext "Searching
for delta
'%s'...
")" "$deltafile"
482 if db_remove_delta
"$deltafile"; then
485 error
"$(gettext "Delta matching
'%s' not found.
")" "$deltafile"
491 msg
"$(gettext "Searching
for package
'%s'...
")" "$pkgname"
493 if db_remove_entry
"$pkgname"; then
494 rm -f "$tmpdir/$pkgname.deltas"
497 error
"$(gettext "Package matching
'%s' not found.
")" "$pkgname"
512 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
513 (( CLEAN_LOCK
)) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
520 # determine whether we have gettext; make it a no-op if we do not
521 if ! type gettext &>/dev
/null
; then
528 -h|
--help) usage
; exit 0;;
529 -V|
--version) version
; exit 0;;
532 # figure out what program we are
534 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
535 error
"$(gettext "Invalid
command name
'%s' specified.
")" "$cmd"
539 tmpdir
=$
(mktemp
-d /tmp
/repo-tools.XXXXXXXXXX
) ||
(\
540 error
"$(gettext "Cannot create temp directory
for database building.
")"; \
544 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
545 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
546 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
550 while [[ $# > 0 ]]; do
552 -q|
--quiet) QUIET
=1;;
553 -d|
--delta) DELTA
=1;;
554 -f|
--files) WITHFILES
=1;;
558 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
559 if [[ ! -z $GPGKEY ]]; then
560 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
562 error
"$(gettext "There is no key
in your keyring.
")"
571 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
572 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
581 if [[ -z $REPO_DB_FILE ]]; then
583 LOCKFILE
="$REPO_DB_FILE.lck"
587 repo-add
) add
$1 && success
=1 ;;
588 repo-remove
) remove
$1 && success
=1 ;;
596 # if at least one operation was a success, re-zip database
597 if (( success
)); then
598 msg
"$(gettext "Creating updated database
file '%s'")" "$REPO_DB_FILE"
600 case "$REPO_DB_FILE" in
601 *tar.gz
) TAR_OPT
="z" ;;
602 *tar.bz2
) TAR_OPT
="j" ;;
603 *tar.xz
) TAR_OPT
="J" ;;
604 *) warning
"$(gettext "'%s' does not have a valid archive extension.
")" \
608 filename
=$
(basename "$REPO_DB_FILE")
610 pushd "$tmpdir" >/dev
/null
611 if [[ -n $
(ls) ]]; then
612 bsdtar
-c${TAR_OPT}f
"$filename" *
614 # we have no packages remaining? zip up some emptyness
615 warning
"$(gettext "No packages remain
, creating empty database.
")"
616 bsdtar
-c${TAR_OPT}f
"$filename" -T /dev
/null
618 create_signature
"$filename"
622 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
623 [[ -f $REPO_DB_FILE.sig
]] && rm -f "$REPO_DB_FILE.sig"
624 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
625 [[ -f $tmpdir/$filename.sig
]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig"
626 dblink
="${REPO_DB_FILE%.tar.*}"
627 target
=${REPO_DB_FILE##*/}
628 ln -sf "$target" "$dblink" 2>/dev
/null || \
629 ln -f "$target" "$dblink" 2>/dev
/null || \
630 cp "$REPO_DB_FILE" "$dblink"
631 if [[ -f "$target.sig" ]]; then
632 ln -sf "$target.sig" "$dblink.sig" 2>/dev
/null || \
633 ln -f "$target.sig" "$dblink.sig" 2>/dev
/null || \
634 cp "$REPO_DB_FILE.sig" "$dblink.sig"
637 msg
"$(gettext "No packages modified
, nothing to
do.
")"
642 # vim: set ts=2 sw=2 noet: