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-2012 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/>.
24 # gettext initialization
25 export TEXTDOMAIN
='pacman-scripts'
26 export TEXTDOMAINDIR
='@localedir@'
28 myver
='@PACKAGE_VERSION@'
29 confdir
='@sysconfdir@'
40 # ensure we have a sane umask set
43 m4_include
(library
/output_format.sh
)
45 # print usage instructions
48 printf -- "%s (pacman) %s\n\n" "$cmd" "$myver"
49 if [[ $cmd == "repo-add" ]] ; then
50 printf -- "$(gettext "Usage
: repo-add
[options
] <path-to-db
> <package|delta
> ...
\n")"
52 printf -- "$(gettext "\
53 repo-add will update a package database by reading a package
file.
\n\
54 Multiple packages to add can be specified on the
command line.
\n")"
56 printf -- "$(gettext "Options
:\n")"
57 printf -- "$(gettext " -d, --delta generate and add delta
for package update
\n")"
58 printf -- "$(gettext " -f, --files update database
's file list\n")"
59 elif [[ $cmd == "repo-remove" ]] ; then
60 printf -- "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n")"
62 printf -- "$(gettext "\
63 repo-remove will update a package database by removing the package name\n\
64 specified on the command line from the given repo database. Multiple\n\
65 packages to remove can be specified on the command line.\n")"
67 printf -- "$(gettext "Options:\n")"
69 printf -- "$(gettext "Please move along, there is nothing to see here.\n")"
72 printf -- "$(gettext " -q, --quiet minimize output\n")"
73 printf -- "$(gettext " -s, --sign sign database with GnuPG after update\n")"
74 printf -- "$(gettext " -k, --key <key> use the specified key to sign the database\n")"
75 printf -- "$(gettext " -v, --verify verify database's signature before update
\n")"
76 printf -- "$(gettext "\n\
77 See
%s
(8) for more details and descriptions of the available options.
\n")" $cmd
79 if [[ $cmd == "repo-add" ]] ; then
80 printf -- "$(gettext "Example
: repo-add
/path
/to
/repo.db.
tar.gz pacman-3.0
.0-1-i686.pkg.
tar.gz
\n")"
81 elif [[ $cmd == "repo-remove" ]] ; then
82 printf -- "$(gettext "Example
: repo-remove
/path
/to
/repo.db.
tar.gz kernel26
\n")"
88 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
89 printf -- "$(gettext "\
90 Copyright
(c
) 2006-2012 Pacman Development Team
<pacman-dev@archlinux.org
>\n\n\
91 This is free software
; see the
source for copying conditions.
\n\
92 There is NO WARRANTY
, to the extent permitted by law.
\n")"
95 # format a metadata entry
102 printf '%%%s%%\n' "$field"
111 for pkgentry
in "$tmpdir/tree/$pkgname"*; do
113 if [[ ${name%-*-*} = $pkgname ]]; then
121 # Get the package name from the delta filename
122 get_delta_pkgname
() {
129 # write a delta entry
130 # arg1 - path to delta file
133 pkgname
=$
(get_delta_pkgname
"$deltafile")
135 pkgentry
=$
(find_pkgentry
"$pkgname")
136 if [[ -z $pkgentry ]]; then
137 error
"$(gettext "No database entry
for package
'%s'.
")" "$pkgname"
140 deltas
=$pkgentry/deltas
141 if [[ ! -f $deltas ]]; then
142 echo -e "%DELTAS%" >"$deltas"
144 # get md5sum and compressed size of package
145 md5sum=$
(openssl dgst
-md5 "$deltafile")
147 csize
=$
(@SIZECMD@
-L "$deltafile")
149 oldfile
=$
(xdelta3 printhdr
"$deltafile" |
grep "XDELTA filename (source)" |
sed 's/.*: *//')
150 newfile
=$
(xdelta3 printhdr
"$deltafile" |
grep "XDELTA filename (output)" |
sed 's/.*: *//')
152 if grep -q "$oldfile.*$newfile" "$deltas"; then
153 sed -i.backup
"/$oldfile.*$newfile/d" "$deltas" && rm -f "$deltas.backup"
155 msg2
"$(gettext "Adding
'deltas' entry
: %s
-> %s
")" "$oldfile" "$newfile"
156 echo "${deltafile##*/} $md5sum $csize $oldfile $newfile" >> "$deltas"
159 } # end db_write_delta
161 # remove a delta entry
162 # arg1 - path to delta file
165 filename
=${deltafile##*/}
166 pkgname
=$
(get_delta_pkgname
"$deltafile")
168 pkgentry
=$
(find_pkgentry
"$pkgname")
169 if [[ -z $pkgentry ]]; then
172 deltas
=$pkgentry/deltas
173 if [[ ! -f $deltas ]]; then
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"
183 } # end db_remove_delta
186 if ! type -p gpg
>/dev
/null
; then
187 error
"$(gettext "Cannot
find the gpg binary
! Is GnuPG installed?
")"
188 exit 1 # $E_MISSING_PROGRAM
192 # sign the package database once repackaged
194 (( ! SIGN
)) && return
197 msg
"$(gettext "Signing database...
")"
200 if [[ -n $GPGKEY ]]; then
201 SIGNWITHKEY
="-u ${GPGKEY}"
203 gpg
--detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev
/null || ret
=$?
206 msg2
"$(gettext "Created signature
file %s.
")" "${dbfile##*/}.sig"
208 warning
"$(gettext "Failed to sign package database.
")"
212 # verify the existing package database signature
214 (( ! VERIFY
)) && return
217 msg
"$(gettext "Verifying database signature...
")"
219 if [[ ! -f $dbfile.sig
]]; then
220 warning
"$(gettext "No existing signature found
, skipping verification.
")"
223 gpg
--verify "$dbfile.sig" || ret
=$?
225 msg2
"$(gettext "Database signature
file verified.
")"
227 error
"$(gettext "Database signature was NOT valid
!")"
232 verify_repo_extension
() {
236 *.@
(db|files
).
tar.gz
) TAR_OPT
="z" ;;
237 *.@
(db|files
).
tar.bz2
) TAR_OPT
="j" ;;
238 *.@
(db|files
).
tar.xz
) TAR_OPT
="J" ;;
239 *.@
(db|files
).
tar.Z
) TAR_OPT
="Z" ;;
240 *.@
(db|files
).
tar) TAR_OPT
="" ;;
241 *) error
"$(gettext "'%s' does not have a valid archive extension.
")" \
246 printf '%s' "$TAR_OPT"
249 # write an entry to the pacman database
250 # arg1 - path to package
252 # blank out all variables
254 local -a _groups _licenses _replaces _depends _conflicts _provides _optdepends
255 local pkgname pkgver pkgdesc csize size url arch builddate packager \
256 md5sum sha256sum pgpsig pgpsigsize
258 # read info from the zipped package
260 while read -r line
; do
261 [[ ${line:0:1} = '#' ]] && continue
262 IFS
=' =' read -r var val
< <(printf '%s\n' "$line")
264 # normalize whitespace with an extglob
265 declare "$var=${val//+([[:space:]])/ }"
267 group
) _groups
+=("$group") ;;
268 license
) _licenses
+=("$license") ;;
269 replaces
) _replaces
+=("$replaces") ;;
270 depend
) _depends
+=("$depend") ;;
271 conflict
) _conflicts
+=("$conflict") ;;
272 provides
) _provides
+=("$provides") ;;
273 optdepend
) _optdepends
+=("$optdepend") ;;
275 done< <(bsdtar
-xOqf "$pkgfile" .PKGINFO
)
277 # ensure $pkgname and $pkgver variables were found
278 if [[ -z $pkgname ||
-z $pkgver ]]; then
279 error
"$(gettext "Invalid package
file '%s'.
")" "$pkgfile"
283 if [[ -d $tmpdir/tree
/$pkgname-$pkgver ]]; then
284 warning
"$(gettext "An entry
for '%s' already existed
")" "$pkgname-$pkgver"
287 pkgentry
=$
(find_pkgentry
"$pkgname")
288 if [[ -n $pkgentry ]]; then
289 local oldfilename
=$
(grep -A1 FILENAME
"$pkgentry/desc" |
tail -n1)
290 local oldfile
="$(dirname "$1")/$oldfilename"
295 # compute base64'd PGP signature
296 if [[ -f "$pkgfile.sig" ]]; then
297 pgpsigsize
=$
(@SIZECMD@
-L "$pkgfile.sig")
298 if (( pgpsigsize
> 16384 )); then
299 error
"$(gettext "Invalid package signature
file '%s'.
")" "$pkgfile.sig"
302 msg2
"$(gettext "Adding package signature...
")"
303 pgpsig
=$
(openssl base64
-in "$pkgfile.sig" |
tr -d '\n')
306 csize
=$
(@SIZECMD@
-L "$pkgfile")
309 msg2
"$(gettext "Computing checksums...
")"
310 md5sum=$
(openssl dgst
-md5 "$pkgfile")
312 sha256sum
=$
(openssl dgst
-sha256 "$pkgfile")
313 sha256sum
=${sha256sum##* }
315 # remove an existing entry if it exists, ignore failures
316 db_remove_entry
"$pkgname"
318 # create package directory
319 pushd "$tmpdir/tree" >/dev
/null
320 mkdir
"$pkgname-$pkgver"
321 pushd "$pkgname-$pkgver" >/dev
/null
323 # restore an eventual deltas file
324 [[ -f ..
/$pkgname.deltas
]] && mv "../$pkgname.deltas" deltas
327 msg2
"$(gettext "Creating
'%s' db entry...
")" 'desc'
329 format_entry
"FILENAME" "${1##*/}"
330 format_entry
"NAME" "$pkgname"
331 format_entry
"BASE" "$pkgbase"
332 format_entry
"VERSION" "$pkgver"
333 format_entry
"DESC" "$pkgdesc"
334 format_entry
"GROUPS" "${_groups[@]}"
335 format_entry
"CSIZE" "$csize"
336 format_entry
"ISIZE" "$size"
339 format_entry
"MD5SUM" "$md5sum"
340 format_entry
"SHA256SUM" "$sha256sum"
343 format_entry
"PGPSIG" "$pgpsig"
345 format_entry
"URL" "$url"
346 format_entry
"LICENSE" "${_licenses[@]}"
347 format_entry
"ARCH" "$arch"
348 format_entry
"BUILDDATE" "$builddate"
349 format_entry
"PACKAGER" "$packager"
350 format_entry
"REPLACES" "${_replaces[@]}"
353 # create depends entry
354 msg2
"$(gettext "Creating
'%s' db entry...
")" 'depends'
356 format_entry
"DEPENDS" "${_depends[@]}"
357 format_entry
"CONFLICTS" "${_conflicts[@]}"
358 format_entry
"PROVIDES" "${_provides[@]}"
359 format_entry
"OPTDEPENDS" "${_optdepends[@]}"
365 # create files file if wanted
366 if (( WITHFILES
)); then
367 msg2
"$(gettext "Creating
'%s' db entry...
")" 'files'
368 local files_path
="$tmpdir/tree/$pkgname-$pkgver/files"
369 echo "%FILES%" >"$files_path"
370 bsdtar
--exclude='^.*' -tf "$pkgfile" >>"$files_path"
373 # create a delta file
375 if [[ -n $oldfilename ]]; then
376 if [[ -f $oldfile ]]; then
377 delta
=$
(pkgdelta
-q "$oldfile" "$1")
378 if [[ -f $delta ]]; then
379 db_write_delta
"$delta"
382 warning
"$(gettext "Old package
file not found
: %s
")" "$oldfilename"
388 } # end db_write_entry
390 # remove existing entries from the DB
391 # arg1 - package name
395 local pkgentry
=$
(find_pkgentry
"$pkgname")
396 while [[ -n $pkgentry ]]; do
398 if [[ -f $pkgentry/deltas
]]; then
399 mv "$pkgentry/deltas" "$tmpdir/tree/$pkgname.deltas"
401 msg2
"$(gettext "Removing existing entry
'%s'...
")" \
404 pkgentry
=$
(find_pkgentry
"$pkgname")
407 } # end db_remove_entry
410 case $
(( RANDOM
% 2 )) in
411 0) printf '%s\n' "H4sIAL3qBE4CAyWLwQ3AMAgD/0xh5UPzYiFUMgjq7LUJsk7yIQNAQTAikFUDnqkr" \
412 "OQFOUm0Wd9pHCi13ONjBpVdqcWx+EdXVX4vXvGv5cgztB9+fJxZ7AAAA"
415 1) printf '%s\n' "H4sIAJVWBU4CA21RMQ7DIBDbeYWrDgQJ7rZ+IA/IB05l69alcx5fc0ASVXUk4jOO" \
416 "7yAAUWtorygwJ4hlMii0YkJKKRKGvsMsiykl1SalvrMD1gUXyXRkGZPx5OPft81K" \
417 "tNAiAjyGjYO47h1JjizPkJrCWbK/4C+uLkT7bzpGc7CT9bmOzNSW5WLSO5vexjmH" \
418 "ZL9JFFZeAa0a2+lKjL2anpYfV+0Zx9LJ+/MC8nRayuDlSNy2rfAPibOzsiWHL0jL" \
421 esac | openssl base64
-d |
gzip -d
427 # ensure the path to the DB exists
428 if [[ "$LOCKFILE" == /* ]]; then
429 repodir
=${LOCKFILE%/*}/
431 repodir
=$PWD/$LOCKFILE
432 repodir
=${repodir%/*}/
435 if [[ ! -d $repodir ]]; then
436 error
"$(gettext "%s does not exist or is not a directory.
")" "$repodir"
441 if ( set -o noclobber
; echo "$$" > "$LOCKFILE") 2> /dev
/null
; then
444 error
"$(gettext "Failed to acquire lockfile
: %s.
")" "$LOCKFILE"
445 [[ -f $LOCKFILE ]] && error
"$(gettext "Held by process
%s
")" "$(cat "$LOCKFILE")"
449 if [[ -f $REPO_DB_FILE ]]; then
450 # there are two situations we can have here- a DB with some entries,
451 # or a DB with no contents at all.
452 if ! bsdtar
-tqf "$REPO_DB_FILE" '*/desc' >/dev
/null
2>&1; then
454 if [[ -n $
(bsdtar
-tqf "$REPO_DB_FILE" '*' 2>/dev
/null
) ]]; then
455 error
"$(gettext "Repository
file '%s' is not a proper pacman database.
")" "$REPO_DB_FILE"
459 verify_signature
"$REPO_DB_FILE"
460 msg
"$(gettext "Extracting database to a temporary location...
")"
461 bsdtar
-xf "$REPO_DB_FILE" -C "$tmpdir/tree"
465 error
"$(gettext "Repository
file '%s' was not found.
")" "$REPO_DB_FILE"
469 # check if the file can be created (write permission, directory existence, etc)
470 if ! touch "$REPO_DB_FILE"; then
471 error
"$(gettext "Repository
file '%s' could not be created.
")" "$REPO_DB_FILE"
474 rm -f "$REPO_DB_FILE"
481 if [[ ! -f $1 ]]; then
482 error
"$(gettext "File
'%s' not found.
")" "$1"
486 if [[ ${1##*.} == "delta" ]]; then
488 msg
"$(gettext "Adding delta
'%s'")" "$deltafile"
489 if ! type xdelta3
&>/dev
/null
; then
490 error
"$(gettext "Cannot
find the xdelta3 binary
! Is xdelta3 installed?
")"
493 if db_write_delta
"$deltafile"; then
501 if ! bsdtar
-tqf "$pkgfile" .PKGINFO
>/dev
/null
2>&1; then
502 error
"$(gettext "'%s' is not a package
file, skipping
")" "$pkgfile"
506 msg
"$(gettext "Adding package
'%s'")" "$pkgfile"
508 db_write_entry
"$pkgfile"
512 if [[ ${1##*.} == "delta" ]]; then
514 msg
"$(gettext "Searching
for delta
'%s'...
")" "$deltafile"
515 if db_remove_delta
"$deltafile"; then
518 error
"$(gettext "Delta matching
'%s' not found.
")" "$deltafile"
524 msg
"$(gettext "Searching
for package
'%s'...
")" "$pkgname"
526 if db_remove_entry
"$pkgname"; then
527 rm -f "$tmpdir/tree/$pkgname.deltas"
530 error
"$(gettext "Package matching
'%s' not found.
")" "$pkgname"
536 # unhook all traps to avoid race conditions
537 trap '' EXIT TERM HUP QUIT INT ERR
545 local exit_code
=${1:-$?}
547 # unhook all traps to avoid race conditions
548 trap '' EXIT TERM HUP QUIT INT ERR
550 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
551 (( CLEAN_LOCK
)) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
558 # determine whether we have gettext; make it a no-op if we do not
559 if ! type gettext &>/dev
/null
; then
566 -h|
--help) usage
; exit 0;;
567 -V|
--version) version
; exit 0;;
570 # figure out what program we are
572 if [[ $cmd == "repo-elephant" ]]; then
577 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
578 error
"$(gettext "Invalid
command name
'%s' specified.
")" "$cmd"
582 tmpdir
=$
(mktemp
-d /tmp
/repo-tools.XXXXXXXXXX
) ||
(\
583 error
"$(gettext "Cannot create temp directory
for database building.
")"; \
588 for signal
in TERM HUP QUIT
; do
589 trap "trap_exit \"$(gettext "%s signal caught. Exiting...
")\" \"$signal\"" "$signal"
591 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
592 trap 'trap_exit "$(gettext "An unknown error has occurred. Exiting...")"' ERR
599 -q|
--quiet) QUIET
=1;;
600 -d|
--delta) DELTA
=1;;
601 -f|
--files) WITHFILES
=1;;
605 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
606 if [[ ! -z $GPGKEY ]]; then
607 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
609 error
"$(gettext "There is no key
in your keyring.
")"
618 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
619 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
634 REPO_DB_FILE
=${args[0]}
635 if [[ -z $REPO_DB_FILE ]]; then
640 LOCKFILE
=$REPO_DB_FILE.lck
642 verify_repo_extension
"$REPO_DB_FILE" >/dev
/null
645 for arg
in "${args[@]:1}"; do
647 repo-add
) add
"$arg" ;;
648 repo-remove
) remove
"$arg" ;;
652 # if at least one operation was a success, re-zip database
653 if (( success
)); then
654 msg
"$(gettext "Creating updated database
file '%s'")" "$REPO_DB_FILE"
656 TAR_OPT
=$
(verify_repo_extension
"$REPO_DB_FILE")
657 filename
=${REPO_DB_FILE##*/}
659 pushd "$tmpdir/tree" >/dev
/null
660 if ( shopt -s nullglob
; files
=(*); (( ${#files[*]} )) ); then
661 bsdtar
-c${TAR_OPT}f
"$tmpdir/$filename" *
663 # we have no packages remaining? zip up some emptyness
664 warning
"$(gettext "No packages remain
, creating empty database.
")"
665 bsdtar
-c${TAR_OPT}f
"$tmpdir/$filename" -T /dev
/null
669 create_signature
"$tmpdir/$filename"
671 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
672 if [[ -f $REPO_DB_FILE.sig
]]; then
673 mv -f "$REPO_DB_FILE.sig" "$REPO_DB_FILE.old.sig"
675 rm -f "$REPO_DB_FILE.old.sig"
677 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
678 [[ -f $tmpdir/$filename.sig
]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig"
679 dblink
=${REPO_DB_FILE%.tar*}
680 target
=${REPO_DB_FILE##*/}
681 rm -f "$dblink" "$dblink.sig"
682 ln -s "$target" "$dblink" 2>/dev
/null || \
683 ln "$target" "$dblink" 2>/dev
/null || \
684 cp "$REPO_DB_FILE" "$dblink"
685 if [[ -f "$REPO_DB_FILE.sig" ]]; then
686 ln -s "$target.sig" "$dblink.sig" 2>/dev
/null || \
687 ln "$target.sig" "$dblink.sig" 2>/dev
/null || \
688 cp "$REPO_DB_FILE.sig" "$dblink.sig"
691 msg
"$(gettext "No packages modified
, nothing to
do.
")"
696 # vim: set ts=2 sw=2 noet: