# vim: set syntax=yaml ts=2 sw=2 sts=2 et :
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2016  Marek Marczykowski-Górecki
#                                 <marmarek@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#


# Merge two structures in depth. This function assumes both have the same
# structure, which is ok for top files (mapping of mapping of lists).
{% macro deep_merge(first, second) %}

# first handle mapping (check only the first argument - see assumption above)
{% if first is mapping %}
# for each key in the first mapping, check if matching value is present in the
# second one
{%- for key, value in first.items() %}
'{{ key }}':
  {% if not key in second %}
# if not - simply output the first value
  {{ value|yaml }}
  {% else %}
# otherwise, merge them recursively
  {{ deep_merge(value, second[key])|indent(2) }}
  {% endif %}
{% endfor %}
# then output values present only in the second mapping
{%- for key, value in second.items() if key not in first %}
'{{ key }}':
  {{ value|yaml }}
{% endfor %}

# if it is't mapping, check if it is sequence (list)
{% elif first is sequence %}

# output all entries from the first list
{%- for item in first %}
- {{ item|yaml }}
{% endfor %}

# then entries from the second one, skipping duplicates
{%- for item in second if item not in first %}
- {{ item|yaml }}
{% endfor %}

# not mapping, not sequence - don't know how to merge them - output the first
# value, ignore the second one
{% else %}
{{ first }}
{% endif %}
{% endmacro %}

# merge_tops macro iterate over provided list of tops. Each entry should be a
# path to proper salt top file
{% macro merge_tops(tops) %}
# output buffer - start with empty mapping. Use single element array, because
# of variable's scope issue (value set inside loop isn't visible outside, or
# even in another loop iteration).
{% set merged_top = [{}] %}

# for each top:
{% for top in tops %}
# 1. Load it to single_top variable.
{%- load_yaml as single_top -%}
{% include top %}
{%- endload -%}
# 2. Merge with output buffer (merged_top), saving result in new_merged_top
{%- load_yaml as new_merged_top -%}
{{ deep_merge(merged_top[0], single_top) }}
{%- endload -%}
# Some debugging
{#
Merging: {{ merged_top[0] }}
with: {{ single_top }}
result: {{ new_merged_top }} 
#}

# 3. Override output buffer with new_merged_top
{%- set _ = merged_top.pop() -%}
{%- set _ = merged_top.append(new_merged_top) -%}

{%- endfor -%}

# After processing the last one, return output.
{{ merged_top[0]|yaml }}

{% endmacro %}

