From 42c74efbac61e47789626ea90930e35fa2d0c15f Mon Sep 17 00:00:00 2001 From: Erik Flodin Date: Sun, 10 Jan 2021 22:38:42 +0100 Subject: [PATCH] Add support for multiple local classes A local class is set with: $ yadm config local.class cls1 More classes can be added with: $ yadm config --add local.class cls2 $ yadm config --add local.class cls3 Any of cls1, cls2 and cls3 can be used in an alternate condition. For templates, the existing variable yadm.class/YADM_CLASS is set to the last class (i.e. cls3) to remain compatible with how it works today and with what the following command gives: $ yadm config local.class For the default template processor there is no explicit yadm.classes variable. Instead a yadm.class condition will check against all classes. For the other processors, a new template variable YADM_CLASSES will be set to all classes separated by newline. For jinja2 templates a class can be checked with: {%- if "cls" in YADM_CLASSES.split("\n") %} For esh templates the logic is a bit more complex, but it is possible to do. Fixes #185. --- pylintrc | 2 +- test/test_alt.py | 4 ++- test/test_unit_score_file.py | 1 + test/test_unit_set_local_alt_values.py | 5 +++- test/test_unit_template_default.py | 6 ++++ test/test_unit_template_esh.py | 7 +++++ test/test_unit_template_j2.py | 6 ++++ test/utils.py | 5 ++-- yadm | 40 ++++++++++++++++++++++---- 9 files changed, 66 insertions(+), 10 deletions(-) diff --git a/pylintrc b/pylintrc index 1034736..ba41b74 100644 --- a/pylintrc +++ b/pylintrc @@ -8,7 +8,7 @@ max-attributes=8 max-statements=65 [SIMILARITIES] -min-similarity-lines=7 +min-similarity-lines=8 [MESSAGES CONTROL] disable=redefined-outer-name diff --git a/test/test_alt.py b/test/test_alt.py index 45c9055..1559f10 100644 --- a/test/test_alt.py +++ b/test/test_alt.py @@ -97,7 +97,9 @@ def test_alt_conditions( # set the class tst_class = 'testclass' - utils.set_local(paths, 'class', tst_class) + utils.set_local(paths, 'class', tst_class + ".before") + utils.set_local(paths, 'class', tst_class, add=True) + utils.set_local(paths, 'class', tst_class + ".after", add=True) suffix = string.Template(suffix).substitute( tst_arch=tst_arch, diff --git a/test/test_unit_score_file.py b/test/test_unit_score_file.py index f7b821a..2c9d9c9 100644 --- a/test/test_unit_score_file.py +++ b/test/test_unit_score_file.py @@ -201,6 +201,7 @@ def test_score_values( YADM_TEST=1 source {yadm} score=0 local_class={local_class} + local_classes=({local_class}) local_arch={local_arch} local_system={local_system} local_distro={local_distro} diff --git a/test/test_unit_set_local_alt_values.py b/test/test_unit_set_local_alt_values.py index e49d055..2bb7802 100644 --- a/test/test_unit_set_local_alt_values.py +++ b/test/test_unit_set_local_alt_values.py @@ -34,7 +34,10 @@ def test_set_local_alt_values( echo "user='$local_user'" """ - if override: + if override == 'class': + utils.set_local(paths, override, 'first') + utils.set_local(paths, override, 'override', add=True) + elif override: utils.set_local(paths, override, 'override') run = runner(command=['bash'], inp=script) diff --git a/test/test_unit_template_default.py b/test/test_unit_template_default.py index f503a39..5afe1d7 100644 --- a/test/test_unit_template_default.py +++ b/test/test_unit_template_default.py @@ -5,6 +5,7 @@ FILE_MODE = 0o754 # these values are also testing the handling of bizarre characters LOCAL_CLASS = "default_Test+@-!^Class" +LOCAL_CLASS2 = "default_Test+@-|^2nd_Class withSpace" LOCAL_ARCH = "default_Test+@-!^Arch" LOCAL_SYSTEM = "default_Test+@-!^System" LOCAL_HOST = "default_Test+@-!^Host" @@ -32,6 +33,9 @@ Multiple lines {{% else %}} Should not be included... {{% endif %}} +{{% if yadm.class == "{LOCAL_CLASS2}" %}} +Included section for second class +{{% endif %}} {{% if yadm.class == "wrongclass2" %}} wrong class 2 {{% endif %}} @@ -93,6 +97,7 @@ default distro = >{LOCAL_DISTRO}< Included section from else Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated) Multiple lines +Included section for second class Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated) Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated) Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again) @@ -150,6 +155,7 @@ def test_template_default(runner, yadm, tmpdir): YADM_TEST=1 source {yadm} set_awk local_class="{LOCAL_CLASS}" + local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}") local_arch="{LOCAL_ARCH}" local_system="{LOCAL_SYSTEM}" local_host="{LOCAL_HOST}" diff --git a/test/test_unit_template_esh.py b/test/test_unit_template_esh.py index ee3888a..2672380 100644 --- a/test/test_unit_template_esh.py +++ b/test/test_unit_template_esh.py @@ -4,6 +4,7 @@ import os FILE_MODE = 0o754 LOCAL_CLASS = "esh_Test+@-!^Class" +LOCAL_CLASS2 = "esh_Test+@-|^2nd_Class withSpace" LOCAL_ARCH = "esh_Test+@-!^Arch" LOCAL_SYSTEM = "esh_Test+@-!^System" LOCAL_HOST = "esh_Test+@-!^Host" @@ -26,6 +27,10 @@ Included section for class = <%=$YADM_CLASS%> (<%=$YADM_CLASS%> repeated) <% if [ "$YADM_CLASS" = "wrongclass2" ]; then -%> wrong class 2 <% fi -%> +<% echo "$YADM_CLASSES" | while IFS='' read cls; do + if [ "$cls" = "{LOCAL_CLASS2}" ]; then -%> +Included section for second class +<% fi; done -%> <% if [ "$YADM_ARCH" = "wrongarch1" ]; then -%> wrong arch 1 <% fi -%> @@ -82,6 +87,7 @@ esh host = >{LOCAL_HOST}< esh user = >{LOCAL_USER}< esh distro = >{LOCAL_DISTRO}< Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated) +Included section for second class Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated) Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated) Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again) @@ -108,6 +114,7 @@ def test_template_esh(runner, yadm, tmpdir): script = f""" YADM_TEST=1 source {yadm} local_class="{LOCAL_CLASS}" + local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}") local_arch="{LOCAL_ARCH}" local_system="{LOCAL_SYSTEM}" local_host="{LOCAL_HOST}" diff --git a/test/test_unit_template_j2.py b/test/test_unit_template_j2.py index 6e4c5b0..e2f48d9 100644 --- a/test/test_unit_template_j2.py +++ b/test/test_unit_template_j2.py @@ -5,6 +5,7 @@ import pytest FILE_MODE = 0o754 LOCAL_CLASS = "j2_Test+@-!^Class" +LOCAL_CLASS2 = "j2_Test+@-|^2nd_Class withSpace" LOCAL_ARCH = "j2_Test+@-!^Arch" LOCAL_SYSTEM = "j2_Test+@-!^System" LOCAL_HOST = "j2_Test+@-!^Host" @@ -27,6 +28,9 @@ Included section for class = {{{{YADM_CLASS}}}} ({{{{YADM_CLASS}}}} repeated) {{%- if YADM_CLASS == "wrongclass2" %}} wrong class 2 {{%- endif %}} +{{%- if "{LOCAL_CLASS2}" in YADM_CLASSES.split("\\n") %}} +Included section for second class +{{%- endif %}} {{%- if YADM_ARCH == "wrongarch1" %}} wrong arch 1 {{%- endif %}} @@ -83,6 +87,7 @@ j2 host = >{LOCAL_HOST}< j2 user = >{LOCAL_USER}< j2 distro = >{LOCAL_DISTRO}< Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated) +Included section for second class Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated) Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated) Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again) @@ -110,6 +115,7 @@ def test_template_j2(runner, yadm, tmpdir, processor): script = f""" YADM_TEST=1 source {yadm} local_class="{LOCAL_CLASS}" + local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}") local_arch="{LOCAL_ARCH}" local_system="{LOCAL_SYSTEM}" local_host="{LOCAL_HOST}" diff --git a/test/utils.py b/test/utils.py index 2291fc5..67a9e53 100644 --- a/test/utils.py +++ b/test/utils.py @@ -21,11 +21,12 @@ INCLUDE_DIRS = ['', 'test alt'] INCLUDE_CONTENT = '8780846c02e34c930d0afd127906668f' -def set_local(paths, variable, value): +def set_local(paths, variable, value, add=False): """Set local override""" + add = "--add" if add else "" os.system( f'GIT_DIR={str(paths.repo)} ' - f'git config --local "local.{variable}" "{value}"' + f'git config --local {add} "local.{variable}" "{value}"' ) diff --git a/yadm b/yadm index bce89ff..167f921 100755 --- a/yadm +++ b/yadm @@ -211,7 +211,7 @@ function score_file() { return fi elif [[ "$label" =~ ^(c|class)$ ]]; then - if [ "$value" = "$local_class" ]; then + if in_list "$value" "${local_classes[@]}"; then score=$((score + 8)) else score=0 @@ -418,12 +418,22 @@ function replace_vars() { gsub(("{{" blank "*yadm\\." label blank "*}}"), c[label]) } } +function condition_helper(label, value) { + gsub(/[\\.^$(){}\[\]|*+?]/, "\\\\&", value) + return sprintf("yadm\\.%s" blank "*==" blank "*\"%s\"", label, value) +} function conditions() { pattern = ifs blank "+(" for (label in c) { - value = c[label] - gsub(/[\\.^$(){}\[\]|*+?]/, "\\\\&", value) - pattern = sprintf("%syadm\\.%s" blank "*==" blank "*\"%s\"|", pattern, label, value) + if (label != "class") { + value = c[label] + pattern = sprintf("%s%s|", pattern, condition_helper(label, value)); + } + } + split(classes, cls_array, "\n") + for (idx in cls_array) { + value = cls_array[idx] + pattern = sprintf("%s%s|", pattern, condition_helper("class", value)); } sub(/\|$/, ")" blank "*%}$", pattern) return pattern @@ -439,6 +449,7 @@ EOF -v distro="$local_distro" \ -v source="$input" \ -v source_dir="$(dirname "$input")" \ + -v classes="$(join_string $'\n' "${local_classes[@]}")" \ "$awk_pgm" \ "$input" > "$temp_file" || rm -f "$temp_file" @@ -457,6 +468,7 @@ function template_j2cli() { YADM_USER="$local_user" \ YADM_DISTRO="$local_distro" \ YADM_SOURCE="$input" \ + YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \ "$J2CLI_PROGRAM" "$input" -o "$temp_file" move_file "$input" "$output" "$temp_file" @@ -474,6 +486,7 @@ function template_envtpl() { YADM_USER="$local_user" \ YADM_DISTRO="$local_distro" \ YADM_SOURCE="$input" \ + YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \ "$ENVTPL_PROGRAM" --keep-template "$input" -o "$temp_file" move_file "$input" "$output" "$temp_file" @@ -484,6 +497,7 @@ function template_esh() { output="$2" temp_file="${output}.$$.$RANDOM" + YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \ "$ESH_PROGRAM" -o "$temp_file" "$input" \ YADM_CLASS="$local_class" \ YADM_ARCH="$local_arch" \ @@ -521,6 +535,7 @@ function alt() { # gather values for processing alternates local local_class + local -a local_classes local local_arch local local_system local local_host @@ -620,7 +635,12 @@ function remove_stale_links() { function set_local_alt_values() { - local_class="$(config local.class)" + local -a all_classes + all_classes=$(config --get-all local.class) + while IFS='' read -r local_class; do + local_classes+=("$local_class") + done <<< "$all_classes" + local_class="${local_classes[-1]:-}" local_arch="$(config local.arch)" if [ -z "$local_arch" ] ; then @@ -2032,6 +2052,16 @@ function join_string { printf "%s" "${*:2}" } +function in_list { + local element="$1" + shift + + for e in "$@"; do + [[ "$e" = "$element" ]] && return 0 + done + return 1 +} + function get_mode { local filename="$1" local mode