Browse Source

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.
Erik Flodin 4 years ago
parent
commit
42c74efbac

+ 1 - 1
pylintrc

@@ -8,7 +8,7 @@ max-attributes=8
 max-statements=65
 max-statements=65
 
 
 [SIMILARITIES]
 [SIMILARITIES]
-min-similarity-lines=7
+min-similarity-lines=8
 
 
 [MESSAGES CONTROL]
 [MESSAGES CONTROL]
 disable=redefined-outer-name
 disable=redefined-outer-name

+ 3 - 1
test/test_alt.py

@@ -97,7 +97,9 @@ def test_alt_conditions(
 
 
     # set the class
     # set the class
     tst_class = 'testclass'
     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(
     suffix = string.Template(suffix).substitute(
         tst_arch=tst_arch,
         tst_arch=tst_arch,

+ 1 - 0
test/test_unit_score_file.py

@@ -201,6 +201,7 @@ def test_score_values(
         YADM_TEST=1 source {yadm}
         YADM_TEST=1 source {yadm}
         score=0
         score=0
         local_class={local_class}
         local_class={local_class}
+        local_classes=({local_class})
         local_arch={local_arch}
         local_arch={local_arch}
         local_system={local_system}
         local_system={local_system}
         local_distro={local_distro}
         local_distro={local_distro}

+ 4 - 1
test/test_unit_set_local_alt_values.py

@@ -34,7 +34,10 @@ def test_set_local_alt_values(
         echo "user='$local_user'"
         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')
         utils.set_local(paths, override, 'override')
 
 
     run = runner(command=['bash'], inp=script)
     run = runner(command=['bash'], inp=script)

+ 6 - 0
test/test_unit_template_default.py

@@ -5,6 +5,7 @@ FILE_MODE = 0o754
 
 
 # these values are also testing the handling of bizarre characters
 # these values are also testing the handling of bizarre characters
 LOCAL_CLASS = "default_Test+@-!^Class"
 LOCAL_CLASS = "default_Test+@-!^Class"
+LOCAL_CLASS2 = "default_Test+@-|^2nd_Class withSpace"
 LOCAL_ARCH = "default_Test+@-!^Arch"
 LOCAL_ARCH = "default_Test+@-!^Arch"
 LOCAL_SYSTEM = "default_Test+@-!^System"
 LOCAL_SYSTEM = "default_Test+@-!^System"
 LOCAL_HOST = "default_Test+@-!^Host"
 LOCAL_HOST = "default_Test+@-!^Host"
@@ -32,6 +33,9 @@ Multiple lines
 {{% else %}}
 {{% else %}}
 Should not be included...
 Should not be included...
 {{% endif %}}
 {{% endif %}}
+{{% if yadm.class == "{LOCAL_CLASS2}" %}}
+Included section for second class
+{{% endif %}}
 {{% if yadm.class == "wrongclass2" %}}
 {{% if yadm.class == "wrongclass2" %}}
 wrong class 2
 wrong class 2
 {{% endif %}}
 {{% endif %}}
@@ -93,6 +97,7 @@ default distro = >{LOCAL_DISTRO}<
 Included section from else
 Included section from else
 Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
 Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
 Multiple lines
 Multiple lines
+Included section for second class
 Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated)
 Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
 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}
         YADM_TEST=1 source {yadm}
         set_awk
         set_awk
         local_class="{LOCAL_CLASS}"
         local_class="{LOCAL_CLASS}"
+        local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}")
         local_arch="{LOCAL_ARCH}"
         local_arch="{LOCAL_ARCH}"
         local_system="{LOCAL_SYSTEM}"
         local_system="{LOCAL_SYSTEM}"
         local_host="{LOCAL_HOST}"
         local_host="{LOCAL_HOST}"

+ 7 - 0
test/test_unit_template_esh.py

@@ -4,6 +4,7 @@ import os
 FILE_MODE = 0o754
 FILE_MODE = 0o754
 
 
 LOCAL_CLASS = "esh_Test+@-!^Class"
 LOCAL_CLASS = "esh_Test+@-!^Class"
+LOCAL_CLASS2 = "esh_Test+@-|^2nd_Class withSpace"
 LOCAL_ARCH = "esh_Test+@-!^Arch"
 LOCAL_ARCH = "esh_Test+@-!^Arch"
 LOCAL_SYSTEM = "esh_Test+@-!^System"
 LOCAL_SYSTEM = "esh_Test+@-!^System"
 LOCAL_HOST = "esh_Test+@-!^Host"
 LOCAL_HOST = "esh_Test+@-!^Host"
@@ -26,6 +27,10 @@ Included section for class = <%=$YADM_CLASS%> (<%=$YADM_CLASS%> repeated)
 <% if [ "$YADM_CLASS" = "wrongclass2" ]; then -%>
 <% if [ "$YADM_CLASS" = "wrongclass2" ]; then -%>
 wrong class 2
 wrong class 2
 <% fi -%>
 <% 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 -%>
 <% if [ "$YADM_ARCH" = "wrongarch1" ]; then -%>
 wrong arch 1
 wrong arch 1
 <% fi -%>
 <% fi -%>
@@ -82,6 +87,7 @@ esh host   = >{LOCAL_HOST}<
 esh user   = >{LOCAL_USER}<
 esh user   = >{LOCAL_USER}<
 esh distro = >{LOCAL_DISTRO}<
 esh distro = >{LOCAL_DISTRO}<
 Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
 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 arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
 Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
@@ -108,6 +114,7 @@ def test_template_esh(runner, yadm, tmpdir):
     script = f"""
     script = f"""
         YADM_TEST=1 source {yadm}
         YADM_TEST=1 source {yadm}
         local_class="{LOCAL_CLASS}"
         local_class="{LOCAL_CLASS}"
+        local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}")
         local_arch="{LOCAL_ARCH}"
         local_arch="{LOCAL_ARCH}"
         local_system="{LOCAL_SYSTEM}"
         local_system="{LOCAL_SYSTEM}"
         local_host="{LOCAL_HOST}"
         local_host="{LOCAL_HOST}"

+ 6 - 0
test/test_unit_template_j2.py

@@ -5,6 +5,7 @@ import pytest
 FILE_MODE = 0o754
 FILE_MODE = 0o754
 
 
 LOCAL_CLASS = "j2_Test+@-!^Class"
 LOCAL_CLASS = "j2_Test+@-!^Class"
+LOCAL_CLASS2 = "j2_Test+@-|^2nd_Class withSpace"
 LOCAL_ARCH = "j2_Test+@-!^Arch"
 LOCAL_ARCH = "j2_Test+@-!^Arch"
 LOCAL_SYSTEM = "j2_Test+@-!^System"
 LOCAL_SYSTEM = "j2_Test+@-!^System"
 LOCAL_HOST = "j2_Test+@-!^Host"
 LOCAL_HOST = "j2_Test+@-!^Host"
@@ -27,6 +28,9 @@ Included section for class = {{{{YADM_CLASS}}}} ({{{{YADM_CLASS}}}} repeated)
 {{%- if YADM_CLASS == "wrongclass2" %}}
 {{%- if YADM_CLASS == "wrongclass2" %}}
 wrong class 2
 wrong class 2
 {{%- endif %}}
 {{%- endif %}}
+{{%- if "{LOCAL_CLASS2}" in YADM_CLASSES.split("\\n") %}}
+Included section for second class
+{{%- endif %}}
 {{%- if YADM_ARCH == "wrongarch1" %}}
 {{%- if YADM_ARCH == "wrongarch1" %}}
 wrong arch 1
 wrong arch 1
 {{%- endif %}}
 {{%- endif %}}
@@ -83,6 +87,7 @@ j2 host   = >{LOCAL_HOST}<
 j2 user   = >{LOCAL_USER}<
 j2 user   = >{LOCAL_USER}<
 j2 distro = >{LOCAL_DISTRO}<
 j2 distro = >{LOCAL_DISTRO}<
 Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
 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 arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
 Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
 Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
@@ -110,6 +115,7 @@ def test_template_j2(runner, yadm, tmpdir, processor):
     script = f"""
     script = f"""
         YADM_TEST=1 source {yadm}
         YADM_TEST=1 source {yadm}
         local_class="{LOCAL_CLASS}"
         local_class="{LOCAL_CLASS}"
+        local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}")
         local_arch="{LOCAL_ARCH}"
         local_arch="{LOCAL_ARCH}"
         local_system="{LOCAL_SYSTEM}"
         local_system="{LOCAL_SYSTEM}"
         local_host="{LOCAL_HOST}"
         local_host="{LOCAL_HOST}"

