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/>.
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 repo-add will update a package database by reading a package
file.
\n\
53 Multiple packages to add can be specified on the
command line.
\n\n")"
54 printf "$(gettext "Options
:\n")"
55 printf "$(gettext " -d, --delta generate and add delta
for package update
\n")"
56 printf "$(gettext " -f, --files update database
's file list\n")"
57 elif [[ $cmd == "repo-remove" ]] ; then
58 printf "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n\n")"
60 repo-remove will update a package database by removing the package name\n\
61 specified on the command line from the given repo database. Multiple\n\
62 packages to remove can be specified on the command line.\n\n")"
63 printf "$(gettext "Options:\n")"
65 printf "$(gettext " -q, --quiet minimize output\n")"
66 printf "$(gettext " -s, --sign sign database with GnuPG after update\n")"
67 printf "$(gettext " -k, --key <key> use the specified key to sign the database\n")"
68 printf "$(gettext " -v, --verify verify database's signature before update
\n")"
69 printf "$(gettext "\n\
70 See
%s
(8) for more details and descriptions of the available options.
\n\n")" $cmd
71 if [[ $cmd == "repo-add" ]] ; then
72 echo "$(gettext "Example
: repo-add
/path
/to
/repo.db.
tar.gz pacman-3.0
.0-1-i686.pkg.
tar.gz
")"
73 elif [[ $cmd == "repo-remove" ]] ; then
74 echo "$(gettext "Example
: repo-remove
/path
/to
/repo.db.
tar.gz kernel26
")"
80 printf "%s (pacman) %s\n\n" "$cmd" "$myver"
82 Copyright
(c
) 2006-2011 Pacman Development Team
<pacman-dev@archlinux.org
>\n\n\
83 This is free software
; see the
source for copying conditions.
\n\
84 There is NO WARRANTY
, to the extent permitted by law.
\n")"
87 # format a metadata entry
94 printf '%%%s%%\n' "$field"
103 for pkgentry
in $tmpdir/$pkgname*; do
105 if [[ ${name%-*-*} = $pkgname ]]; then
113 # Get the package name from the delta filename
114 get_delta_pkgname
() {
121 # write a delta entry
122 # arg1 - path to delta file
125 pkgname
="$(get_delta_pkgname $deltafile)"
127 pkgentry
=$
(find_pkgentry
$pkgname)
128 if [[ -z $pkgentry ]]; then
129 error
"$(gettext "No database entry
for package
'%s'.
")" "$pkgname"
132 deltas
="$pkgentry/deltas"
133 if [[ ! -f $deltas ]]; then
134 echo -e "%DELTAS%" >$deltas
136 # get md5sum and compressed size of package
137 md5sum="$(openssl dgst -md5 "$deltafile")"
138 md5sum="${md5sum##* }"
139 csize
=$
(@SIZECMD@
"$deltafile")
141 oldfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (source)" |
sed 's/.*: *//')
142 newfile
=$
(xdelta3 printhdr
$deltafile |
grep "XDELTA filename (output)" |
sed 's/.*: *//')
144 if grep -q "$oldfile.*$newfile" $deltas; then
145 sed -i.backup
"/$oldfile.*$newfile/d" $deltas && rm -f $deltas.backup
147 msg2
"$(gettext "Adding
'deltas' entry
: %s
-> %s
")" "$oldfile" "$newfile"
148 echo ${deltafile##*/} $md5sum $csize $oldfile $newfile >> $deltas
151 } # end db_write_delta
153 # remove a delta entry
154 # arg1 - path to delta file
157 filename
=${deltafile##*/}
158 pkgname
="$(get_delta_pkgname $deltafile)"
160 pkgentry
=$
(find_pkgentry
$pkgname)
161 if [[ -z $pkgentry ]]; then
164 deltas
="$pkgentry/deltas"
165 if [[ ! -f $deltas ]]; then
168 if grep -q "$filename" $deltas; then
169 sed -i.backup
"/$filename/d" $deltas && rm -f $deltas.backup
170 msg2
"$(gettext "Removing existing entry
'%s'...
")" "$filename"
175 } # end db_remove_delta
178 if ! type -p gpg
>/dev
/null
; then
179 error
"$(gettext "Cannot
find the gpg binary
! Is gnupg installed?
")"
180 exit 1 # $E_MISSING_PROGRAM
184 # sign the package database once repackaged
186 (( ! SIGN
)) && return
189 msg
"$(gettext "Signing database...
")"
192 if [[ -n $GPGKEY ]]; then
193 SIGNWITHKEY
="-u ${GPGKEY}"
195 gpg
--detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev
/null || ret
=$?
198 msg2
"$(gettext "Created signature
file %s.
")" "$dbfile.sig"
200 warning
"$(gettext "Failed to sign package database.
")"
204 # verify the existing package database signature
206 (( ! VERIFY
)) && return
209 msg
"$(gettext "Verifying database signature...
")"
211 if [[ ! -f $dbfile.sig
]]; then
212 warning
"$(gettext "No existing signature found
, skipping verification.
")"
215 gpg
--verify "$dbfile.sig" || ret
=$?
217 msg2
"$(gettext "Database signature
file verified.
")"
219 error
"$(gettext "Database signature was NOT valid
!")"
224 verify_repo_extension
() {
228 *.@
(db|files
).
tar.gz
) TAR_OPT
="z" ;;
229 *.@
(db|files
).
tar.bz2
) TAR_OPT
="j" ;;
230 *.@
(db|files
).
tar.xz
) TAR_OPT
="J" ;;
231 *.@
(db|files
).
tar) TAR_OPT
="" ;;
232 *) error
"$(gettext "'%s' does not have a valid archive extension.
")" \
237 printf '%s' "$TAR_OPT"
240 # write an entry to the pacman database
241 # arg1 - path to package
243 # blank out all variables
245 local -a _groups _licenses _replaces _depends _conflicts _provides _optdepends
246 local pkgname pkgver pkgdesc csize size url arch builddate packager \
247 md5sum sha256sum pgpsig
249 # read info from the zipped package
251 while read -r line
; do
252 [[ ${line:0:1} = '#' ]] && continue
253 IFS
=' =' read -r var val
< <(printf '%s\n' "$line")
255 # normalize whitespace with an extglob
256 declare "$var=${val//+([[:space:]])/ }"
258 group
) _groups
+=("$group") ;;
259 license
) _licenses
+=("$license") ;;
260 replaces
) _replaces
+=("$replaces") ;;
261 depend
) _depends
+=("$depend") ;;
262 conflict
) _conflicts
+=("$conflict") ;;
263 provides
) _provides
+=("$provides") ;;
264 optdepend
) _optdepends
+=("$optdepend") ;;
266 done< <(bsdtar
-xOqf "$pkgfile" .PKGINFO
)
268 csize
=$
(@SIZECMD@
"$pkgfile")
271 msg2
"$(gettext "Computing checksums...
")"
272 md5sum="$(openssl dgst -md5 "$pkgfile")"
273 md5sum="${md5sum##* }"
274 sha256sum
="$(openssl dgst -sha256 "$pkgfile")"
275 sha256sum
="${sha256sum##* }"
277 # compute base64'd PGP signature
278 if [[ -f "$pkgfile.sig" ]]; then
279 pgpsig
=$
(openssl base64
-in "$pkgfile.sig" |
tr -d '\n')
282 # ensure $pkgname and $pkgver variables were found
283 if [[ -z $pkgname ||
-z $pkgver ]]; then
284 error
"$(gettext "Invalid package
file '%s'.
")" "$pkgfile"
288 pushd "$tmpdir" >/dev
/null
289 if [[ -d $pkgname-$pkgver ]]; then
290 warning
"$(gettext "An entry
for '%s' already existed
")" "$pkgname-$pkgver"
293 pkgentry
=$
(find_pkgentry
$pkgname)
294 if [[ -n $pkgentry ]]; then
295 local oldfilename
=$
(grep -A1 FILENAME
$pkgentry/desc |
tail -n1)
296 local oldfile
="$(dirname $1)/$oldfilename"
301 # remove an existing entry if it exists, ignore failures
302 db_remove_entry
"$pkgname"
304 # create package directory
305 mkdir
"$pkgname-$pkgver"
306 pushd "$pkgname-$pkgver" >/dev
/null
308 # restore an eventual deltas file
309 [[ -f ..
/$pkgname.deltas
]] && mv "../$pkgname.deltas" deltas
312 msg2
"$(gettext "Creating
'%s' db entry...
")" 'desc'
314 format_entry
"FILENAME" "${1##*/}"
315 format_entry
"NAME" "$pkgname"
316 format_entry
"BASE" "$pkgbase"
317 format_entry
"VERSION" "$pkgver"
318 format_entry
"DESC" "$pkgdesc"
319 format_entry
"GROUPS" "${_groups[@]}"
320 format_entry
"CSIZE" "$csize"
321 format_entry
"ISIZE" "$size"
324 format_entry
"MD5SUM" "$md5sum"
325 format_entry
"SHA256SUM" "$sha256sum"
328 format_entry
"PGPSIG" "$pgpsig"
330 format_entry
"URL" "$url"
331 format_entry
"LICENSE" "${_licenses[@]}"
332 format_entry
"ARCH" "$arch"
333 format_entry
"BUILDDATE" "$builddate"
334 format_entry
"PACKAGER" "$packager"
335 format_entry
"REPLACES" "${_replaces[@]}"
338 # create depends entry
339 msg2
"$(gettext "Creating
'%s' db entry...
")" 'depends'
341 format_entry
"DEPENDS" "${_depends[@]}"
342 format_entry
"CONFLICTS" "${_conflicts[@]}"
343 format_entry
"PROVIDES" "${_provides[@]}"
344 format_entry
"OPTDEPENDS" "${_optdepends[@]}"
350 # create files file if wanted
351 if (( WITHFILES
)); then
352 msg2
"$(gettext "Creating
'%s' db entry...
")" 'files'
353 local files_path
="$tmpdir/$pkgname-$pkgver/files"
354 echo "%FILES%" >$files_path
355 bsdtar
--exclude='^.*' -tf "$pkgfile" >>$files_path
358 # create a delta file
360 if [[ -n $oldfilename ]]; then
361 if [[ -f $oldfile ]]; then
362 delta
=$
(pkgdelta
-q $oldfile $1)
363 if [[ -f $delta ]]; then
364 db_write_delta
$delta
367 warning
"$(gettext "Old package
file not found
: %s
")" "$oldfilename"
373 } # end db_write_entry
375 # remove existing entries from the DB
376 # arg1 - package name
380 local pkgentry
=$
(find_pkgentry
$pkgname)
381 while [[ -n $pkgentry ]]; do
383 if [[ -f $pkgentry/deltas
]]; then
384 mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas"
386 msg2
"$(gettext "Removing existing entry
'%s'...
")" \
389 pkgentry
=$
(find_pkgentry
$pkgname)
392 } # end db_remove_entry
395 case $
(( RANDOM
% 2 )) in
396 0) printf '%s\n' "H4sIAL3qBE4CAyWLwQ3AMAgD/0xh5UPzYiFUMgjq7LUJsk7yIQNAQTAikFUDnqkr" \
397 "OQFOUm0Wd9pHCi13ONjBpVdqcWx+EdXVX4vXvGv5cgztB9+fJxZ7AAAA"
400 1) printf '%s\n' "H4sIAJVWBU4CA21RMQ7DIBDbeYWrDgQJ7rZ+IA/IB05l69alcx5fc0ASVXUk4jOO" \
401 "7yAAUWtorygwJ4hlMii0YkJKKRKGvsMsiykl1SalvrMD1gUXyXRkGZPx5OPft81K" \
402 "tNAiAjyGjYO47h1JjizPkJrCWbK/4C+uLkT7bzpGc7CT9bmOzNSW5WLSO5vexjmH" \
403 "ZL9JFFZeAa0a2+lKjL2anpYfV+0Zx9LJ+/MC8nRayuDlSNy2rfAPibOzsiWHL0jL" \
406 esac | openssl base64
-d |
gzip -d
412 # ensure the path to the DB exists
413 if [[ "$LOCKFILE" == /* ]]; then
414 repodir
=${LOCKFILE%/*}/
416 repodir
=$PWD/$LOCKFILE
417 repodir
=${repodir%/*}/
420 if [[ ! -d "$repodir" ]]; then
421 error
"$(gettext "%s does not exist or is not a directory.
")" "$repodir"
426 if ( set -o noclobber
; echo "$$" > "$LOCKFILE") 2> /dev
/null
; then
429 error
"$(gettext "Failed to acquire lockfile
: %s.
")" "$LOCKFILE"
430 [[ -f $LOCKFILE ]] && error
"$(gettext "Held by process
%s
")" "$(cat $LOCKFILE)"
434 if [[ -f $REPO_DB_FILE ]]; then
435 # there are two situations we can have here- a DB with some entries,
436 # or a DB with no contents at all.
437 if ! bsdtar
-tqf "$REPO_DB_FILE" '*/desc' >/dev
/null
2>&1; then
439 if [[ -n $
(bsdtar
-tqf "$REPO_DB_FILE" '*' 2>/dev
/null
) ]]; then
440 error
"$(gettext "Repository
file '%s' is not a proper pacman database.
")" "$REPO_DB_FILE"
444 verify_signature
"$REPO_DB_FILE"
445 msg
"$(gettext "Extracting database to a temporary location...
")"
446 bsdtar
-xf "$REPO_DB_FILE" -C "$tmpdir"
450 error
"$(gettext "Repository
file '%s' was not found.
")" "$REPO_DB_FILE"
454 # check if the file can be created (write permission, directory existence, etc)
455 if ! touch "$REPO_DB_FILE"; then
456 error
"$(gettext "Repository
file '%s' could not be created.
")" "$REPO_DB_FILE"
459 rm -f "$REPO_DB_FILE"
466 if [[ ! -f $1 ]]; then
467 error
"$(gettext "File
'%s' not found.
")" "$1"
471 if [[ ${1##*.} == "delta" ]]; then
473 msg
"$(gettext "Adding delta
'%s'")" "$deltafile"
474 if ! type xdelta3
&>/dev
/null
; then
475 error
"$(gettext "Cannot
find the xdelta3 binary
! Is xdelta3 installed?
")"
478 if db_write_delta
"$deltafile"; then
486 if ! bsdtar
-tqf "$pkgfile" .PKGINFO
>/dev
/null
2>&1; then
487 error
"$(gettext "'%s' is not a package
file, skipping
")" "$pkgfile"
491 msg
"$(gettext "Adding package
'%s'")" "$pkgfile"
493 db_write_entry
"$pkgfile"
497 if [[ ${1##*.} == "delta" ]]; then
499 msg
"$(gettext "Searching
for delta
'%s'...
")" "$deltafile"
500 if db_remove_delta
"$deltafile"; then
503 error
"$(gettext "Delta matching
'%s' not found.
")" "$deltafile"
509 msg
"$(gettext "Searching
for package
'%s'...
")" "$pkgname"
511 if db_remove_entry
"$pkgname"; then
512 rm -f "$tmpdir/$pkgname.deltas"
515 error
"$(gettext "Package matching
'%s' not found.
")" "$pkgname"
529 [[ -d $tmpdir ]] && rm -rf "$tmpdir"
530 (( CLEAN_LOCK
)) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE"
537 # determine whether we have gettext; make it a no-op if we do not
538 if ! type gettext &>/dev
/null
; then
545 -h|
--help) usage
; exit 0;;
546 -V|
--version) version
; exit 0;;
549 # figure out what program we are
551 if [[ $cmd == "repo-elephant" ]]; then
556 if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then
557 error
"$(gettext "Invalid
command name
'%s' specified.
")" "$cmd"
561 tmpdir
=$
(mktemp
-d /tmp
/repo-tools.XXXXXXXXXX
) ||
(\
562 error
"$(gettext "Cannot create temp directory
for database building.
")"; \
566 trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
567 trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
568 trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR
575 -q|
--quiet) QUIET
=1;;
576 -d|
--delta) DELTA
=1;;
577 -f|
--files) WITHFILES
=1;;
581 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
582 if [[ ! -z $GPGKEY ]]; then
583 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
585 error
"$(gettext "There is no key
in your keyring.
")"
594 if ! gpg
--list-key ${GPGKEY} &>/dev
/null
; then
595 error
"$(gettext "The key
${GPGKEY} does not exist
in your keyring.
")"
611 REPO_DB_FILE
=${args[0]}
612 LOCKFILE
=$REPO_DB_FILE.lck
614 verify_repo_extension
"$REPO_DB_FILE" >/dev
/null
617 for arg
in "${args[@]:1}"; do
619 repo-add
) add
"$arg" ;;
620 repo-remove
) remove
"$arg" ;;
624 # if at least one operation was a success, re-zip database
625 if (( success
)); then
626 msg
"$(gettext "Creating updated database
file '%s'")" "$REPO_DB_FILE"
628 TAR_OPT
=$
(verify_repo_extension
"$REPO_DB_FILE")
629 filename
=${REPO_DB_FILE##*/}
631 pushd "$tmpdir" >/dev
/null
632 # strip the './' off filenames; this also allows us to tar an empty dir
633 bsdtar
-s %^.
/%% -c${TAR_OPT}f
"$REPO_DB_FILE" .
/
634 create_signature
"$filename"
637 [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old"
638 [[ -f $REPO_DB_FILE.sig
]] && rm -f "$REPO_DB_FILE.sig"
639 [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE"
640 [[ -f $tmpdir/$filename.sig
]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig"
641 dblink
="${REPO_DB_FILE%.tar*}"
642 target
=${REPO_DB_FILE##*/}
644 ln -s "$target" "$dblink" 2>/dev
/null || \
645 ln "$target" "$dblink" 2>/dev
/null || \
646 cp "$REPO_DB_FILE" "$dblink"
647 if [[ -f "$target.sig" ]]; then
649 ln -s "$target.sig" "$dblink.sig" 2>/dev
/null || \
650 ln "$target.sig" "$dblink.sig" 2>/dev
/null || \
651 cp "$REPO_DB_FILE.sig" "$dblink.sig"
654 msg
"$(gettext "No packages modified
, nothing to
do.
")"
659 # vim: set ts=2 sw=2 noet: