Gentoo Archives: gentoo-commits

From: James Le Cuirot <chewi@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: eclass/
Date: Thu, 27 Apr 2017 21:41:59
Message-Id: 1493329281.fde70c442fd394bfd912d266b8442d86b76dea1a.chewi@gentoo
1 commit: fde70c442fd394bfd912d266b8442d86b76dea1a
2 Author: James Le Cuirot <chewi <AT> gentoo <DOT> org>
3 AuthorDate: Sun Apr 16 09:36:07 2017 +0000
4 Commit: James Le Cuirot <chewi <AT> gentoo <DOT> org>
5 CommitDate: Thu Apr 27 21:41:21 2017 +0000
6 URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=fde70c44
7
8 cdrom.eclass: Detect case-insensitively and handle special characters
9
10 This eclass previously used "find -iname" but it only checked the file
11 case-insensitively and not the directories. There is "find -ipath" but
12 this does not intelligently skip non-matching paths, making it
13 slow. Globbing is used here instead.
14
15 The : character has always been used to delimit paths given to
16 cdrom_get_cds, which makes sense because : generally isn't allowed on
17 CDs, while whitespace is. Despite that, whitespace was not being
18 handled properly and neither were wildcard characters. Now all special
19 characters are automatically escaped.
20
21 eclass/cdrom.eclass | 58 ++++++++++++++++++++++++++++++++++++++++-------------
22 1 file changed, 44 insertions(+), 14 deletions(-)
23
24 diff --git a/eclass/cdrom.eclass b/eclass/cdrom.eclass
25 index 41488d2446c..a51270d33e9 100644
26 --- a/eclass/cdrom.eclass
27 +++ b/eclass/cdrom.eclass
28 @@ -79,12 +79,13 @@ cdrom_get_cds() {
29 export CDROM_ROOT=${CD_ROOT_1:-${CD_ROOT}}
30 einfo "Found CD #${CDROM_CURRENT_CD} root at ${CDROM_ROOT}"
31 export CDROM_SET=-1
32 - for f in ${CDROM_CHECK_1//:/ } ; do
33 + local IFS=:
34 + for f in ${CDROM_CHECK_1} ; do
35 + unset IFS
36 ((++CDROM_SET))
37 - [[ -e ${CDROM_ROOT}/${f} ]] && break
38 + export CDROM_MATCH=$(_cdrom_glob_match "${CDROM_ROOT}" "${f}")
39 + [[ -n ${CDROM_MATCH} ]] && return
40 done
41 - export CDROM_MATCH=${f}
42 - return
43 fi
44
45 # User didn't help us out so lets make sure they know they can
46 @@ -181,28 +182,24 @@ _cdrom_locate_file_on_cd() {
47 local showedmsg=0 showjolietmsg=0
48
49 while [[ -z ${CDROM_ROOT} ]] ; do
50 - local i=0
51 - local -a cdset=(${*//:/ })
52 + local i=0 cdset
53 + IFS=: read -r -a cdset -d "" <<< "${*}"
54 +
55 if [[ -n ${CDROM_SET} ]] ; then
56 - cdset=(${cdset[${CDROM_SET}]})
57 + cdset=( "${cdset[${CDROM_SET}]}" )
58 fi
59
60 while [[ -n ${cdset[${i}]} ]] ; do
61 - local dir=$(dirname ${cdset[${i}]})
62 - local file=$(basename ${cdset[${i}]})
63 -
64 local point= node= fs= foo=
65 while read point node fs foo ; do
66 [[ " cd9660 iso9660 udf " != *" ${fs} "* ]] && \
67 ! [[ ${fs} == "subfs" && ",${opts}," == *",fs=cdfss,"* ]] \
68 && continue
69 point=${point//\040/ }
70 - [[ ! -d ${point}/${dir} ]] && continue
71 - [[ -z $(find "${point}/${dir}" -maxdepth 1 -iname "${file}") ]] \
72 - && continue
73 + export CDROM_MATCH=$(_cdrom_glob_match "${point}" "${cdset[${i}]}")
74 + [[ -z ${CDROM_MATCH} ]] && continue
75 export CDROM_ROOT=${point}
76 export CDROM_SET=${i}
77 - export CDROM_MATCH=${cdset[${i}]}
78 return
79 done <<< "$(get_mounts)"
80
81 @@ -243,4 +240,37 @@ _cdrom_locate_file_on_cd() {
82 done
83 }
84
85 +# @FUNCTION: _cdrom_glob_match
86 +# @USAGE: <root directory> <path>
87 +# @INTERNAL
88 +# @DESCRIPTION:
89 +# Locates the given path ($2) within the given root directory ($1)
90 +# case-insensitively and returns the first actual matching path. This
91 +# eclass previously used "find -iname" but it only checked the file
92 +# case-insensitively and not the directories. There is "find -ipath"
93 +# but this does not intelligently skip non-matching paths, making it
94 +# slow. Case-insensitive matching can only be applied to patterns so
95 +# extended globbing is used to turn regular strings into patterns. All
96 +# special characters are escaped so don't worry about breaking this.
97 +_cdrom_glob_match() {
98 + # The following line turns this:
99 + # foo*foo/bar bar/baz/file.zip
100 + #
101 + # Into this:
102 + # ?(foo\*foo)/?(bar\ bar)/?(baz)/?(file\.zip)
103 + #
104 + # This turns every path component into an escaped extended glob
105 + # pattern to allow case-insensitive matching. Globs cannot span
106 + # directories so each component becomes an individual pattern.
107 + local p=\?\($(sed -e 's:[^A-Za-z0-9/]:\\\0:g' -e 's:/:)/?(:g' <<< "$2" || die)\)
108 + (
109 + cd "$1" 2>/dev/null || return
110 + shopt -s extglob nocaseglob nullglob || die
111 + # The first person to make this work without an eval wins a
112 + # cookie. It breaks without it when spaces are present.
113 + eval "ARRAY=( ${p} )"
114 + echo ${ARRAY[0]}
115 + )
116 +}
117 +
118 fi