I'm trying to sort a list of files based on a desired extension preference. Let's say I have a list that looks like:
- name: Declare all assets
ansible.builtin.set_fact:
asset_list:
- artifact_amd64.tar.gz
- artifact_amd64.tar.gz.sbom
- artifact_arm64.tar.gz
- artifact.deb
- artifact.appimage
- artifact_amd64
- artifact_amd64.sha256sum
Now, I'd like to get sort them in some order which could be changed by prompt, say: ['deb', 'appimage', 'tar.gz', '']
. In this case ''
means no extension, which in this case means it's a linux executable. Regarding the files that don't match the extension, I'm not intereseted in them, I'd prefer them to be removed.
Is this possible to do without writing a custom filter? I had the idea to prepend the extensions to the items with something like: map('regex_replace', '^(.*\\.)(deb|appimage|tar\\.gz)$', '\\2 \\1\\2')
but I would still need to prepend a number or something to pass it through the regular ansible sort before trying to remove it to get the final filename. The entire thing looks very complicated and hard to read in that case and I don't have a good solution for no extension.
Given the lists of the files and the extensions
asset_list:
- artifact_amd64.tar.gz
- artifact_amd64.tar.gz.sbom
- artifact_arm64.tar.gz
- artifact.deb
- artifact.appimage
- artifact_amd64
- artifact_amd64.sha256sum
asset_order: [deb, appimage, tar.gz]
Reverse the items
asset_list_reverse: "{{ asset_list | map('reverse') }}"
asset_order_reverse: "{{ asset_order | map('reverse') }}"
Use the fact that the test match:
succeeds if it finds the pattern at the beginning of the string
and create the ordered list of files with extensions
asset_list_order: |
{% filter flatten %}
[{% for ext in asset_order_reverse %}
{{ asset_list_reverse | select('match', ext) | map('reverse') }},
{% endfor %}]
{% endfilter %}
gives
asset_list_order:
- artifact.deb
- artifact.appimage
- artifact_amd64.tar.gz
- artifact_arm64.tar.gz
Create a list of executables
asset_list_exe: "{{ asset_list | reject('search', '\\.') }}"
gives
asset_list_exe:
- artifact_amd64
Add the lists
result: "{{ asset_list_order + asset_list_exe }}"
gives
result:
- artifact.deb
- artifact.appimage
- artifact_amd64.tar.gz
- artifact_arm64.tar.gz
- artifact_amd64
Notes
- hosts: localhost
vars:
asset_list:
- artifact_amd64.tar.gz
- artifact_amd64.tar.gz.sbom
- artifact_arm64.tar.gz
- artifact.deb
- artifact.appimage
- artifact_amd64
- artifact_amd64.sha256sum
asset_list_reverse: "{{ asset_list | map('reverse') }}"
asset_order: [deb, appimage, tar.gz]
asset_order_reverse: "{{ asset_order | map('reverse') }}"
asset_list_order: |
{% filter flatten %}
[{% for ext in asset_order_reverse %}
{{ asset_list_reverse | select('match', ext) | map('reverse') }},
{% endfor %}]
{% endfilter %}
asset_list_exe: "{{ asset_list | reject('search', '\\.') }}"
result: "{{ asset_list_order + asset_list_exe }}"
tasks:
- debug:
var: asset_list_order
- debug:
var: asset_list_exe
- debug:
var: result
asset_order: [deb, appimage, tar.gz, '']
remove it from the list of the reversed extensions
asset_order_reverse: "{{ asset_order | select | map('reverse') }}"
and test it when assembling the result
result: "{{ ('' in asset_order) |
ternary(asset_list_order + asset_list_exe,
asset_list_order) }}"
- hosts: localhost
vars:
asset_list:
- artifact_amd64.tar.gz
- artifact_amd64.tar.gz.sbom
- artifact_arm64.tar.gz
- artifact.deb
- artifact.appimage
- artifact_amd64
- artifact_amd64.sha256sum
asset_order: [deb, '', appimage, tar.gz]
asset_list_reverse: "{{ asset_list | map('reverse') }}"
asset_order_reverse: "{{ asset_order | map('reverse') }}"
result: |
[{% for ext in asset_order_reverse %}
{% if ext|length > 0 %}
{{ asset_list_reverse | select('match', ext) | map('reverse') }},
{% else %}
{{ asset_list | reject('search', '\.') }},
{% endif %}
{% endfor %}]
tasks:
- debug:
var: result | flatten
gives
result | flatten:
- artifact.deb
- artifact_amd64
- artifact.appimage
- artifact_amd64.tar.gz
- artifact_arm64.tar.gz