index.subr revision 252980
1151497Sruif [ ! "$_PACKAGES_INDEX_SUBR" ]; then _PACKAGES_INDEX_SUBR=1
2114402Sru#
3114402Sru# Copyright (c) 2013 Devin Teske
4114402Sru# All rights reserved.
5114402Sru#
6114402Sru# Redistribution and use in source and binary forms, with or without
7114402Sru# modification, are permitted provided that the following conditions
8114402Sru# are met:
9114402Sru# 1. Redistributions of source code must retain the above copyright
10114402Sru#    notice, this list of conditions and the following disclaimer.
11114402Sru# 2. Redistributions in binary form must reproduce the above copyright
12114402Sru#    notice, this list of conditions and the following disclaimer in the
13114402Sru#    documentation and/or other materials provided with the distribution.
14114402Sru#
15114402Sru# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16114402Sru# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17114402Sru# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18114402Sru# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19114402Sru# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20114402Sru# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21114402Sru# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22114402Sru# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23114402Sru# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24114402Sru# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25151497Sru# SUCH DAMAGE.
26151497Sru#
27114402Sru# $FreeBSD: head/usr.sbin/bsdconfig/share/packages/index.subr 252980 2013-07-07 18:21:30Z dteske $
28114402Sru#
29114402Sru############################################################ INCLUDES
30114402Sru
31151497SruBSDCFG_SHARE="/usr/share/bsdconfig"
32114402Sru. $BSDCFG_SHARE/common.subr || exit 1
33114402Sruf_dprintf "%s: loading includes..." packages/index.subr
34114402Sruf_include $BSDCFG_SHARE/device.subr
35114402Sruf_include $BSDCFG_SHARE/media/common.subr
36114402Sruf_include $BSDCFG_SHARE/strings.subr
37114402Sru
38114402SruBSDCFG_LIBE="/usr/libexec/bsdconfig"
39114402Sruf_include_lang $BSDCFG_LIBE/include/messages.subr
40114402Sru
41114402Sru############################################################ GLOBALS
42114402Sru
43114402SruPACKAGE_INDEX=
44114402Sru_INDEX_INITTED=
45114402Sru
46114402Sru############################################################ FUNCTIONS
47114402Sru
48114402Sru# f_index_initialize $path [$var_to_set]
49114402Sru#
50114402Sru# Read and initialize the global index. $path is to be relative to the chosen
51114402Sru# media (not necessarily the filesystem; e.g. FTP) -- this is usually going to
52114402Sru# be `packages/INDEX'. Returns success unless media cannot be initialized for
53114402Sru# any reason (e.g. user cancels media selection dialog) or an error occurs. The
54114402Sru# index is sorted before being loaded into $var_to_set.
55114402Sru#
56114402Sru# NOTE: The index is processed with f_index_read() [below] after being loaded.
57114402Sru#
58114402Sruf_index_initialize()
59114402Sru{
60114402Sru	local __path="$1" __var_to_set="${2:-PACKAGE_INDEX}"
61114402Sru
62114402Sru	[ "$_INDEX_INITTED" ] && return $SUCCESS
63114402Sru	[ "$__path" ] || return $FAILURE
64114402Sru
65114402Sru	# Got any media?
66114402Sru	f_media_verify || return $FAILURE
67114402Sru
68114402Sru	# Does it move when you kick it?
69114402Sru	f_device_init media || return $FAILURE
70114402Sru
71114402Sru	f_show_info "$msg_attempting_to_fetch_file_from_selected_media" \
72114402Sru	            "$__path"
73114402Sru	eval "$__var_to_set"='$( f_device_get media "$__path" )'
74114402Sru	if [ $? -ne $SUCCESS ]; then
75114402Sru		f_show_msg "$msg_unable_to_get_file_from_selected_media" \
76114402Sru		           "$__path"
77114402Sru		f_device_shutdown media
78114402Sru		return $FAILURE
79114402Sru	fi
80114402Sru	eval "$__var_to_set"='$( debug= f_getvar "$__var_to_set" | sort )'
81114402Sru
82114402Sru	f_show_info "$msg_located_index_now_reading_package_data_from_it"
83151497Sru	if ! f_index_read "$__var_to_set"; then
84114402Sru		f_show_msg "$msg_io_or_format_error_on_index_file" "$__path"
85114402Sru		return $FAILURE
86114402Sru	fi
87114402Sru
88151497Sru	_INDEX_INITTED=1
89114402Sru	return $SUCCESS
90114402Sru}
91114402Sru
92114402Sru# f_index_read [$var_to_get]
93114402Sru#
94114402Sru# Process the INDEX file (contents contained in $var_to_get) and...
95114402Sru#
96114402Sru# 1. create a list ($CATEGORY_MENU_LIST) of categories with package counts
97114402Sru# 2. For convenience, create $_npkgs holding the total number of all packages
98114402Sru# 3. extract associative categories for each package into $_categories_$varpkg
99114402Sru# 4. extract runtime dependencies for each package into $_rundeps_$varpkg
100114402Sru# 5. extract a [sorted] list of categories into $PACKAGE_CATEGORIES
101114402Sru# 6. create $_npkgs_$varcat holding the total number of packages in category
102114402Sru#
103151497Sru# NOTE: $varpkg is the product of f_str2varname $package varpkg
104114402Sru# NOTE: $package is the name as it appears in the INDEX (no archive suffix)
105114402Sru# NOTE: We only show categories for which there are at least one package.
106114402Sru# NOTE: $varcat is the product of f_str2varname $category varcat
107114402Sru#
108114402Sruf_index_read()
109114402Sru{
110114402Sru	local var_to_get="${1:-PACKAGE_INDEX}"
111114402Sru
112114402Sru	# Export variables required by awk(1) below
113114402Sru	export msg_no_description_provided
114114402Sru	export msg_all msg_all_desc
115114402Sru	export VALID_VARNAME_CHARS
116114402Sru	export msg_packages
117114402Sru
118114402Sru	eval "$( debug= f_getvar "$var_to_get" | awk -F'|' '
119114402Sru	function asorti(src, dest)
120114402Sru	{
121114402Sru		# Copy src indices to dest and calculate array length
122114402Sru		nitems = 0; for (i in src) dest[++nitems] = i
123151497Sru
124114402Sru		# Sort the array of indices (dest) using insertion sort method
125114402Sru		for (i = 1; i <= nitems; k = i++)
126114402Sru		{
127114402Sru			idx = dest[i]
128114402Sru			while ((k > 0) && (dest[k] > idx))
129114402Sru			{
130114402Sru				dest[k+1] = dest[k]
131114402Sru				k--
132114402Sru			}
133114402Sru			dest[k+1] = idx
134114402Sru		}
135114402Sru
136114402Sru		return nitems
137114402Sru	}
138114402Sru	function print_category(category, npkgs, desc)
139114402Sru	{
140114402Sru		cat = category
141114402Sru		# Accent the category if the first page has been
142114402Sru		# cached (also acting as a visitation indicator)
143114402Sru		if ( ENVIRON["_index_page_" varcat "_1"] )
144114402Sru			cat = cat "*"
145114402Sru		printf "'\''%s'\'' '\''%s " packages "'\'' '\''%s'\''\n",
146114402Sru		       cat, npkgs, desc
147151497Sru	}
148114402Sru	BEGIN {
149114402Sru		valid_chars = ENVIRON["VALID_VARNAME_CHARS"]
150151497Sru		default_desc = ENVIRON["msg_no_description_provided"]
151151497Sru		packages = ENVIRON["msg_packages"]
152151497Sru		tpkgs = 0
153151497Sru		prefix = ""
154114402Sru	}
155114402Sru	{
156114402Sru		tpkgs++
157114402Sru		varpkg = $1
158114402Sru		gsub("[^" valid_chars "]", "_", varpkg)
159114402Sru		print "_categories_" varpkg "=\"" $7 "\""
160114402Sru		split($7, pkg_categories, /[[:space:]]+/)
161114402Sru		for (pkg_category in pkg_categories)
162114402Sru			categories[pkg_categories[pkg_category]]++
163114402Sru		print "_rundeps_" varpkg "=\"" $9 "\""
164114402Sru	}
165114402Sru	END {
166114402Sru		print "_npkgs=" tpkgs # For convenience, total package count
167114402Sru
168114402Sru		n = asorti(categories, categories_sorted)
169114402Sru
170114402Sru		# Produce package counts for each category
171114402Sru		for (i = 1; i <= n; i++)
172114402Sru		{
173114402Sru			cat = varcat = categories_sorted[i]
174114402Sru			npkgs = categories[cat]
175114402Sru			gsub("[^" valid_chars "]", "_", varcat)
176114402Sru			print "_npkgs_" varcat "=\"" npkgs "\""
177151497Sru		}
178114402Sru
179114402Sru		# Create menu list and generate list of categories at same time
180114402Sru		print "CATEGORY_MENU_LIST=\""
181114402Sru		print_category(ENVIRON["msg_all"], tpkgs,
182114402Sru		               ENVIRON["msg_all_desc"])
183114402Sru		category_list = ""
184114402Sru		for (i = 1; i <= n; i++)
185114402Sru		{
186114402Sru			cat = varcat = categories_sorted[i]
187114402Sru			npkgs = categories[cat]
188114402Sru			cur_prefix = tolower(substr(cat, 1, 1))
189151497Sru			if ( prefix != cur_prefix )
190151497Sru				prefix = cur_prefix
191151497Sru			else
192151497Sru				cat = " " cat
193114402Sru			gsub("[^" valid_chars "]", "_", varcat)
194114402Sru			desc = ENVIRON["_category_" varcat]
195114402Sru			if ( ! desc ) desc = default_desc
196114402Sru			print_category(cat, npkgs, desc)
197114402Sru			category_list = category_list " " cat
198114402Sru		}
199114402Sru		print "\""
200114402Sru
201114402Sru		# Produce the list of categories (calculated in above block)
202114402Sru		sub(/^ /, "", category_list)
203114402Sru		print "PACKAGE_CATEGORIES=\"" category_list "\""
204114402Sru
205114402Sru	}' )" # End-Quote
206114402Sru}
207114402Sru
208114402Sru# f_index_extract_pages $var_to_get $var_basename $pagesize [$category]
209114402Sru#
210114402Sru# Extracts the package INDEX ($PACKAGE_INDEX by default if/when $var_to_get is
211114402Sru# NULL; but should not be missing) into a series of sequential variables
212114402Sru# corresponding to "pages" containing up to $pagesize packages. The package
213114402Sru# INDEX data must be contained in the variable $var_to_get. The extracted pages
214114402Sru# are stored in variables ${var_basename}_# -- where "#" is a the page number.
215114402Sru# If $category is set, only packages for that category are extracted.
216114402Sru# Otherwise, if $category is "All", missing, or NULL, all packages are
217114402Sru# extracted and no filtering is done.
218114402Sru#
219114402Sruf_index_extract_pages()
220114402Sru{
221114402Sru	local var_to_get="${1:-PACKAGE_INDEX}" var_basename="$2" pagesize="$3"
222114402Sru	local category="$4" # Optional
223114402Sru
224114402Sru	eval "$(
225114402Sru		debug= f_getvar "$var_to_get" | awk -F'|' \
226114402Sru			-v cat="$category" \
227114402Sru			-v pagesize="$pagesize" \
228114402Sru			-v var_basename="$var_basename" \
229114402Sru			-v i18n_all="$msg_all" '
230114402Sru		BEGIN { n = page = 0 }
231114402Sru		/'\''/{ gsub(/'\''/, "'\''\\'\'\''") }
232114402Sru		{
233114402Sru			if ( cat !~ "(^$|^" i18n_all "$)" && $7 !~ \
234114402Sru			     "(^|[[:space:]])" cat "([[:space:]]|$)" ) next
235114402Sru			starting_new_page = (n++ == (pagesize * page))
236114402Sru			if ( starting_new_page )
237114402Sru				printf "%s%s", ( n > 1 ? "'\''\n" : "" ),
238114402Sru				       var_basename "_" ++page "='\''"
239114402Sru			printf "%s%s", ( starting_new_page ? "" : "\n" ), $0
240114402Sru		}
241114402Sru		END { if ( n > 0 ) print "'\''" }'
242114402Sru	)"
243114402Sru}
244114402Sru
245114402Sru# f_index_search $var_to_get $name [$var_to_set]
246114402Sru#
247114402Sru# Search the package INDEX ($PACKAGE_INDEX by default if/when $var_to_get is
248114402Sru# NULL; but should not be missing) for $name, returning the first match.
249114402Sru# Matches are strict (not regular expressions) and must match the beginning
250114402Sru# portion of the package name to be considered a match. If $var_to_set is
251114402Sru# missing or NULL, output is sent to standard output. If a match is found,
252114402Sru# returns success; otherwise failure.
253114402Sru#
254114402Sruf_index_search()
255114402Sru{
256114402Sru	local __var_to_get="${1:-PACKAGE_INDEX}" __pkg_basename="$2"
257114402Sru	local __var_to_set="$3"
258114402Sru
259114402Sru	f_dprintf "f_index_search: Searching package data (in %s) for %s" \
260114402Sru	          "$__var_to_get" "$__pkg_basename"
261114402Sru
262114402Sru	local __pkg=
263114402Sru	__pkg=$( debug= f_getvar "$__var_to_get" |
264114402Sru			awk -F'|' -v basename="$__pkg_basename" '
265114402Sru		BEGIN { n = length(basename) }
266114402Sru		substr($1, 0, n) == basename { print $1; exit }
267114402Sru	' )
268114402Sru	if [ ! "$__pkg" ]; then
269114402Sru		f_dprintf "f_index_search: No packages matching %s found" \
270114402Sru		          "$__pkg_basename"
271114402Sru		return $FAILURE
272114402Sru	fi
273114402Sru
274114402Sru	f_dprintf "f_index_search: Found package %s" "$__pkg"
275114402Sru	if [ "$__var_to_set" ]; then
276114402Sru		setvar "$__var_to_set" "$__pkg"
277114402Sru	else
278114402Sru		echo "$__pkg"
279114402Sru	fi
280114402Sru	return $SUCCESS
281114402Sru}
282114402Sru
283114402Sru############################################################ MAIN
284114402Sru
285114402Sruf_dprintf "%s: Successfully loaded." packages/index.subr
286114402Sru
287114402Srufi # ! $_PACKAGES_INDEX_SUBR
288114402Sru