Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH 1/1] Update softwareupdate completion for macOS 13
Thank you for the update.
I've never used softwareupdate, but it seems _softwareupdate needs
some more updates.
(1) The output format of 'softwareupdate --list' has changed and
the current _softwareupdate_ignored_update_name() doesn't work.
(this is rather hard to test since 'softwareupdate --list' gives
nothing if your Mac is fully updated)
(2) --download requires one or more update names.
The patch below (against the current master) also includes:
(3) use '+ (option_group)' for mutually exclusive options.
(4) complete version numbers of available macOS full installers.
(5) some simplifications (do not call _arguments multiple times, etc.)
diff --git a/Completion/Darwin/Command/_softwareupdate b/Completion/Darwin/Command/_softwareupdate
index 6054fd768..e4bdede86 100644
--- a/Completion/Darwin/Command/_softwareupdate
+++ b/Completion/Darwin/Command/_softwareupdate
@@ -1,75 +1,105 @@
#compdef softwareupdate
-_softwareupdate_ignored_update_name() {
- if [[ -z "$_softwareupdate_ignored_updates" ]]; then
- local res="$(_call_program pkgs softwareupdate --ignored)"
- _softwareupdate_ignored_updates=("${(Qs/, /)${${res#Current ignored updates: \(}%\)}}")
- fi
- if (( ${#_softwareupdate_ignored_updates} > 0 )); then
- _wanted pkgs expl "ignored package" compadd -a _softwareupdate_ignored_updates && return 0
- fi
- return 1
+# rebuild cache for available updates everyday (ad hoc)
+_softwareupdate_caching_policy() {
+ local -a newer=( "$1"(Nmd-1) )
+ return $#newer
}
-_softwareupdate_update_name() {
- local name line
- if [[ -z "$_softwareupdate_updates" ]]; then
+# completes available updates (with description)
+
+_softwareupdate_update_names () {
+ local name line update_policy ret=1
+ local cache_id=softwareupdate-updates
+ zstyle -s ":completion:${curcontext}:" cache-policy update_policy
+ if [[ -z "$update_policy" ]]; then
+ zstyle ":completion:${curcontext}:" cache-policy \
+ _softwareupdate_caching_policy
+ fi
+ if { [[ ! -v _softwareupdate_updates ]] || _cache_invalid $cache_id } &&
+ ! _retrieve_cache $cache_id; then
+ # Output format of 'softwareupdate --list' seems to be not stable,
+ # but at least on macOS 12 and 13 it contains the following two lines
+ # for each update:
+ #* Label: update name (may contain spaces)
+ # Title: description of the update (single TAB before Title:)
+ # softwareupdate(1) manpage says the '*' before the Label: is replaced
+ # by '-' for non-recommended updates (but I've never seen it).
_softwareupdate_updates=()
- for line in ${(f)"$(_call_program pkgs softwareupdate --list)"}; do
- if [[ $line == ' '* ]]; then
- name="${line# ? }"
- elif [[ -n "$name" ]]; then
- _softwareupdate_updates+=("$name:${line# }")
- name=""
+ for line in ${(f)"$(_call_program updates softwareupdate --list)"}; do
+ if [[ $line = [-\*]\ Label:\ (#b)(*) ]]; then
+ # add '*' or '-' in front of the name; this will be removed later
+ name=$line[1]$match[1]
+ elif [[ -n $name && $line = $'\t'Title:\ (#b)(*) ]]; then
+ _softwareupdate_updates+=( $name:$match[1] )
+ name=
fi
done
+ _store_cache $cache_id _softwareupdate_updates
fi
- if (( ${#_softwareupdate_updates} > 0 )); then
- _describe -t pkgs "update name" _softwareupdate_updates && return 0
- fi
- return 1
+ # recommended and non-recommended updates
+ local rec=( ${${_softwareupdate_updates:#-*}#\*} )
+ local non=( ${${(M)_softwareupdate_updates:#-*}#-} )
+ _describe -t updates "update" rec && ret=0
+ _describe -t non-recommended-updates "non-recommended update" non && ret=0
+ return ret
}
-_softwareupdate() {
- local context state line expl
- typeset -A opt_args
+# completes versions of available macOS full installer (with description)
- _arguments -R \
- '(-h --help -l --list)-q[quiet mode]' \
- {-l,--list}'[list all available updates]:*:' \
- {-d,--download}'[download to directory set in InternetConfig]:*:' \
- {-i,--install}'[install (requires root)]:*: :->install' \
- '--ignored[show or manage ignored updates list (per-user)]:*:: :->ignored' \
- '--schedule[scheduler preferences (per-user)]:automatic checking:(on off)' \
- {-h,--help}'[print command usage]:*:' && return 0
+_softwareupdate_installer_versions () {
+ local versions=()
+ for line in ${(f)"$(_call_program installer-versions
+ softwareupdate --list-full-installers)"}; do
+ if [[ $line = \*\ Title:\ *\ Version:\ (#b)([0-9.]##)* ]]; then
+ versions+=( ${match[1]}:${line#*Title: } )
+ fi
+ done
+ _describe -t insteller-versions "version" versions
+}
- case "$state" in
- install)
- _arguments \
- '(* -a --all)'{-a,--all}'[all available active updates]' \
- '(* -r --req)'{-r,--req}'[all required active updates]' \
- '*:update name:_softwareupdate_update_name' && return 0
- ;;
- ignored)
- local -a ignored_subcmd
- ignored_subcmd=(add remove)
+# main completion script
+local -a specs
- if (( CURRENT == 1 )); then
- _describe -t commands "subcommand" ignored_subcmd && return 0
- fi
- case $words[1] in
- add)
- _softwareupdate_update_name && return 0
- ;;
- remove)
- _arguments \
- '(* -a --all)'{-a,--all}'[all available active updates]' \
- '*:update name:_softwareupdate_ignored_update_name' && return 0
- ;;
- esac
- ;;
- esac
- return 1
-}
+if (( ${words[(I)(-i|--install)]} == 0 )); then
+ specs=(
+ '--no-scan[do not scan when listing or installing updates]'
+ '--product-types[limit a scan to a particular product type only]:list of product types'
+ '--products[a comma separated list of product keys to operate on]:list of product keys'
+ '--force[force an operation to complete]'
+ '--agree-to-license[agree to the software license agreement without user interaction]'
+ '--verbose[enable verbose output]'
+ '(* -)'{-h,--help}'[print command usage]:*:'
+
+ + '(operation)'
+
+ {-l,--list}'[list all available updates]'
+ {-d,--download}'[download but not install specified updates]:*: : _softwareupdate_update_names'
+ {-i,--install}'[download and install specified updates]'
+ '--list-full-installers[list the available macOS installers]'
+ '(* -)--fetch-full-installer[install the latest recommended macOS installer]: :(--full-installer-version): : _softwareupdate_installer_versions'
+ '--install-rosetta[install Rosetta 2 (Apple Silicon only)]'
+ '--schedule[returns the per-machine automatic check preference]'
+ '--background[trigger a background scan and update operation]'
+ '--dump-state[log the internal state of the SU daemon to /var/log/install.log]'
+ '--evaluate-products[evaluate a list of product keys specified by the --products option]'
+ '--history[show the install history]'
+ )
+else # if -i/--install is already on the command line
+ specs=(
+ !{-i,--install}
+ '(-R --restart)'{-R,--restart}'[automatically restart if required to complete installation]'
+ '--stdinpass[password to authenticate as an owner (Apple Silicon only)]'
+ '--user[local username to authenticate as an owner (Apple Silicon only)]'
+ '*: : _softwareupdate_update_names'
+
+ + '(select-updates)'
+
+ '(*)'{-a,--all}'[all updates that are applicable to your system]'
+ '(*)'{-r,--recommended}'[all updates that are recommended for your system]'
+ '(*)--os-only[only macOS updates]'
+ '(*)--safari-only[only Safari updates]'
+ )
+fi
-_softwareupdate "$@"
+_arguments -s : $specs
Messages sorted by:
Reverse Date,
Date,
Thread,
Author