Ansible:独特的最短路径

Ansible: Unique Shortest Paths

上下文

我有一个要删除的文件和目录列表。
这是从 rsync 标准输出中以单词“删除”开头的行获得的。

rsync stdout_lines: [
    "building file list ... done",
    "*deleting   Lab02/Ex2/Doc1.txt",
    "*deleting   Lab02/Ex2/",
    "*deleting   Lab02/Ex1/Doc1.txt",
    "*deleting   Lab02/Ex1/",
    "*deleting   Lab02/",
    ".d..t...... ./",
    "*deleting   Lab01/Ex2/Doc1.txt",
    "*deleting   Lab01/Ex2/",
    "*deleting   Lab01/Ex1/Doc2.txt",
    "*deleting   Lab01/Ex1/Doc1.txt",
    ".d..t...... Lab01/",
    ".d..t...... Lab01/Ex1/",
    "sent 350 bytes  received 191 bytes  360.67 bytes/sec",
    "total size is 614  speedup is 1.13 (DRY RUN)"
]  

格式化使用:

'{{ sync_return.stdout_lines | select("regex", "^[*]deleting") | map("regex_replace", "^[*]deleting", "") | map("regex_replace", " ", "") | list }}'

此列表格式的原始示例如下:

formatted list: [
    "Lab02/Ex2/Doc1.txt",
    "Lab02/Ex2/",
    "Lab02/Ex1/Doc1.txt",
    "Lab02/Ex1/",
    "Lab02/",
    "Lab01/Ex2/Doc1.txt",
    "Lab01/Ex2/",
    "Lab01/Ex1/Doc2.txt",
    "Lab01/Ex1/Doc1.txt"
]

为了加快删除过程(通过减少要迭代的元素数量)- 我将列表分成 2 个子列表:

上面示例的子列表是...

directories to delete: [
    "Lab02/Ex2/",
    "Lab02/Ex1/",
    "Lab02/",
    "Lab01/Ex2/"
]

files to delete: [
    "Lab01/Ex1/Doc2.txt",
    "Lab01/Ex1/Doc1.txt"
]

问题

虽然当前的解决方案有效,但它并不是最好的。梦想是有一个解决方案,其中“要删除的目录”列表仅包含可能的最高级别目录。即因为我们知道目录“Lab02/”正在被删除,“要删除的目录”将不包含“Lab02/Ex2/”或“Lab02/Ex1/”。
我相信我的目标有点类似于 os.path.commonprefix python 函数,但是必须针对列表中的各种文件路径完成。

我对 Ansible 比较陌生,所以如果 guidance/help 有任何关于此事的意见,我们将不胜感激。

我不会问你为什么要实现它,我会把它当作练习。

想法是,您可以按字母顺序对目录进行排序,然后在循环路径时,删除以上一行开头的所有路径。

你可以这样写你的过滤器(放在filter_plugins目录):

def common_paths(paths=[]):
    sorted_paths = sorted(paths)
    pfx = sorted_paths[0]
    for path in sorted_paths[1:]:
      if re.compile("^%s.*" % pfx).match(path):
         sorted_paths.remove(path)
      else:
         pfx = path
    return sorted_paths

class FilterModule(object):
    def filters(self):
        return { 'common_paths': common_paths }

然后:

 - name: Filter
   set_fact:
       bar: "{{ foo | common_paths }}"

本地测试:

---
 
- hosts: localhost
  tasks:
    - name: Test data
      set_fact: 
        foo:
          - 'Lab01/'
          - 'Lab01/Ex5/'
          - 'Ex2/foo3/'
          - 'Ex2/foo2/'
          - 'Ex2/'
          - 'Lab03/Ex5/e/'
          - 'Lab02/y/z/Lab01/1/'
          - 'Lab02/y/z/Lab01/3/'
          - 'Lab01/Ex5/Lab02/'
          - 'Lab03/Ex5/d/1'

    - name: Filter
      set_fact: 
        bar: "{{ foo | common_paths }}"

输出:

$ ansible-playbook common_paths.yml  -vvv
ansible-playbook 2.10.4

PLAYBOOK: common_paths.yml *********************************************************************************
1 plays in common_paths.yml

PLAY [localhost] *********************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [localhost]

TASK [Test data] *********************************************************************************    task path: /home/guido/Development/git/ansible-local/common_paths.yml:5
ok: [localhost] => {
    "ansible_facts": {
        "foo": [
            "Lab01/",
            "Lab01/Ex5/",
            "Ex2/foo3/",
            "Ex2/foo2/",
            "Ex2/",
            "Lab03/Ex5/e/",
            "Lab02/y/z/Lab01/1/",
            "Lab02/y/z/Lab01/3/",
            "Lab01/Ex5/Lab02/",
            "Lab03/Ex5/d/1/"
        ]
    },
    "changed": false
}

TASK [Filter] *********************************************************************************
task path: /home/guido/Development/git/ansible-local/common_paths.yml:19
ok: [localhost] => {
    "ansible_facts": {
        "bar": [
            "Ex2/",
            "Lab01/",
            "Lab02/y/z/Lab01/1/",
            "Lab02/y/z/Lab01/3/",
            "Lab03/Ex5/d/1/",
            "Lab03/Ex5/e/"
        ]
    },
    "changed": false
}

PLAY RECAP *********************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0