@@ -91,78 +91,135 @@ function generate_tar_ignore_list() {
9191 local list_var=" $4 "
9292 local prefix=" $5 "
9393 local includes_array=" ${includes_var} [@]"
94+ # shellcheck disable=SC2034
9495 local includes=(" ${! includes_array} " )
9596 local excludes_array=" ${excludes_var} [@]"
9697 local excludes=(" ${! excludes_array} " )
97- local dir all_dirs found_match inc
98-
99- mapfile -t all_dirs < <( find " ${directory} " -mindepth 1 -maxdepth 1 -type d | sort)
100- for dir in " ${all_dirs[@]} " ; do
101- found_match=false
102- for inc in " ${includes[@]} " ; do
103- if [[ " ./${inc} " =~ ^${dir} ]]; then
104- found_match=true
105- if [[ " ./${inc} " != " ${dir} " ]]; then
106- # check subdirectories
107- generate_tar_ignore_list " ${dir} " " ${includes_var} " " ${excludes_var} " " ${list_var} " " ${prefix} "
108- fi
109- # check if files/subdir in $dir are in excludes list
110- _generate_excludes_for_dir " ${dir} " " ${includes_var} " " ${excludes_var} " " ${list_var} "
111- break
112- fi
113- done
114- if ! ${found_match} ; then
115- _add_to_list " ${list_var} " " ${dir} "
98+
99+ # Loop through excludes and put all without path in single_excludes
100+ local single_excludes=()
101+ for item in " ${excludes[@]} " ; do
102+ if [[ ${item} != * /* ]]; then
103+ single_excludes+=(" ${item} " )
116104 fi
117105 done
106+
107+ local ignore_list=()
108+ _process_directory " ${directory} " false
109+
110+ for item in " ${ignore_list[@]} " ; do
111+ eval " ${list_var} +=(\" --tar-ignore=${item} \" )"
112+ done
118113}
119114
120- function _generate_excludes_for_dir () {
115+ function _process_directory () {
121116 local directory=" $1 "
122- local includes_var=" $2 "
123- local excludes_var=" $3 "
124- local list_var=" $4 "
125- local includes_array=" ${includes_var} [@]"
126- local includes=(" ${! includes_array} " )
127- local excludes_array=" ${excludes_var} [@]"
128- local excludes=(" ${! excludes_array} " )
129- local file all_files excluded included is_match
130-
131- mapfile -t all_files < <( find " ${directory} " -mindepth 1 -maxdepth 1 | sort)
132- is_match=false
133- for file in " ${all_files[@]} " ; do
134- for included in " ${includes[@]} " ; do
135- if [[ " ${file} " == ./${included} ]]; then
136- is_match=true
137- break
117+ local isParentIncluded=" $2 "
118+ local all_items item
119+
120+ mapfile -t all_items < <( find " ${directory} " -mindepth 1 -maxdepth 1 | sort)
121+ for item in " ${all_items[@]} " ; do
122+ debug " Checking item: ${item} "
123+ if _is_exact_match " includes" " ${item} " ; then
124+ debug " Including (full match): ${item} "
125+ if [[ -d " ${item} " ]]; then
126+ _process_directory " ${item} " true
138127 fi
139- done
140- if ${is_match} ; then
141- if [[ " ${file} " != ./ ${included} ]] && [[ -f " ${file } " ]]; then
142- _add_to_list " ${list_var } " " ${file } "
128+ elif _starts_with " includes " " ${item} " ; then
129+ debug " Including (partial match): ${item} "
130+ if [[ -d " ${item } " ]]; then
131+ _process_directory " ${item } " " ${isParentIncluded } "
143132 fi
133+ elif _is_exact_match " excludes" " ${item} " ; then
134+ debug " Excluding (full match): ${item} "
135+ _add_to_list " ${item} "
136+ elif _ends_with " single_excludes" " ${item} " || _is_wildcard_match " single_excludes" " ${item} " ; then
137+ debug " Excluding (single exclude): ${item} "
138+ _add_to_list " ${item} "
139+ elif [[ " ${isParentIncluded} " == " false" ]]; then
140+ debug " Excluding (not included): ${item} "
141+ _add_to_list " ${item} "
144142 else
145- for excluded in " ${excludes[@]} " ; do
146- if [[ " ${file} " == ./${excluded} ]]; then
147- _add_to_list " ${list_var} " " ${file} "
148- break
149- elif [[ " ./${excluded} " =~ ^${file} ]]; then
150- # check subdirectories
151- _generate_excludes_for_dir " ${file} " " ${includes_var} " " ${excludes_var} " " ${list_var} "
152- break
153- fi
154- done
143+ debug " Including (parent included): ${item} "
144+ if [[ -d " ${item} " ]]; then
145+ _process_directory " ${item} " " ${isParentIncluded} "
146+ fi
155147 fi
156148 done
157149}
158150
159151function _add_to_list() {
160- local list_var=" $1 "
161- local filename=" $2 "
162-
163- # Note: the files end up in subdirectories under `keyman` (or rather
164- # the directory name of $KEYMAN_ROOT), so we can
165- # include that when matching files and directories to ignore.
166- # shellcheck disable=SC2154
167- eval " ${list_var} +=(\" --tar-ignore=${prefix} /${filename# ./ } \" )"
152+ local item=" $1 "
153+ ignore_list+=(" ${prefix} /${item# ./ } " )
154+ }
155+
156+ # Returns true if one of the values in the $1 array equals ${file} ($2)
157+ # Example: will return true for array=(path1/path2) file=./path1/path2
158+ function _is_exact_match() {
159+ local array_var=" $1 "
160+ local file=" $2 "
161+ local array_name=" ${array_var} [@]"
162+ local haystack=(" ${! array_name} " )
163+ local item
164+ for item in " ${haystack[@]} " ; do
165+ if [[ " ./${item# ./ } " == " ${file} " ]]; then
166+ return 0
167+ fi
168+ done
169+ return 1
170+ }
171+
172+ # Returns true if one of the values in the $1 array starts with ${file} ($2)
173+ # Example: will return true for array=(path1/path2) file=./path1
174+ function _starts_with() {
175+ local array_var=" $1 "
176+ local file=" $2 "
177+ local array_name=" ${array_var} [@]"
178+ local array_values=(" ${! array_name} " )
179+ local array_item
180+ for array_item in " ${array_values[@]} " ; do
181+ if [[ " ./${array_item# ./ } " == ${file} * ]]; then
182+ return 0
183+ fi
184+ done
185+ return 1
186+ }
187+
188+ # Returns true if ${file} ($2) ends with one of the values in the $1 array
189+ # Example: will return true for array=(path2) file=./path1/path2
190+ function _ends_with() {
191+ local array_var=" $1 "
192+ local file=" $2 "
193+ local array_name=" ${array_var} [@]"
194+ local array_values=(" ${! array_name} " )
195+ local array_item
196+ for array_item in " ${array_values[@]} " ; do
197+ if [[ " ${file} " == * /${array_item# ./ } ]]; then
198+ return 0
199+ fi
200+ done
201+ return 1
202+ }
203+
204+ # Returns true if ${file} ($2) matches one of the values of the $1 array.
205+ # These values may contain wildcards.
206+ # Example: will return true for array=(*.sh) file=./path1/build.sh
207+ function _is_wildcard_match() {
208+ local array_var=" $1 "
209+ local file=" $2 "
210+ local array_name=" ${array_var} [@]"
211+ local array_values=(" ${! array_name} " )
212+ local array_item
213+ for array_item in " ${array_values[@]} " ; do
214+ array_item=${array_item/ ./ \\ .}
215+ if [[ " ${file} " =~ /${array_item/ \* / .\* } $ ]]; then
216+ return 0
217+ fi
218+ done
219+ return 1
220+ }
221+
222+ function debug() {
223+ # echo "$@"
224+ return 0
168225}
0 commit comments