+ 3 - 2
test/utils.py

@@ -21,11 +21,12 @@ INCLUDE_DIRS = ['', 'test alt']
 INCLUDE_CONTENT = '8780846c02e34c930d0afd127906668f'
 INCLUDE_CONTENT = '8780846c02e34c930d0afd127906668f'
 
 
 
 
-def set_local(paths, variable, value):
+def set_local(paths, variable, value, add=False):
     """Set local override"""
     """Set local override"""
+    add = "--add" if add else ""
     os.system(
     os.system(
         f'GIT_DIR={str(paths.repo)} '
         f'GIT_DIR={str(paths.repo)} '
-        f'git config --local "local.{variable}" "{value}"'
+        f'git config --local {add} "local.{variable}" "{value}"'
     )
     )
 
 
 
 

+ 35 - 5
yadm

@@ -211,7 +211,7 @@ function score_file() {
         return
         return
       fi
       fi
     elif [[ "$label" =~ ^(c|class)$ ]]; then
     elif [[ "$label" =~ ^(c|class)$ ]]; then
-      if [ "$value" = "$local_class" ]; then
+      if in_list "$value" "${local_classes[@]}"; then
         score=$((score + 8))
         score=$((score + 8))
       else
       else
         score=0
         score=0
@@ -418,12 +418,22 @@ function replace_vars() {
     gsub(("{{" blank "*yadm\\." label blank "*}}"), c[label])
     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() {
 function conditions() {
   pattern = ifs blank "+("
   pattern = ifs blank "+("
   for (label in c) {
   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)
   sub(/\|$/, ")" blank "*%}$", pattern)
   return pattern
   return pattern
@@ -439,6 +449,7 @@ EOF
     -v distro="$local_distro" \
     -v distro="$local_distro" \
     -v source="$input" \
     -v source="$input" \
     -v source_dir="$(dirname "$input")" \
     -v source_dir="$(dirname "$input")" \
+    -v classes="$(join_string $'\n' "${local_classes[@]}")" \
     "$awk_pgm" \
     "$awk_pgm" \
     "$input" > "$temp_file" || rm -f "$temp_file"
     "$input" > "$temp_file" || rm -f "$temp_file"
 
 
@@ -457,6 +468,7 @@ function template_j2cli() {
   YADM_USER="$local_user"     \
   YADM_USER="$local_user"     \
   YADM_DISTRO="$local_distro" \
   YADM_DISTRO="$local_distro" \
   YADM_SOURCE="$input"        \
   YADM_SOURCE="$input"        \
+  YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \
   "$J2CLI_PROGRAM" "$input" -o "$temp_file"
   "$J2CLI_PROGRAM" "$input" -o "$temp_file"
 
 
   move_file "$input" "$output" "$temp_file"
   move_file "$input" "$output" "$temp_file"
@@ -474,6 +486,7 @@ function template_envtpl() {
   YADM_USER="$local_user"     \
   YADM_USER="$local_user"     \
   YADM_DISTRO="$local_distro" \
   YADM_DISTRO="$local_distro" \
   YADM_SOURCE="$input"        \
   YADM_SOURCE="$input"        \
+  YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \
   "$ENVTPL_PROGRAM" --keep-template "$input" -o "$temp_file"
   "$ENVTPL_PROGRAM" --keep-template "$input" -o "$temp_file"
 
 
   move_file "$input" "$output" "$temp_file"
   move_file "$input" "$output" "$temp_file"
@@ -484,6 +497,7 @@ function template_esh() {
   output="$2"
   output="$2"
   temp_file="${output}.$$.$RANDOM"
   temp_file="${output}.$$.$RANDOM"
 
 
+  YADM_CLASSES="$(join_string $'\n' "${local_classes[@]}")" \
   "$ESH_PROGRAM" -o "$temp_file" "$input" \
   "$ESH_PROGRAM" -o "$temp_file" "$input" \
   YADM_CLASS="$local_class"   \
   YADM_CLASS="$local_class"   \
   YADM_ARCH="$local_arch"     \
   YADM_ARCH="$local_arch"     \
@@ -521,6 +535,7 @@ function alt() {
 
 
   # gather values for processing alternates
   # gather values for processing alternates
   local local_class
   local local_class
+  local -a local_classes
   local local_arch
   local local_arch
   local local_system
   local local_system
   local local_host
   local local_host
@@ -620,7 +635,12 @@ function remove_stale_links() {
 
 
 function set_local_alt_values() {
 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)"
   local_arch="$(config local.arch)"
   if [ -z "$local_arch" ] ; then
   if [ -z "$local_arch" ] ; then
@@ -2032,6 +2052,16 @@ function join_string {
     printf "%s" "${*:2}"
     printf "%s" "${*:2}"
 }
 }
 
 
+function in_list {
+  local element="$1"
+  shift
+
+  for e in "$@"; do
+    [[ "$e" = "$element" ]] && return 0
+  done
+  return 1
+}
+
 function get_mode {
 function get_mode {
   local filename="$1"
   local filename="$1"
   local mode
   local mode