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
100 for pkgentry
in $tmpdir/$pkgname*; do
102 if [[ ${name%-*-*} = $pkgname ]]; then
110 # Get the package name from the delta filename
111 get_delta_pkgname
() {
118 # write a delta entry
119 # arg1 - path to delta file
123 pkgname
="$(get_delta_pkgname $deltafile)"
125 pkgentry
=$
(find_pkgentry
$pkgname)
126 if [[ -z $pkgentry ]]; then
127 error
"$(gettext "No database entry
for package
'%s'.
")" "$pkgname"
130 deltas
="$pkgentry/deltas"
131 if [[ ! -f $deltas ]]; then
132 echo -e "%DELTAS%" >$deltas
134 # get md5sum and compressed size of package
135 md5sum="$(openssl dgst -md5 "$deltafile")"
136 md5sum="${md5sum##* }"
137 csize
=$
(@SIZECMD@
"$deltafile")
139 oldfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (source)" |
sed 's/.*: *//')
140 newfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (output)" |
sed 's/.*: *//')
142 if grep -q "$oldfile.*$newfile" $deltas; then
143 sed -i.backup
"/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
145 msg2
"$(gettext "Adding
'deltas' entry
: %s
-> %s
")" "$oldfile" "$newfile"
146 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
149 } # end db_write_delta
151 # remove a delta entry
152 # arg1 - path to delta file
156 filename
=${deltafile##*/}
157 pkgname
="$(get_delta_pkgname $deltafile)"
159 pkgentry
=$
(find_pkgentry
$pkgname)
160 if [[ -z $pkgentry ]]; then
163 deltas
="$pkgentry/deltas"
164 if [[ ! -f $deltas ]]; then
167 if grep -q "$filename" $deltas; then
168 sed -i.backup
"/$filename/d" $deltas && rm -f $deltas.backup
169 msg2
"$(gettext "Removing existing entry
'%s'...
")" "$filename"
174 } # end db_remove_delta
177 if ! type -p gpg
>/dev
/null
; then
178 error
"$(gettext "Cannot
find the gpg binary
! Is gnupg installed?
")"
179 exit 1 # $E_MISSING_PROGRAM
183 # sign the package database once repackaged
185 (( ! SIGN
)) && return
188 msg
"$(gettext "Signing database...
")"
191 if [[ -n $GPGKEY ]]; then
192 SIGNWITHKEY
="-u ${GPGKEY}"
194 gpg
--detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev
/null || ret
=$?
197 msg2
"$(gettext "Created signature
file %s.
")" "$dbfile.sig"
199 warning
"$(gettext "Failed to sign package database.
")"
203 # verify the existing package database signature
205 (( ! VERIFY
)) && return
208 msg
"$(gettext "Verifying database signature...
")"
210 if [[ ! -f $dbfile.sig
]]; then
211 warning
"$(gettext "No existing signature found
, skipping verification.
")"
214 gpg
--verify "$dbfile.sig" || ret
=$?
216 msg2
"$(gettext "Database signature
file verified.
")"
218 error
"$(gettext "Database signature was NOT valid
!")"
223 # write an entry to the pacman database
224 # arg1 - path to package
227 # blank out all variables
229 local pkgname pkgver pkgdesc csize size url arch builddate packager \
230 _groups _licenses _replaces _depends _conflicts _provides _optdepends \
231 md5sum sha256sum pgpsig
234 # IFS (field separator) is only the newline character
238 # read info from the zipped package
240 for line
in $
(bsdtar
-xOqf "$pkgfile" .PKGINFO |
241 grep -v '^#' |
sed 's|\(\w*\)\s*=\s*\(.*\)|\1 \2|'); do
242 # bash awesomeness here- var is always one word, val is everything else
247 group
) _groups
="$_groups$group\n" ;;
248 license
) _licenses
="$_licenses$license\n" ;;
249 replaces
) _replaces
="$_replaces$replaces\n" ;;
250 depend
) _depends
="$_depends$depend\n" ;;
251 conflict
) _conflicts
="$_conflicts$conflict\n" ;;
252 provides
) _provides
="$_provides$provides\n" ;;
253 optdepend
) _optdepends
="$_optdepends$optdepend\n" ;;
259 csize
=$
(@SIZECMD@
"$pkgfile")
262 msg2
"$(gettext "Computing checksums...
")"
263 md5sum="$(openssl dgst -md5 "$pkgfile")"
264 md5sum="${md5sum##* }"
265 sha256sum
="$(openssl dgst -sha256 "$pkgfile")"
266 sha256sum
="${sha256sum##* }"
268 # compute base64'd PGP signature
269 if [[ -f "$pkgfile.sig" ]]; then
270 pgpsig
=$
(openssl base64
-in "$pkgfile.sig" |
tr -d '\n')
273 # ensure $pkgname and $pkgver variables were found
274 if [[ -z $pkgname ||
-z $pkgver ]]; then
275 error
"$(gettext "Invalid package
file '%s'.
")" "$pkgfile"
279 pushd "$tmpdir" >/dev
/null
280 if [[ -d $pkgname-$pkgver ]]; then
281 warning
"$(gettext "An entry
for '%s' already existed
")" "$pkgname-$pkgver"
284 pkgentry
=$
(find_pkgentry
$pkgname)
285 if [[ -n $pkgentry ]]; then
286 local oldfilename
=$
(grep -A1 FILENAME
$pkgentry/desc |
tail -n1)
287 local oldfile
="$(dirname $1)/$oldfilename"
292 # remove an existing entry if it exists, ignore failures
293 db_remove_entry
"$pkgname"
295 # create package directory
296 mkdir
"$pkgname-$pkgver"
297 pushd "$pkgname-$pkgver" >/dev
/null
299 # restore an eventual deltas file
300 [[ -f ..
/$pkgname.deltas
]] && mv "../$pkgname.deltas" deltas
303 msg2
"$(gettext "Creating
'%s' db entry...
")" 'desc'
304 echo -e "%FILENAME%\n$(basename "$1")\n" >>desc
305 echo -e "%NAME%\n$pkgname\n" >>desc
306 [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc
307 echo -e "%VERSION%\n$pkgver\n" >>desc
308 [[ -n $pkgdesc ]] && echo -e "%DESC%\n$pkgdesc\n" >>desc
309 write_list_entry
"GROUPS" "$_groups" "desc"
310 [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc
311 [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc
314 echo -e "%MD5SUM%\n$md5sum\n" >>desc
315 echo -e "%SHA256SUM%\n$sha256sum\n" >>desc
318 [[ -n $pgpsig ]] && echo -e "%PGPSIG%\n$pgpsig\n" >>desc
320 [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc
321 write_list_entry
"LICENSE" "$_licenses" "desc"
322 [[ -n $arch ]] && echo -e "%ARCH%\n$arch\n" >>desc
323 [[ -n $builddate ]] && echo -e "%BUILDDATE%\n$builddate\n" >>desc
324 [[ -n $packager ]] && echo -e "%PACKAGER%\n$packager\n" >>desc
325 write_list_entry
"REPLACES" "$_replaces" "desc"
327 # create depends entry
328 msg2
"$(gettext "Creating
'%s' db entry...
")" 'depends'
329 # create the file even if it will remain empty
331 write_list_entry
"DEPENDS" "$_depends" "depends"
332 write_list_entry
"CONFLICTS" "$_conflicts" "depends"
333 write_list_entry
"PROVIDES" "$_provides" "depends"
334 write_list_entry
"OPTDEPENDS" "$_optdepends" "depends"
339 # create files file if wanted
340 if (( WITHFILES
)); then
341 msg2
"$(gettext "Creating
'%s' db entry...
")" 'files'
342 local files_path
="$tmpdir/$pkgname-$pkgver/files"
343 echo "%FILES%" >$files_path
344 bsdtar
--exclude='^.*' -tf "$pkgfile" >>$files_path
347 # create a delta file
349 if [[ -n $oldfilename ]]; then
350 if [[ -f $oldfile ]]; then
351 delta
=$
(pkgdelta
-q $oldfile $1)
352 if [[ -f $delta ]]; then
353 db_write_delta
$delta
356 warning
"$(gettext "Old package
file not found
: %s
")" "$oldfilename"
362 } # end db_write_entry
364 # remove existing entries from the DB
365 # arg1 - package name
369 local pkgentry
=$
(find_pkgentry
$pkgname)
370 while [[ -n $pkgentry ]]; do
372 if [[ -f $pkgentry/deltas
]]; then
373 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
375 msg2
"$(gettext "Removing existing entry
'%s'...
")" \
376 "$(basename $pkgentry)"
378 pkgentry
=$
(find_pkgentry
$pkgname)
381 } # end db_remove_entry
386 if ( set -o noclobber
; echo "$$" > "$LOCKFILE") 2> /dev
/null
; then
389 error
"$(gettext "Failed to acquire lockfile
: %s.
")" "$LOCKFILE"
390 [[ -f $LOCKFILE ]] && error
"$(gettext "Held by process
%s
")" "$(cat $LOCKFILE)"
394 if [[ -f $REPO_DB_FILE ]]; then
395 # there are two situations we can have here- a DB with some entries,
396 # or a DB with no contents at all.
397 if ! bsdtar
-tqf "$REPO_DB_FILE" '*/desc' >/dev
/null
2>&1; then
399 if [[ -n $
(bsdtar
-tqf "$REPO_DB_FILE" '*' 2>/dev
/null
) ]]; then
400 error
"$(gettext "Repository
file '%s' is not a proper pacman database.
")" "$REPO_DB_FILE"
404 verify_signature
"$REPO_DB_FILE"
405 msg
"$(gettext "Extracting database to a temporary location...
")"
406 bsdtar
-xf "$REPO_DB_FILE" -C "$tmpdir"
410 error
"$(gettext "Repository
file '%s' was not found.
")" "$REPO_DB_FILE"
414 # check if the file can be created (write permission, directory existence, etc)
415 if ! touch "$REPO_DB_FILE"; then
416 error
"$(gettext "Repository
file '%s' could not be created.
")" "$REPO_DB_FILE"
419 rm -f "$REPO_DB_FILE"
427 if [[ ! -f $1 ]]; then
428 error
"$(gettext "File
'%s' not found.
")" "$1"
432 if [[ ${1##*.} == "delta" ]]; then
434 msg
"$(gettext "Adding delta
'%s'")" "$deltafile"
435 if ! type xdelta3
&>/dev
/null
; then
436 error
"$(gettext "Cannot
find the xdelta3 binary
! Is xdelta3 installed?
")"
439 if db_write_delta
"$deltafile"; then
447 if ! bsdtar
-tqf "$pkgfile" .PKGINFO
>/dev
/null
2>&1; then
448 error
"$(gettext "'%s' is not a package
file, skipping
")" "$pkgfile"
452 msg
"$(gettext "Adding package
'%s'")" "$pkgfile"
454 db_write_entry
"$pkgfile"
459 if [[ ${1##*.} == "delta" ]]; then
461 msg
"$(gettext "Searching
for delta
'%s'...
")" "$deltafile"
462 if db_remove_delta
"$deltafile"; then
465 error
"$(gettext "Delta matching
'%s' not found.
")" "$deltafile"
471 msg
"$(gettext "Searching
for package
'%s'...
")" "$pkgname"
473 if db_remove_entry
"$pkgname"; then
474 rm -f "$tmpdir/$pkgname.deltas"
477 error
"$(gettext "Package matching
'%s' not found.
")" "$pkgname"
492 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
493 (( CLEAN_LOCK
)) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
500 # determine whether we have gettext; make it a no-op if we do not
501 if ! type gettext &>/dev
/null
; then
508 -h|
--help) usage
; exit 0;;
509 -V|
--version) version
; exit 0;;
512 # figure out what program we are
514 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
515 error
"$(gettext "Invalid
command name
'%s' specified.
")" "$cmd"
519 tmpdir
=$
(mktemp
-d /tmp
/repo-tools.XXXXXXXXXX
) ||
(\
520 error
"$(gettext "Cannot create temp directory
for database building.
")"; \
524 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
525 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
526 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
530 while [[ $# > 0 ]]; do
532 -q|
--quiet) QUIET
=1;;
533 -d|
--delta) DELTA
=1;;
534 -f|
--files) WITHFILES
=1;;
538 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
539 if [[ ! -z $GPGKEY ]]; then
540 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
542 error
"$(gettext "There is no key
in your keyring.
")"
551 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
552 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
561 if [[ -z $REPO_DB_FILE ]]; then
563 LOCKFILE
="$REPO_DB_FILE.lck"
567 repo-add
) add
$1 && success
=1 ;;
568 repo-remove
) remove
$1 && success
=1 ;;
576 # if at least one operation was a success, re-zip database
577 if (( success
)); then
578 msg
"$(gettext "Creating updated database
file '%s'")" "$REPO_DB_FILE"
580 case "$REPO_DB_FILE" in
581 *tar.gz
) TAR_OPT
="z" ;;
582 *tar.bz2
) TAR_OPT
="j" ;;
583 *tar.xz
) TAR_OPT
="J" ;;
584 *) warning
"$(gettext "'%s' does not have a valid archive extension.
")" \
588 filename
=$
(basename "$REPO_DB_FILE")
590 pushd "$tmpdir" >/dev
/null
591 if [[ -n $
(ls) ]]; then
592 bsdtar
-c${TAR_OPT}f
"$filename" *
594 # we have no packages remaining? zip up some emptyness
595 warning
"$(gettext "No packages remain
, creating empty database.
")"
596 bsdtar
-c${TAR_OPT}f
"$filename" -T /dev
/null
598 create_signature
"$filename"
602 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
603 [[ -f $REPO_DB_FILE.sig
]] && rm -f "$REPO_DB_FILE.sig"
604 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
605 [[ -f $tmpdir/$filename.sig
]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig"
606 dblink
="${REPO_DB_FILE%.tar.*}"
607 target
=${REPO_DB_FILE##*/}
608 ln -sf "$target" "$dblink" 2>/dev
/null || \
609 ln -f "$target" "$dblink" 2>/dev
/null || \
610 cp "$REPO_DB_FILE" "$dblink"
611 if [[ -f "$target.sig" ]]; then
612 ln -sf "$target.sig" "$dblink.sig" 2>/dev
/null || \
613 ln -f "$target.sig" "$dblink.sig" 2>/dev
/null || \
614 cp "$REPO_DB_FILE.sig" "$dblink.sig"
617 msg
"$(gettext "No packages modified
, nothing to
do.
")"
622 # vim: set ts=2 sw=2 noet: