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
41 m4_include
(library
/output_format.sh
)
43 # print usage instructions
46 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
47 if [[ $cmd == "repo-add" ]] ; then
48 printf "$(gettext "Usage
: repo-add
[options
] <path-to-db
> <package|delta
> ...
\n")"
50 repo-add will update a package database by reading a package
file.
\n\
51 Multiple packages to add can be specified on the
command line.
\n\n")"
52 printf "$(gettext "Options
:\n")"
53 printf "$(gettext " -d, --delta generate and add delta
for package update
\n")"
54 printf "$(gettext " -f, --files update database
's file list\n")"
55 elif [[ $cmd == "repo-remove" ]] ; then
56 printf "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n\n")"
58 repo-remove will update a package database by removing the package name\n\
59 specified on the command line from the given repo database. Multiple\n\
60 packages to remove can be specified on the command line.\n\n")"
61 printf "$(gettext "Options:\n")"
63 printf "$(gettext " -q, --quiet minimize output\n")"
64 printf "$(gettext " -s, --sign sign database with GnuPG after update\n")"
65 printf "$(gettext " -k, --key <key> use the specified key to sign the database\n")"
66 printf "$(gettext " -v, --verify verify database's signature before update
\n")"
67 printf "$(gettext "\n\
68 See
%s
(8) for more details and descriptions of the available options.
\n\n")" $cmd
69 if [[ $cmd == "repo-add" ]] ; then
70 echo "$(gettext "Example
: repo-add
/path
/to
/repo.db.
tar.gz pacman-3.0
.0-1-i686.pkg.
tar.gz
")"
71 elif [[ $cmd == "repo-remove" ]] ; then
72 echo "$(gettext "Example
: repo-remove
/path
/to
/repo.db.
tar.gz kernel26
")"
78 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
80 Copyright
(c
) 2006-2011 Pacman Development Team
<pacman-dev@archlinux.org
>\n\n\
81 This is free software
; see the
source for copying conditions.
\n\
82 There is NO WARRANTY
, to the extent permitted by law.
\n")"
88 # arg3 - File to write to
99 for pkgentry
in $tmpdir/$pkgname*; do
101 if [[ ${name%-*-*} = $pkgname ]]; then
109 # Get the package name from the delta filename
110 get_delta_pkgname
() {
117 # write a delta entry
118 # arg1 - path to delta file
121 pkgname
="$(get_delta_pkgname $deltafile)"
123 pkgentry
=$
(find_pkgentry
$pkgname)
124 if [[ -z $pkgentry ]]; then
125 error
"$(gettext "No database entry
for package
'%s'.
")" "$pkgname"
128 deltas
="$pkgentry/deltas"
129 if [[ ! -f $deltas ]]; then
130 echo -e "%DELTAS%" >$deltas
132 # get md5sum and compressed size of package
133 md5sum="$(openssl dgst -md5 "$deltafile")"
134 md5sum="${md5sum##* }"
135 csize
=$
(@SIZECMD@
"$deltafile")
137 oldfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (source)" |
sed 's/.*: *//')
138 newfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (output)" |
sed 's/.*: *//')
140 if grep -q "$oldfile.*$newfile" $deltas; then
141 sed -i.backup
"/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
143 msg2
"$(gettext "Adding
'deltas' entry
: %s
-> %s
")" "$oldfile" "$newfile"
144 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
147 } # end db_write_delta
149 # remove a delta entry
150 # arg1 - path to delta file
153 filename
=${deltafile##*/}
154 pkgname
="$(get_delta_pkgname $deltafile)"
156 pkgentry
=$
(find_pkgentry
$pkgname)
157 if [[ -z $pkgentry ]]; then
160 deltas
="$pkgentry/deltas"
161 if [[ ! -f $deltas ]]; then
164 if grep -q "$filename" $deltas; then
165 sed -i.backup
"/$filename/d" $deltas && rm -f $deltas.backup
166 msg2
"$(gettext "Removing existing entry
'%s'...
")" "$filename"
171 } # end db_remove_delta
174 if ! type -p gpg
>/dev
/null
; then
175 error
"$(gettext "Cannot
find the gpg binary
! Is gnupg installed?
")"
176 exit 1 # $E_MISSING_PROGRAM
180 # sign the package database once repackaged
182 (( ! SIGN
)) && return
185 msg
"$(gettext "Signing database...
")"
188 if [[ -n $GPGKEY ]]; then
189 SIGNWITHKEY
="-u ${GPGKEY}"
191 gpg
--detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev
/null || ret
=$?
194 msg2
"$(gettext "Created signature
file %s.
")" "$dbfile.sig"
196 warning
"$(gettext "Failed to sign package database.
")"
200 # verify the existing package database signature
202 (( ! VERIFY
)) && return
205 msg
"$(gettext "Verifying database signature...
")"
207 if [[ ! -f $dbfile.sig
]]; then
208 warning
"$(gettext "No existing signature found
, skipping verification.
")"
211 gpg
--verify "$dbfile.sig" || ret
=$?
213 msg2
"$(gettext "Database signature
file verified.
")"
215 error
"$(gettext "Database signature was NOT valid
!")"
220 # write an entry to the pacman database
221 # arg1 - path to package
223 # blank out all variables
225 local pkgname pkgver pkgdesc csize size url arch builddate packager \
226 _groups _licenses _replaces _depends _conflicts _provides _optdepends \
227 md5sum sha256sum pgpsig
230 # IFS (field separator) is only the newline character
234 # read info from the zipped package
236 for line
in $
(bsdtar
-xOqf "$pkgfile" .PKGINFO |
237 grep -v '^#' |
sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
238 # bash awesomeness here- var is always one word, val is everything else
243 group
) _groups
="$_groups$group\n" ;;
244 license
) _licenses
="$_licenses$license\n" ;;
245 replaces
) _replaces
="$_replaces$replaces\n" ;;
246 depend
) _depends
="$_depends$depend\n" ;;
247 conflict
) _conflicts
="$_conflicts$conflict\n" ;;
248 provides
) _provides
="$_provides$provides\n" ;;
249 optdepend
) _optdepends
="$_optdepends$optdepend\n" ;;
255 csize
=$
(@SIZECMD@
"$pkgfile")
258 msg2
"$(gettext "Computing checksums...
")"
259 md5sum="$(openssl dgst -md5 "$pkgfile")"
260 md5sum="${md5sum##* }"
261 sha256sum
="$(openssl dgst -sha256 "$pkgfile")"
262 sha256sum
="${sha256sum##* }"
264 # compute base64'd PGP signature
265 if [[ -f "$pkgfile.sig" ]]; then
266 pgpsig
=$
(openssl base64
-in "$pkgfile.sig" |
tr -d '\n')
269 # ensure $pkgname and $pkgver variables were found
270 if [[ -z $pkgname ||
-z $pkgver ]]; then
271 error
"$(gettext "Invalid package
file '%s'.
")" "$pkgfile"
275 pushd "$tmpdir" >/dev
/null
276 if [[ -d $pkgname-$pkgver ]]; then
277 warning
"$(gettext "An entry
for '%s' already existed
")" "$pkgname-$pkgver"
280 pkgentry
=$
(find_pkgentry
$pkgname)
281 if [[ -n $pkgentry ]]; then
282 local oldfilename
=$
(grep -A1 FILENAME
$pkgentry/desc |
tail -n1)
283 local oldfile
="$(dirname $1)/$oldfilename"
288 # remove an existing entry if it exists, ignore failures
289 db_remove_entry
"$pkgname"
291 # create package directory
292 mkdir
"$pkgname-$pkgver"
293 pushd "$pkgname-$pkgver" >/dev
/null
295 # restore an eventual deltas file
296 [[ -f ..
/$pkgname.deltas
]] && mv "../$pkgname.deltas" deltas
299 msg2
"$(gettext "Creating
'%s' db entry...
")" 'desc'
300 echo -e "%FILENAME%\n${1##*/}\n" >>desc
301 echo -e "%NAME%\n$pkgname\n" >>desc
302 [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc
303 echo -e "%VERSION%\n$pkgver\n" >>desc
304 [[ -n $pkgdesc ]] && echo -e "%DESC%\n$pkgdesc\n" >>desc
305 write_list_entry
"GROUPS" "$_groups" "desc"
306 [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc
307 [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc
310 echo -e "%MD5SUM%\n$md5sum\n" >>desc
311 echo -e "%SHA256SUM%\n$sha256sum\n" >>desc
314 [[ -n $pgpsig ]] && echo -e "%PGPSIG%\n$pgpsig\n" >>desc
316 [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc
317 write_list_entry
"LICENSE" "$_licenses" "desc"
318 [[ -n $arch ]] && echo -e "%ARCH%\n$arch\n" >>desc
319 [[ -n $builddate ]] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
320 [[ -n $packager ]] && echo -e "%PACKAGER%\n$packager\n" >>desc
321 write_list_entry
"REPLACES" "$_replaces" "desc"
323 # create depends entry
324 msg2
"$(gettext "Creating
'%s' db entry...
")" 'depends'
325 # create the file even if it will remain empty
327 write_list_entry
"DEPENDS" "$_depends" "depends"
328 write_list_entry
"CONFLICTS" "$_conflicts" "depends"
329 write_list_entry
"PROVIDES" "$_provides" "depends"
330 write_list_entry
"OPTDEPENDS" "$_optdepends" "depends"
335 # create files file if wanted
336 if (( WITHFILES
)); then
337 msg2
"$(gettext "Creating
'%s' db entry...
")" 'files'
338 local files_path
="$tmpdir/$pkgname-$pkgver/files"
339 echo "%FILES%" >$files_path
340 bsdtar
--exclude='^.*' -tf "$pkgfile" >>$files_path
343 # create a delta file
345 if [[ -n $oldfilename ]]; then
346 if [[ -f $oldfile ]]; then
347 delta
=$
(pkgdelta
-q $oldfile $1)
348 if [[ -f $delta ]]; then
349 db_write_delta
$delta
352 warning
"$(gettext "Old package
file not found
: %s
")" "$oldfilename"
358 } # end db_write_entry
360 # remove existing entries from the DB
361 # arg1 - package name
365 local pkgentry
=$
(find_pkgentry
$pkgname)
366 while [[ -n $pkgentry ]]; do
368 if [[ -f $pkgentry/deltas
]]; then
369 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
371 msg2
"$(gettext "Removing existing entry
'%s'...
")" \
374 pkgentry
=$
(find_pkgentry
$pkgname)
377 } # end db_remove_entry
382 # ensure the path to the DB exists
383 if [[ "$LOCKFILE" == /* ]]; then
384 repodir
=${LOCKFILE%/*}/
386 repodir
=$PWD/$LOCKFILE
387 repodir
=${repodir%/*}/
390 if [[ ! -d "$repodir" ]]; then
391 error
"$(gettext "%s does not exist or is not a directory.
")" "$repodir"
396 if ( set -o noclobber
; echo "$$" > "$LOCKFILE") 2> /dev
/null
; then
399 error
"$(gettext "Failed to acquire lockfile
: %s.
")" "$LOCKFILE"
400 [[ -f $LOCKFILE ]] && error
"$(gettext "Held by process
%s
")" "$(cat $LOCKFILE)"
404 if [[ -f $REPO_DB_FILE ]]; then
405 # there are two situations we can have here- a DB with some entries,
406 # or a DB with no contents at all.
407 if ! bsdtar
-tqf "$REPO_DB_FILE" '*/desc' >/dev
/null
2>&1; then
409 if [[ -n $
(bsdtar
-tqf "$REPO_DB_FILE" '*' 2>/dev
/null
) ]]; then
410 error
"$(gettext "Repository
file '%s' is not a proper pacman database.
")" "$REPO_DB_FILE"
414 verify_signature
"$REPO_DB_FILE"
415 msg
"$(gettext "Extracting database to a temporary location...
")"
416 bsdtar
-xf "$REPO_DB_FILE" -C "$tmpdir"
420 error
"$(gettext "Repository
file '%s' was not found.
")" "$REPO_DB_FILE"
424 # check if the file can be created (write permission, directory existence, etc)
425 if ! touch "$REPO_DB_FILE"; then
426 error
"$(gettext "Repository
file '%s' could not be created.
")" "$REPO_DB_FILE"
429 rm -f "$REPO_DB_FILE"
436 if [[ ! -f $1 ]]; then
437 error
"$(gettext "File
'%s' not found.
")" "$1"
441 if [[ ${1##*.} == "delta" ]]; then
443 msg
"$(gettext "Adding delta
'%s'")" "$deltafile"
444 if ! type xdelta3
&>/dev
/null
; then
445 error
"$(gettext "Cannot
find the xdelta3 binary
! Is xdelta3 installed?
")"
448 if db_write_delta
"$deltafile"; then
456 if ! bsdtar
-tqf "$pkgfile" .PKGINFO
>/dev
/null
2>&1; then
457 error
"$(gettext "'%s' is not a package
file, skipping
")" "$pkgfile"
461 msg
"$(gettext "Adding package
'%s'")" "$pkgfile"
463 db_write_entry
"$pkgfile"
467 if [[ ${1##*.} == "delta" ]]; then
469 msg
"$(gettext "Searching
for delta
'%s'...
")" "$deltafile"
470 if db_remove_delta
"$deltafile"; then
473 error
"$(gettext "Delta matching
'%s' not found.
")" "$deltafile"
479 msg
"$(gettext "Searching
for package
'%s'...
")" "$pkgname"
481 if db_remove_entry
"$pkgname"; then
482 rm -f "$tmpdir/$pkgname.deltas"
485 error
"$(gettext "Package matching
'%s' not found.
")" "$pkgname"
499 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
500 (( CLEAN_LOCK
)) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
507 # determine whether we have gettext; make it a no-op if we do not
508 if ! type gettext &>/dev
/null
; then
515 -h|
--help) usage
; exit 0;;
516 -V|
--version) version
; exit 0;;
519 # figure out what program we are
521 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
522 error
"$(gettext "Invalid
command name
'%s' specified.
")" "$cmd"
526 tmpdir
=$
(mktemp
-d /tmp
/repo-tools.XXXXXXXXXX
) ||
(\
527 error
"$(gettext "Cannot create temp directory
for database building.
")"; \
531 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
532 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
533 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
537 while [[ $# > 0 ]]; do
539 -q|
--quiet) QUIET
=1;;
540 -d|
--delta) DELTA
=1;;
541 -f|
--files) WITHFILES
=1;;
545 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
546 if [[ ! -z $GPGKEY ]]; then
547 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
549 error
"$(gettext "There is no key
in your keyring.
")"
558 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
559 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
568 if [[ -z $REPO_DB_FILE ]]; then
570 LOCKFILE
="$REPO_DB_FILE.lck"
574 repo-add
) add
$1 && success
=1 ;;
575 repo-remove
) remove
$1 && success
=1 ;;
583 # if at least one operation was a success, re-zip database
584 if (( success
)); then
585 msg
"$(gettext "Creating updated database
file '%s'")" "$REPO_DB_FILE"
587 case "$REPO_DB_FILE" in
588 *.
tar.gz
) TAR_OPT
="z" ;;
589 *.
tar.bz2
) TAR_OPT
="j" ;;
590 *.
tar.xz
) TAR_OPT
="J" ;;
592 *) warning
"$(gettext "'%s' does not have a valid archive extension.
")" \
596 filename
=${REPO_DB_FILE##*/}
598 pushd "$tmpdir" >/dev
/null
599 if [[ -n $
(ls) ]]; then
600 bsdtar
-c${TAR_OPT}f
"$filename" *
602 # we have no packages remaining? zip up some emptyness
603 warning
"$(gettext "No packages remain
, creating empty database.
")"
604 bsdtar
-c${TAR_OPT}f
"$filename" -T /dev
/null
606 create_signature
"$filename"
610 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
611 [[ -f $REPO_DB_FILE.sig
]] && rm -f "$REPO_DB_FILE.sig"
612 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
613 [[ -f $tmpdir/$filename.sig
]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig"
614 dblink
="${REPO_DB_FILE%.tar*}"
615 target
=${REPO_DB_FILE##*/}
616 ln -sf "$target" "$dblink" 2>/dev
/null || \
617 ln -f "$target" "$dblink" 2>/dev
/null || \
618 cp "$REPO_DB_FILE" "$dblink"
619 if [[ -f "$target.sig" ]]; then
620 ln -sf "$target.sig" "$dblink.sig" 2>/dev
/null || \
621 ln -f "$target.sig" "$dblink.sig" 2>/dev
/null || \
622 cp "$REPO_DB_FILE.sig" "$dblink.sig"
625 msg
"$(gettext "No packages modified
, nothing to
do.
")"
630 # vim: set ts=2 sw=2 noet: