1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
|
#compdef opkg ipkg
# Notes:
#
# - This function has been designed with opkg in mind, but much of it should
# also work with ipkg.
#
# - Caching doesn't appear to save a HUGE amount of time given the scale of most
# opkg repos (compared to e.g. APT) and the resources available to the devices
# that use them.
#
# - _opkg_pkg_* functions can be called with --update to update their respective
# cache files without actually completing.
#
# - Lots of code redundancy here (@todo).
#
# Notable styles supported:
#
# % zstyle ':completion:*:opkg:*' use-cache <yes/no>
# Set to yes to enable caching of package names. Usually disabled by default.
#
# % zstyle ':completion:*:opkg:*' cache-path <directory>
# Set to a directory path to override the default cache-file directory.
#
# % zstyle ':completion:*:opkg:*' cache-persists <yes/no>
# Set to yes to keep cache data in memory for the remainder of the shell
# session. Most completion functions do this always, but opkg tends to be used
# on fairly resource-constrained devices, so it's disabled by default here.
#
# % zstyle ':completion:*:opkg:*' status-paths <pattern> ...
# Set to one or more paths or glob patterns to override the defaults used when
# checking cache validity. If any of the specified files has been modified
# more recently than the cache, the cache is considered invalid.
#
# % zstyle ':completion:*:opkg:*' conf-paths <pattern> ...
# Set to one or more paths or glob patterns to override the defaults used when
# searching opkg configuration data.
#
# Elevated privileges may be necessary to complete package names, etc.; consider
# setting the gain-privileges style as follows:
# zstyle ':completion:*:(ipkg|opkg)/*' gain-privileges yes
##
# Check cache validity.
__opkg_cache_policy() {
local -a tmp
# Always invalidate if it's been over a week
tmp=( $1(#qmw+1N) )
(( $#tmp )) && return 0
zstyle -a ":completion:$curcontext:" status-paths tmp
if (( $#tmp )); then
tmp=( $~tmp(#qN) )
else
tmp=(
{/opt,/usr,/var}/lib/{i,o}pkg/status(#q-.N)
{/opt,/usr,/var}/lib/{i,o}pkg/lists/packages(#q-.N)
/opt/var/opkg-lists/packages(#q-.N)
)
fi
# Always invalidate if we found no status files
(( $#tmp )) || return 0
# Invalidate if any status file is newer than the cache file
for 2 in $tmp; do
[[ $2 -nt $1 ]] && return 0
done
return 1
}
##
# Search opkg config files.
__opkg_grep_conf() {
local -aU tmp
zstyle -a ":completion:$curcontext:" conf-paths tmp
if (( $#tmp )); then
tmp=( $~tmp(#qN) )
else
tmp=(
{,/opt}/etc/{i,o}pkg*.conf(#q-.N)
{,/opt}/etc/{i,o}pkg/*.conf(#q-.N)
)
fi
(( $#tmp )) || return 1
GREP_OPTIONS= command grep -sE "$@" $tmp
}
##
# Complete architecture/priority pair.
#
# Architecture names are essentially arbitrary (up to the packager), so we can't
# really complete every possibility here — but we'll account for most of the
# popular ones.
_opkg_arch_prio() {
local -a copts=( "$@" )
local -aU tmp
[[ -prefix *: ]] && {
_message priority
return
}
# Already configured arches
tmp=( ${(f)"$( _call_program -p architectures $svc print-architecture )"} )
tmp=( ${${tmp##arch[ ]##}%% *} )
tmp+=(
# 'Meta' arches
all any noarch
# Arches supported by entware-ng
armv5soft armv7soft mipselsf x86-32 x86-64
# Arches mentioned in the optware-ng source
arm armeb fsg3be hpmv2 i686 ixp4xxbe ixp4xxle mssii nslu2 powerpc qemux86
slugosbe slugosle
# Arches mentioned in the Ångström distribution's narcissus source
a780 ac100 akita am180x-evm am3517-crane am3517-evm am37x-evm archos5
archos5it arm arm-oabi armeb armv4 armv4b armv4t armv4tb armv5 armv5-vfp
armv5e armv5e-vfp armv5eb armv5t armv5t-vfp armv5te armv5te-vfp armv5teb
armv6 armv6-vfp armv6t-vfp armv7 armv7-vfp armv7a armv7a-vfp armv7a-vfp-neon
armv7at2-vfp armv7at2-vfp-neon armv7t2-vfp at32stk1000 at91sam9263ek
atngw100 avr32 beagleboard beaglebone bug20 c6a816x-evm c6a816x_evm c7x0
cm-t35 collie da830-omapl137-evm da850-omapl138-evm davinci-dvevm dht-walnut
dm355-evm dm355-leopard dm357-evm dm365-evm dm3730-am3715-evm dm37x-evm
dm6446-evm dm6467-evm dm6467t-evm dns323 eee701 efika h2200 h3900 h4000
h5000 hawkboard htcalpine hx4700 i386 i486 i586 i686 igep0020 iwmmxt
ixp4xxbe ixp4xxle kuropro lsppchd lsppchg lspro mini2440 mini6410 mips
mv2120 n1200 n2100 neuros-osd2 nokia800 om-gta01 om-gta02 omap3-pandora
omap3-touchbook omap3evm omap4430-panda omap4430_panda omap5912osk omapzoom
omapzoom2 omapzoom36x openrd-base openrd-client overo palmt650 poodle
powerpc ppc ppc405 ppc603e qemuarm qemumips qemuppc qemux86 sheevaplug
simpad smartq5 spitz tosa ts409 tsx09 usrp-e1xx x86
)
_values -O copts -w -S : architecture ${^tmp}:priority
}
##
# Complete destination name.
_opkg_dest() {
local -a copts=( "$@" )
local -aU tmp
tmp=( ${(f)"$( __opkg_grep_conf '^\s*dest\s+\S+\s+\S+' )"} )
tmp=( ${tmp##[[:space:]]#dest[[:space:]]##} )
tmp=( ${tmp%%[[:space:]]*} )
(( $#tmp )) || {
_message destination
return
}
_values -O copts -w destination $tmp
}
##
# Complete destination-name/path pair.
_opkg_dest_path() {
local -a copts=( "$@" )
local -aU tmp
tmp=( ${(f)"$( __opkg_grep_conf '^\s*dest\s+\S+\s+\S+' )"} )
tmp=( ${tmp##[[:space:]]#dest[[:space:]]##} )
tmp=( ${tmp%%[[:space:]]*} )
(( $#tmp )) || {
_message destination:path
return
}
_values -O copts -w -S : destination ${^tmp}': :_directories'
}
##
# Complete any package name.
_opkg_pkg_all() {
local -a upd copts
zparseopts -a upd -D -E -update
copts=( "$@" )
{ (( ! $#_opkg_cache_pkg_all )) || _cache_invalid opkg-pkg-all } &&
! _retrieve_cache opkg-pkg-all && {
_opkg_cache_pkg_all=( ${(f)"$(
_call_program -p pkg-all ${svc:-opkg} list )"}
)
_opkg_cache_pkg_all=( ${(@)_opkg_cache_pkg_all##[[:space:]]*} )
_opkg_cache_pkg_all=( ${(@)_opkg_cache_pkg_all%%[[:space:]]*} )
_store_cache opkg-pkg-all _opkg_cache_pkg_all
}
(( $#upd )) && return 0
(( $#_opkg_cache_pkg_all )) || {
_message package
return
}
_values -O copts -w package $_opkg_cache_pkg_all
}
##
# Complete installed package name.
_opkg_pkg_inst() {
local -a upd copts
zparseopts -a upd -D -E -update
copts=( "$@" )
{ (( ! $#_opkg_cache_pkg_inst )) || _cache_invalid opkg-pkg-inst } &&
! _retrieve_cache opkg-pkg-inst && {
_opkg_cache_pkg_inst=( ${(f)"$(
_call_program -p pkg-inst ${svc:-opkg} list-installed
)"} )
_opkg_cache_pkg_inst=( ${(@)_opkg_cache_pkg_inst##[[:space:]]*} )
_opkg_cache_pkg_inst=( ${(@)_opkg_cache_pkg_inst%%[[:space:]]*} )
_store_cache opkg-pkg-inst _opkg_cache_pkg_inst
}
(( $#upd )) && return 0
(( $#_opkg_cache_pkg_inst )) || {
_message 'installed package'
return
}
_values -O copts -w 'installed package' $_opkg_cache_pkg_inst
}
##
# Complete new (installable) package name.
_opkg_pkg_new() {
local -a upd copts
zparseopts -a upd -D -E -update
copts=( "$@" )
{ (( ! $#_opkg_cache_pkg_new )) || _cache_invalid opkg-pkg-new } &&
! _retrieve_cache opkg-pkg-new && {
_opkg_pkg_all --update
_opkg_pkg_inst --update
_opkg_cache_pkg_new=( ${_opkg_cache_pkg_all:|_opkg_cache_pkg_inst} )
_store_cache opkg-pkg-new _opkg_cache_pkg_new
}
(( $#upd )) && return 0
(( $#_opkg_cache_pkg_new )) || {
_message 'installable package'
return
}
_values -O copts -w 'installable package' $_opkg_cache_pkg_new
}
##
# Complete upgradeable package name.
_opkg_pkg_upgr() {
local -a upd copts
zparseopts -a upd -D -E -update
copts=( "$@" )
{ (( ! $#_opkg_cache_pkg_upgr )) || _cache_invalid opkg-pkg-upgr } &&
! _retrieve_cache opkg-pkg-upgr && {
_opkg_cache_pkg_upgr=( ${(f)"$(
_call_program -p pkg-upgr ${svc:-opkg} list-upgradable
)"} )
_opkg_cache_pkg_upgr=( ${(@)_opkg_cache_pkg_upgr##[[:space:]]*} )
_opkg_cache_pkg_upgr=( ${(@)_opkg_cache_pkg_upgr%%[[:space:]]*} )
_store_cache opkg-pkg-upgr _opkg_cache_pkg_upgr
}
(( $#upd )) && return 0
(( $#_opkg_cache_pkg_upgr )) || {
_message 'upgradable package'
return
}
_values -O copts -w 'upgradable package' $_opkg_cache_pkg_upgr
}
_opkg() {
local curcontext=$curcontext ret=1 cache_policy help variant svc=$words[1]
local -a line state state_descr args tmp
local -A opt_args val_args
if
zstyle -t ":completion:*:*:$service:*" cache-persists &&
(( ! $+_opkg_cache_pkg_all ))
then
typeset -gaU _opkg_cache_pkg_all
typeset -gaU _opkg_cache_pkg_inst
typeset -gaU _opkg_cache_pkg_new
typeset -gaU _opkg_cache_pkg_upgr
else
local -aU _opkg_cache_pkg_all
local -aU _opkg_cache_pkg_inst
local -aU _opkg_cache_pkg_new
local -aU _opkg_cache_pkg_upgr
fi
zstyle -s ":completion:*:*:$service:*" cache-policy cache_policy
[[ -n $cache_policy ]] ||
zstyle ":completion:*:*:$service:*" cache-policy __opkg_cache_policy
# Options are ordered by long name. Alternative names not listed in the usage
# help are (mostly) ignored
args=(
'*--add-arch=[register architecture with priority]: :_opkg_arch_prio'
'*--add-dest=[register destination with path]: :_opkg_dest_path'
'--autoremove[remove unnecessary packages]'
'--combine[combine upgrade and install operations]'
'(-f --conf)'{-f+,--conf=}'[specify opkg config file]:config file:_files'
'(-d --dest)'{-d+,--dest=}'[specify root directory for package operations]: :_opkg_dest'
'--download-only[make no changes (download only)]'
'--force-checksum[ignore checksum mismatches]'
'--force-downgrade[allow package downgrades]'
'--force-depends[ignore failed dependencies]'
'(--force-maintainer --ignore-maintainer)--force-maintainer[overwrite local config files with upstream changes]'
'--force-overwrite[overwrite files from other packages]'
'--force-postinstall[always run postinstall scripts]'
'--force-reinstall[reinstall packages]'
# This is obnoxiously long; maybe add --force-removal-* to ignored-patterns
'--force-removal-of-dependent-packages[remove packages and all dependencies]'
'--force-remove[ignore failed prerm scripts]'
'--force-space[disable free-space checks]'
'(--force-maintainer --ignore-maintainer)--ignore-maintainer[ignore upstream changes to config files]'
'(-l --lists-dir)'{-l+,--lists-dir=}'[specify package-list directory]:list directory:_directories'
'(--noaction --test)'{--noaction,--test}'[make no changes (test only)]'
'--nodeps[do not follow dependencies]'
# Undocumented variant
'!(-o --offline --offline-root)--offline=:root directory:_directories'
'(-o --offline --offline-root)'{-o+,--offline-root=}'[specify root directory for offline package operations]:root directory:_directories'
'(-A --query-all)'{-A,--query-all}'[query all packages (not just installed)]'
'--recursive[remove packages and all their dependencies]'
'--size[show package sizes]'
'(-t --tmp-dir)'{-t+,--tmp-dir=}'[specify temp directory]:temp directory:_directories'
'(-V --verbosity)'{-V+,--verbosity=}'[specify output verbosity level]: :->verbosity-levels'
'(: -)'{-v,--version}'[display version information]'
'1: :->commands'
'*::: :->extra'
)
# There are a few different variants of opkg, but we'll concern ourselves
# mainly with OpenWRT/Entware vs (up-stream) Yocto
_pick_variant -r variant openwrt=--nocase yocto --help
if [[ $variant == openwrt ]]; then
args+=(
'--cache=[specify cache directory]:cache directory:_directories'
'--nocase[match patterns case-insensitively]'
)
else
args+=(
'*--add-exclude=[register package for exclusion]: :_opkg_pkg_all'
'--cache-dir=[specify cache directory]:cache directory:_directories'
'--host-cache-dir[do not place cache in offline root directory]'
'--no-install-recommends[do not install recommended packages]'
'--prefer-arch-to-version[prefer higher architecture priorities to higher versions]'
'--volatile-cache[use volatile download cache]'
)
fi
_arguments -s -S -C : $args && ret=0
case $state in
commands)
tmp=(
'compare-versions[compare version numbers]'
'configure[configure unpacked package]'
'depends[display dependencies of package]'
'download[download package]'
'files[display files belonging to package]'
'find[search package names and descriptions]'
'flag[flag package]'
'info[display package information]'
'install[install package]'
'list[display available packages]'
'list-changed-conffiles[display user-modified config files]'
'list-installed[display installed packages]'
'list-upgradable[display upgradable packages]'
'print-architecture[display installable architectures]'
'remove[remove package]'
'search[display packages providing file]'
'status[display package status]'
'update[update list of available packages]'
'upgrade[upgrade installed package]'
'whatconflicts[display what conflicts with package]'
'whatdepends[display what depends on package]'
'whatdependsrec[display what depends on package (recursive)]'
'whatprovides[display what provides package]'
'whatrecommends[display what recommends package]'
'whatreplaces[display what replaces package]'
'whatsuggests[display what suggests package]'
)
[[ $variant == openwrt ]] ||
tmp+=( 'clean[clean internal cache]' )
_values sub-command $tmp && ret=0
;;
verbosity-levels)
_values 'verbosity level' \
'0[show errors only]' \
'1[show normal messages (default)]' \
'2[show informational message]' \
'3[show debug messages (level 1)]' \
'4[show debug messages (level 2)]' \
&& ret=0
;;
extra)
case $line[1] in
compare-versions)
case $CURRENT in
1|3) _message 'version string' && ret=0 ;;
2)
_values operator \
'<<[earlier]' \
'<=[earlier or equal]' \
'=[equal]' \
'>=[later or equal]' \
'>>[later]' \
&& ret=0
;;
esac
;;
configure|files|list-*|status)
(( CURRENT == 1 )) && _opkg_pkg_inst && ret=0
;;
depends|what*)
if [[ -n ${opt_args[(I)-A|--query-all]} ]]; then
_opkg_pkg_all && ret=0
else
_opkg_pkg_inst && ret=0
fi
;;
download)
_opkg_pkg_all && ret=0
;;
find|info|list)
(( CURRENT == 1 )) && _opkg_pkg_all && ret=0
;;
flag)
if (( CURRENT == 1 )); then
_values flag hold noprune user ok installed unpacked && ret=0
else
_opkg_pkg_inst && ret=0
fi
;;
install)
_opkg_pkg_new && ret=0
;;
remove)
_opkg_pkg_inst && ret=0
;;
search)
(( CURRENT == 1 )) && _files && ret=0
;;
upgrade)
_opkg_pkg_upgr && ret=0
;;
esac
;;
esac
(( ret && $#state )) && _message 'no more arguments' && ret=0
return ret
}
_opkg "$@"
|