Browse code

find - set proper default based on use_regex (#73961)

When using "use_regex: yes" and setting an excludes: without
specifying a pattern: the existing code passes the file-glob '*' to
the regex matcher. This results in an internal invalid-regex
exception being thrown.

This maintains the old semantics of a default match-all for pattern:
but switches the default to '.*' when use_regex is specified.

The code made sense as-is before excludes: was added (2.5). In that
case, it made no sense to set use_regex but *not* set a pattern.
However, with excludes: it now makes sense to only want to exclude a
given regex but not specify a specific matching pattern.

Closes: #50067

* moved change to new location
added changelog

* Update lib/ansible/modules/find.py


Co-authored-by: Ian Wienand <iwienand@redhat.com>

Brian Coca authored on 2021/03/20 02:18:31
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+bugfixes:
1
+  - find module, fix default pattern when use_regex is true.
... ...
@@ -29,7 +29,7 @@ options:
29 29
               first letter of any of those words (e.g., "1w").
30 30
         type: str
31 31
     patterns:
32
-        default: '*'
32
+        default: []
33 33
         description:
34 34
             - One or more (shell or regex) patterns, which type is controlled by C(use_regex) option.
35 35
             - The patterns restrict the list of files to be returned to those whose basenames match at
... ...
@@ -41,6 +41,7 @@ options:
41 41
             - This parameter expects a list, which can be either comma separated or YAML. If any of the
42 42
               patterns contain a comma, make sure to put them in a list to avoid splitting the patterns
43 43
               in undesirable ways.
44
+            - Defaults to '*' when C(use_regex=False), or '.*' when C(use_regex=True).
44 45
         type: list
45 46
         aliases: [ pattern ]
46 47
         elements: str
... ...
@@ -375,7 +376,7 @@ def main():
375 375
     module = AnsibleModule(
376 376
         argument_spec=dict(
377 377
             paths=dict(type='list', required=True, aliases=['name', 'path'], elements='str'),
378
-            patterns=dict(type='list', default=['*'], aliases=['pattern'], elements='str'),
378
+            patterns=dict(type='list', default=[], aliases=['pattern'], elements='str'),
379 379
             excludes=dict(type='list', aliases=['exclude'], elements='str'),
380 380
             contains=dict(type='str'),
381 381
             read_whole_file=dict(type='bool', default=False),
... ...
@@ -395,6 +396,16 @@ def main():
395 395
 
396 396
     params = module.params
397 397
 
398
+    # Set the default match pattern to either a match-all glob or
399
+    # regex depending on use_regex being set.  This makes sure if you
400
+    # set excludes: without a pattern pfilter gets something it can
401
+    # handle.
402
+    if not params['patterns']:
403
+        if params['use_regex']:
404
+            params['patterns'] = ['.*']
405
+        else:
406
+            params['patterns'] = ['*']
407
+
398 408
     filelist = []
399 409
 
400 410
     if params['age'] is None:
... ...
@@ -251,3 +251,24 @@
251 251
           # dir contents are considered until the depth exceeds the requested depth
252 252
           # there are 8 files/directories in the requested depth and 4 that exceed it by 1
253 253
           - files_with_depth.examined == 12
254
+- name: exclude with regex
255
+  find:
256
+    paths: "{{ output_dir_test }}"
257
+    recurse: yes
258
+    use_regex: true
259
+    exclude: .*\.ogg
260
+  register: find_test3
261
+# Note that currently sane ways of doing this with map() or
262
+# selectattr() aren't available in centos6 era jinja2 ...
263
+- set_fact:
264
+    find_test3_list: >-
265
+      [ {% for f in find_test3.files %}
266
+      {{ f.path }}
267
+      {% if not loop.last %},{% endif %}
268
+      {% endfor %}
269
+      ]
270
+- debug: var=find_test3_list
271
+- name: assert we skipped the ogg file
272
+  assert:
273
+    that:
274
+      - '"{{ output_dir_test }}/e/f/g/h/8.ogg" not in find_test3_list'