Refactor alt handling
* Simplify score_file() by using case in instead of nested ifs with regexps. * Merge record_score() and record_template(). * Alt condition processing no longer stops when a template condition is seen but continues processing to verify that all conditions are valid (as the documentation says it should). Fixes #478. * Support alt dirs with deeply nested tracked files (fixes #490). * Use git ls-files to filter out which tracked files to consider for alt processing. Should speed up auto-alt (#505). * Use nocasematch when comparing distro and distro_family. Fixed #455.
This commit is contained in:
parent
b164d03594
commit
b2b0b143d6
9 changed files with 259 additions and 296 deletions
|
@ -170,6 +170,21 @@ def test_alt_templates(runner, paths, kind, label):
|
||||||
assert str(paths.work.join(source_file)) in created
|
assert str(paths.work.join(source_file)) in created
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("ds1_copy")
|
||||||
|
def test_alt_template_with_condition(runner, paths, tst_arch):
|
||||||
|
"""Test template with extra condition"""
|
||||||
|
yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
|
||||||
|
|
||||||
|
suffix = f"##template,arch.not{tst_arch}"
|
||||||
|
utils.create_alt_files(paths, suffix)
|
||||||
|
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
|
||||||
|
assert run.success
|
||||||
|
assert run.err == ""
|
||||||
|
|
||||||
|
created = utils.parse_alt_output(run.out, linked=False)
|
||||||
|
assert len(created) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("ds1_copy")
|
@pytest.mark.usefixtures("ds1_copy")
|
||||||
@pytest.mark.parametrize("autoalt", [None, "true", "false"])
|
@pytest.mark.parametrize("autoalt", [None, "true", "false"])
|
||||||
def test_auto_alt(runner, yadm_cmd, paths, autoalt):
|
def test_auto_alt(runner, yadm_cmd, paths, autoalt):
|
||||||
|
|
|
@ -40,7 +40,8 @@ def test_alt_copy(runner, yadm_cmd, paths, tst_sys, setting, expect_link, pre_ex
|
||||||
run = runner(yadm_cmd("alt"))
|
run = runner(yadm_cmd("alt"))
|
||||||
assert run.success
|
assert run.success
|
||||||
assert run.err == ""
|
assert run.err == ""
|
||||||
assert "Linking" in run.out
|
action = "Copying" if setting is True else "Linking"
|
||||||
|
assert action in run.out
|
||||||
|
|
||||||
assert alt_path.read() == expected_content
|
assert alt_path.read() == expected_content
|
||||||
assert alt_path.islink() == expect_link
|
assert alt_path.islink() == expect_link
|
||||||
|
|
|
@ -19,6 +19,7 @@ REPORT_RESULTS = """
|
||||||
echo "SCORES:${alt_scores[@]}"
|
echo "SCORES:${alt_scores[@]}"
|
||||||
echo "TARGETS:${alt_targets[@]}"
|
echo "TARGETS:${alt_targets[@]}"
|
||||||
echo "SOURCES:${alt_sources[@]}"
|
echo "SOURCES:${alt_sources[@]}"
|
||||||
|
echo "TEMPLATE_CMDS:${alt_template_cmds[@]}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ def test_dont_record_zeros(runner, yadm):
|
||||||
assert "SCORES:\n" in run.out
|
assert "SCORES:\n" in run.out
|
||||||
assert "TARGETS:\n" in run.out
|
assert "TARGETS:\n" in run.out
|
||||||
assert "SOURCES:\n" in run.out
|
assert "SOURCES:\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS:\n" in run.out
|
||||||
|
|
||||||
|
|
||||||
def test_new_scores(runner, yadm):
|
def test_new_scores(runner, yadm):
|
||||||
|
@ -46,9 +48,9 @@ def test_new_scores(runner, yadm):
|
||||||
script = f"""
|
script = f"""
|
||||||
YADM_TEST=1 source {yadm}
|
YADM_TEST=1 source {yadm}
|
||||||
{INIT_VARS}
|
{INIT_VARS}
|
||||||
record_score "1" "tgt_one" "src_one"
|
record_score "1" "tgt_one" "src_one" ""
|
||||||
record_score "2" "tgt_two" "src_two"
|
record_score "2" "tgt_two" "src_two" ""
|
||||||
record_score "4" "tgt_three" "src_three"
|
record_score "4" "tgt_three" "src_three" ""
|
||||||
{REPORT_RESULTS}
|
{REPORT_RESULTS}
|
||||||
"""
|
"""
|
||||||
run = runner(command=["bash"], inp=script)
|
run = runner(command=["bash"], inp=script)
|
||||||
|
@ -58,6 +60,7 @@ def test_new_scores(runner, yadm):
|
||||||
assert "SCORES:1 2 4\n" in run.out
|
assert "SCORES:1 2 4\n" in run.out
|
||||||
assert "TARGETS:tgt_one tgt_two tgt_three\n" in run.out
|
assert "TARGETS:tgt_one tgt_two tgt_three\n" in run.out
|
||||||
assert "SOURCES:src_one src_two src_three\n" in run.out
|
assert "SOURCES:src_one src_two src_three\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS: \n" in run.out
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("difference", ["lower", "equal", "higher"])
|
@pytest.mark.parametrize("difference", ["lower", "equal", "higher"])
|
||||||
|
@ -81,7 +84,8 @@ def test_existing_scores(runner, yadm, difference):
|
||||||
alt_scores=(2)
|
alt_scores=(2)
|
||||||
alt_targets=("testtgt")
|
alt_targets=("testtgt")
|
||||||
alt_sources=("existing_src")
|
alt_sources=("existing_src")
|
||||||
record_score "{score}" "testtgt" "new_src"
|
alt_template_cmds=("")
|
||||||
|
record_score "{score}" "testtgt" "new_src" ""
|
||||||
{REPORT_RESULTS}
|
{REPORT_RESULTS}
|
||||||
"""
|
"""
|
||||||
run = runner(command=["bash"], inp=script)
|
run = runner(command=["bash"], inp=script)
|
||||||
|
@ -91,6 +95,7 @@ def test_existing_scores(runner, yadm, difference):
|
||||||
assert f"SCORES:{expected_score}\n" in run.out
|
assert f"SCORES:{expected_score}\n" in run.out
|
||||||
assert "TARGETS:testtgt\n" in run.out
|
assert "TARGETS:testtgt\n" in run.out
|
||||||
assert f"SOURCES:{expected_src}\n" in run.out
|
assert f"SOURCES:{expected_src}\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS:\n" in run.out
|
||||||
|
|
||||||
|
|
||||||
def test_existing_template(runner, yadm):
|
def test_existing_template(runner, yadm):
|
||||||
|
@ -101,9 +106,9 @@ def test_existing_template(runner, yadm):
|
||||||
{INIT_VARS}
|
{INIT_VARS}
|
||||||
alt_scores=(1)
|
alt_scores=(1)
|
||||||
alt_targets=("testtgt")
|
alt_targets=("testtgt")
|
||||||
alt_sources=()
|
alt_sources=("src")
|
||||||
alt_template_cmds=("existing_template")
|
alt_template_cmds=("existing_template")
|
||||||
record_score "2" "testtgt" "new_src"
|
record_score "2" "testtgt" "new_src" ""
|
||||||
{REPORT_RESULTS}
|
{REPORT_RESULTS}
|
||||||
"""
|
"""
|
||||||
run = runner(command=["bash"], inp=script)
|
run = runner(command=["bash"], inp=script)
|
||||||
|
@ -112,7 +117,8 @@ def test_existing_template(runner, yadm):
|
||||||
assert "SIZE:1\n" in run.out
|
assert "SIZE:1\n" in run.out
|
||||||
assert "SCORES:1\n" in run.out
|
assert "SCORES:1\n" in run.out
|
||||||
assert "TARGETS:testtgt\n" in run.out
|
assert "TARGETS:testtgt\n" in run.out
|
||||||
assert "SOURCES:\n" in run.out
|
assert "SOURCES:src\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS:existing_template\n" in run.out
|
||||||
|
|
||||||
|
|
||||||
def test_config_first(runner, yadm):
|
def test_config_first(runner, yadm):
|
||||||
|
@ -123,20 +129,61 @@ def test_config_first(runner, yadm):
|
||||||
YADM_TEST=1 source {yadm}
|
YADM_TEST=1 source {yadm}
|
||||||
{INIT_VARS}
|
{INIT_VARS}
|
||||||
YADM_CONFIG={config}
|
YADM_CONFIG={config}
|
||||||
record_score "1" "tgt_before" "src_before"
|
record_score "1" "tgt_before" "src_before" ""
|
||||||
record_template "tgt_tmp" "cmd_tmp" "src_tmp"
|
record_score "1" "tgt_tmp" "src_tmp" "cmd_tmp"
|
||||||
record_score "2" "{config}" "src_config"
|
record_score "2" "{config}" "src_config" ""
|
||||||
record_score "3" "tgt_after" "src_after"
|
record_score "3" "tgt_after" "src_after" ""
|
||||||
|
{REPORT_RESULTS}
|
||||||
|
"""
|
||||||
|
run = runner(command=["bash"], inp=script)
|
||||||
|
assert run.success
|
||||||
|
assert run.err == ""
|
||||||
|
assert "SIZE:4\n" in run.out
|
||||||
|
assert "SCORES:2 1 1 3\n" in run.out
|
||||||
|
assert f"TARGETS:{config} tgt_before tgt_tmp tgt_after\n" in run.out
|
||||||
|
assert "SOURCES:src_config src_before src_tmp src_after\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS: cmd_tmp \n" in run.out
|
||||||
|
|
||||||
|
|
||||||
|
def test_new_template(runner, yadm):
|
||||||
|
"""Test new template"""
|
||||||
|
|
||||||
|
script = f"""
|
||||||
|
YADM_TEST=1 source {yadm}
|
||||||
|
{INIT_VARS}
|
||||||
|
record_score 0 "tgt_one" "src_one" "cmd_one"
|
||||||
|
record_score 0 "tgt_two" "src_two" "cmd_two"
|
||||||
|
record_score 0 "tgt_three" "src_three" "cmd_three"
|
||||||
{REPORT_RESULTS}
|
{REPORT_RESULTS}
|
||||||
echo "CMD_VALUE:${{alt_template_cmds[@]}}"
|
|
||||||
echo "CMD_INDEX:${{!alt_template_cmds[@]}}"
|
|
||||||
"""
|
"""
|
||||||
run = runner(command=["bash"], inp=script)
|
run = runner(command=["bash"], inp=script)
|
||||||
assert run.success
|
assert run.success
|
||||||
assert run.err == ""
|
assert run.err == ""
|
||||||
assert "SIZE:3\n" in run.out
|
assert "SIZE:3\n" in run.out
|
||||||
assert "SCORES:2 1 3\n" in run.out
|
assert "SCORES:0 0 0\n" in run.out
|
||||||
assert f"TARGETS:{config} tgt_before tgt_tmp tgt_after\n" in run.out
|
assert "TARGETS:tgt_one tgt_two tgt_three\n" in run.out
|
||||||
assert "SOURCES:src_config src_before src_tmp src_after\n" in run.out
|
assert "SOURCES:src_one src_two src_three\n" in run.out
|
||||||
assert "CMD_VALUE:cmd_tmp\n" in run.out
|
assert "TEMPLATE_CMDS:cmd_one cmd_two cmd_three\n" in run.out
|
||||||
assert "CMD_INDEX:2\n" in run.out
|
|
||||||
|
|
||||||
|
def test_overwrite_existing_template(runner, yadm):
|
||||||
|
"""Overwrite existing templates"""
|
||||||
|
|
||||||
|
script = f"""
|
||||||
|
YADM_TEST=1 source {yadm}
|
||||||
|
{INIT_VARS}
|
||||||
|
alt_scores=(0)
|
||||||
|
alt_targets=("testtgt")
|
||||||
|
alt_template_cmds=("existing_cmd")
|
||||||
|
alt_sources=("existing_src")
|
||||||
|
record_score 0 "testtgt" "new_src" "new_cmd"
|
||||||
|
{REPORT_RESULTS}
|
||||||
|
"""
|
||||||
|
run = runner(command=["bash"], inp=script)
|
||||||
|
assert run.success
|
||||||
|
assert run.err == ""
|
||||||
|
assert "SIZE:1\n" in run.out
|
||||||
|
assert "SCORES:0\n" in run.out
|
||||||
|
assert "TARGETS:testtgt\n" in run.out
|
||||||
|
assert "SOURCES:new_src\n" in run.out
|
||||||
|
assert "TEMPLATE_CMDS:new_cmd\n" in run.out
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
"""Unit tests: record_template"""
|
|
||||||
|
|
||||||
INIT_VARS = """
|
|
||||||
alt_targets=()
|
|
||||||
alt_template_cmds=()
|
|
||||||
alt_sources=()
|
|
||||||
"""
|
|
||||||
|
|
||||||
REPORT_RESULTS = """
|
|
||||||
echo "SIZE:${#alt_targets[@]}"
|
|
||||||
echo "TARGETS:${alt_targets[@]}"
|
|
||||||
echo "CMDS:${alt_template_cmds[@]}"
|
|
||||||
echo "SOURCES:${alt_sources[@]}"
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def test_new_template(runner, yadm):
|
|
||||||
"""Test new template"""
|
|
||||||
|
|
||||||
script = f"""
|
|
||||||
YADM_TEST=1 source {yadm}
|
|
||||||
{INIT_VARS}
|
|
||||||
record_template "tgt_one" "cmd_one" "src_one"
|
|
||||||
record_template "tgt_two" "cmd_two" "src_two"
|
|
||||||
record_template "tgt_three" "cmd_three" "src_three"
|
|
||||||
{REPORT_RESULTS}
|
|
||||||
"""
|
|
||||||
run = runner(command=["bash"], inp=script)
|
|
||||||
assert run.success
|
|
||||||
assert run.err == ""
|
|
||||||
assert "SIZE:3\n" in run.out
|
|
||||||
assert "TARGETS:tgt_one tgt_two tgt_three\n" in run.out
|
|
||||||
assert "CMDS:cmd_one cmd_two cmd_three\n" in run.out
|
|
||||||
assert "SOURCES:src_one src_two src_three\n" in run.out
|
|
||||||
|
|
||||||
|
|
||||||
def test_existing_template(runner, yadm):
|
|
||||||
"""Overwrite existing templates"""
|
|
||||||
|
|
||||||
script = f"""
|
|
||||||
YADM_TEST=1 source {yadm}
|
|
||||||
{INIT_VARS}
|
|
||||||
alt_targets=("testtgt")
|
|
||||||
alt_template_cmds=("existing_cmd")
|
|
||||||
alt_sources=("existing_src")
|
|
||||||
record_template "testtgt" "new_cmd" "new_src"
|
|
||||||
{REPORT_RESULTS}
|
|
||||||
"""
|
|
||||||
run = runner(command=["bash"], inp=script)
|
|
||||||
assert run.success
|
|
||||||
assert run.err == ""
|
|
||||||
assert "SIZE:1\n" in run.out
|
|
||||||
assert "TARGETS:testtgt\n" in run.out
|
|
||||||
assert "CMDS:new_cmd\n" in run.out
|
|
||||||
assert "SOURCES:new_src\n" in run.out
|
|
|
@ -25,7 +25,7 @@ def test_remove_stale_links(runner, yadm, tmpdir, kind, linked):
|
||||||
|
|
||||||
script = f"""
|
script = f"""
|
||||||
YADM_TEST=1 source {yadm}
|
YADM_TEST=1 source {yadm}
|
||||||
possible_alts=({link})
|
possible_alt_targets=({link})
|
||||||
alt_linked=({alt_linked})
|
alt_linked=({alt_linked})
|
||||||
function rm() {{ echo rm "$@"; }}
|
function rm() {{ echo rm "$@"; }}
|
||||||
remove_stale_links
|
remove_stale_links
|
||||||
|
|
|
@ -89,7 +89,7 @@ def calculate_score(filename):
|
||||||
else:
|
else:
|
||||||
score = 0
|
score = 0
|
||||||
break
|
break
|
||||||
elif label in TEMPLATE_LABELS:
|
elif label not in TEMPLATE_LABELS:
|
||||||
score = 0
|
score = 0
|
||||||
break
|
break
|
||||||
return score
|
return score
|
||||||
|
@ -190,7 +190,7 @@ def test_score_values(runner, yadm, default, arch, system, distro, cla, host, us
|
||||||
expected = ""
|
expected = ""
|
||||||
for filename, score in filenames.items():
|
for filename, score in filenames.items():
|
||||||
script += f"""
|
script += f"""
|
||||||
score_file "{filename}"
|
score_file "{filename}" "dest"
|
||||||
echo "{filename}"
|
echo "{filename}"
|
||||||
echo "$score"
|
echo "$score"
|
||||||
"""
|
"""
|
||||||
|
@ -255,7 +255,7 @@ def test_score_values_templates(runner, yadm):
|
||||||
expected = ""
|
expected = ""
|
||||||
for filename, score in filenames.items():
|
for filename, score in filenames.items():
|
||||||
script += f"""
|
script += f"""
|
||||||
score_file "{filename}"
|
score_file "{filename}" "dest"
|
||||||
echo "{filename}"
|
echo "{filename}"
|
||||||
echo "$score"
|
echo "$score"
|
||||||
"""
|
"""
|
||||||
|
@ -279,7 +279,7 @@ def test_template_recording(runner, yadm, cmd_generated):
|
||||||
|
|
||||||
script = f"""
|
script = f"""
|
||||||
YADM_TEST=1 source {yadm}
|
YADM_TEST=1 source {yadm}
|
||||||
function record_template() {{ echo "template recorded"; }}
|
function record_score() {{ [ -n "$4" ] && echo "template recorded"; }}
|
||||||
{mock}
|
{mock}
|
||||||
score_file "testfile##template.kind"
|
score_file "testfile##template.kind"
|
||||||
"""
|
"""
|
||||||
|
@ -289,15 +289,15 @@ def test_template_recording(runner, yadm, cmd_generated):
|
||||||
assert run.out.rstrip() == expected
|
assert run.out.rstrip() == expected
|
||||||
|
|
||||||
|
|
||||||
def test_underscores_in_distro_and_family(runner, yadm):
|
def test_underscores_and_upper_case_in_distro_and_family(runner, yadm):
|
||||||
"""Test replacing spaces in distro / distro_family with underscores"""
|
"""Test replacing spaces with underscores and lowering case in distro / distro_family"""
|
||||||
local_distro = "test distro"
|
local_distro = "test distro"
|
||||||
local_distro_family = "test family"
|
local_distro_family = "test family"
|
||||||
filenames = {
|
filenames = {
|
||||||
"filename##distro.test distro": 1004,
|
"filename##distro.Test Distro": 1004,
|
||||||
"filename##distro.test-distro": 0,
|
"filename##distro.test-distro": 0,
|
||||||
"filename##distro.test_distro": 1004,
|
"filename##distro.test_distro": 1004,
|
||||||
"filename##distro_family.test family": 1008,
|
"filename##distro_family.test FAMILY": 1008,
|
||||||
"filename##distro_family.test-family": 0,
|
"filename##distro_family.test-family": 0,
|
||||||
"filename##distro_family.test_family": 1008,
|
"filename##distro_family.test_family": 1008,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ ALT_DIR = "test alt/test alt dir"
|
||||||
|
|
||||||
# Directory based alternates must have a tracked contained file.
|
# Directory based alternates must have a tracked contained file.
|
||||||
# This will be the test contained file name
|
# This will be the test contained file name
|
||||||
CONTAINED = "contained_file"
|
CONTAINED = "contained_dir/contained_file"
|
||||||
|
|
||||||
# These variables are used for making include files which will be processed
|
# These variables are used for making include files which will be processed
|
||||||
# within jinja templates
|
# within jinja templates
|
||||||
|
@ -84,7 +84,7 @@ def parse_alt_output(output, linked=True):
|
||||||
"""Parse output of 'alt', and return list of linked files"""
|
"""Parse output of 'alt', and return list of linked files"""
|
||||||
regex = r"Creating (.+) from template (.+)$"
|
regex = r"Creating (.+) from template (.+)$"
|
||||||
if linked:
|
if linked:
|
||||||
regex = r"Linking (.+) to (.+)$"
|
regex = r"(?:Copy|Link)ing (.+) to (.+)$"
|
||||||
parsed_list = {}
|
parsed_list = {}
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
match = re.match(regex, line)
|
match = re.match(regex, line)
|
||||||
|
|
375
yadm
375
yadm
|
@ -166,188 +166,139 @@ function main() {
|
||||||
# ****** Alternate Processing ******
|
# ****** Alternate Processing ******
|
||||||
|
|
||||||
function score_file() {
|
function score_file() {
|
||||||
src="$1"
|
local source="$1"
|
||||||
tgt="${src%%##*}"
|
local target="$2"
|
||||||
conditions="${src#*##}"
|
local conditions="${source#*##}"
|
||||||
|
|
||||||
if [ "${tgt#"$YADM_ALT/"}" != "${tgt}" ]; then
|
|
||||||
tgt="${YADM_BASE}/${tgt#"$YADM_ALT/"}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
score=0
|
score=0
|
||||||
|
local template_cmd=""
|
||||||
|
|
||||||
IFS=',' read -ra fields <<< "$conditions"
|
IFS=',' read -ra fields <<< "$conditions"
|
||||||
for field in "${fields[@]}"; do
|
for field in "${fields[@]}"; do
|
||||||
label=${field%%.*}
|
local label=${field%%.*}
|
||||||
value=${field#*.}
|
local value=${field#*.}
|
||||||
[ "$field" = "$label" ] && value="" # when .value is omitted
|
[ "$field" = "$label" ] && value="" # when .value is omitted
|
||||||
# extension isn't a condition and doesn't affect the score
|
|
||||||
if [[ "$label" =~ ^(e|extension)$ ]]; then
|
local -i delta=-1
|
||||||
continue
|
case "$label" in
|
||||||
fi
|
default)
|
||||||
score=$((score + 1000))
|
delta=0
|
||||||
# default condition
|
;;
|
||||||
if [[ "$label" =~ ^(default)$ ]]; then
|
a|arch)
|
||||||
score=$((score + 0))
|
[ "$value" = "$local_arch" ] && delta=1
|
||||||
# variable conditions
|
;;
|
||||||
elif [[ "$label" =~ ^(a|arch)$ ]]; then
|
o|os)
|
||||||
if [ "$value" = "$local_arch" ]; then
|
[ "$value" = "$local_system" ] && delta=2
|
||||||
score=$((score + 1))
|
;;
|
||||||
else
|
d|distro)
|
||||||
score=0
|
shopt -s nocasematch
|
||||||
return
|
[[ "${value// /_}" = "${local_distro// /_}" ]] && delta=4
|
||||||
fi
|
shopt -u nocasematch
|
||||||
elif [[ "$label" =~ ^(o|os)$ ]]; then
|
;;
|
||||||
if [ "$value" = "$local_system" ]; then
|
f|distro_family)
|
||||||
score=$((score + 2))
|
shopt -s nocasematch
|
||||||
else
|
[[ "${value// /_}" = "${local_distro_family// /_}" ]] && delta=8
|
||||||
score=0
|
shopt -u nocasematch
|
||||||
return
|
;;
|
||||||
fi
|
c|class)
|
||||||
elif [[ "$label" =~ ^(d|distro)$ ]]; then
|
in_list "$value" "${local_classes[@]}" && delta=16
|
||||||
if [ "${value/\ /_}" = "${local_distro/\ /_}" ]; then
|
;;
|
||||||
score=$((score + 4))
|
h|hostname)
|
||||||
else
|
[ "$value" = "$local_host" ] && delta=32
|
||||||
score=0
|
;;
|
||||||
return
|
u|user)
|
||||||
fi
|
[ "$value" = "$local_user" ] && delta=64
|
||||||
elif [[ "$label" =~ ^(f|distro_family)$ ]]; then
|
;;
|
||||||
if [ "${value/\ /_}" = "${local_distro_family/\ /_}" ]; then
|
e|extension)
|
||||||
score=$((score + 8))
|
# extension isn't a condition and doesn't affect the score
|
||||||
else
|
continue
|
||||||
score=0
|
;;
|
||||||
return
|
t|template|yadm)
|
||||||
fi
|
if [ -d "$source" ]; then
|
||||||
elif [[ "$label" =~ ^(c|class)$ ]]; then
|
INVALID_ALT+=("$source")
|
||||||
if in_list "$value" "${local_classes[@]}"; then
|
else
|
||||||
score=$((score + 16))
|
template_cmd=$(choose_template_cmd "$value")
|
||||||
else
|
if [ -n "$template_cmd" ]; then
|
||||||
score=0
|
delta=0
|
||||||
return
|
else
|
||||||
fi
|
debug "No supported template processor for template $source"
|
||||||
elif [[ "$label" =~ ^(h|hostname)$ ]]; then
|
[ -n "$loud" ] && echo "No supported template processor for template $source"
|
||||||
if [ "$value" = "$local_host" ]; then
|
fi
|
||||||
score=$((score + 32))
|
fi
|
||||||
else
|
;;
|
||||||
score=0
|
*)
|
||||||
return
|
INVALID_ALT+=("$source")
|
||||||
fi
|
;;
|
||||||
elif [[ "$label" =~ ^(u|user)$ ]]; then
|
esac
|
||||||
if [ "$value" = "$local_user" ]; then
|
|
||||||
score=$((score + 64))
|
if (( delta < 0 )); then
|
||||||
else
|
|
||||||
score=0
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
# templates
|
|
||||||
elif [[ "$label" =~ ^(t|template|yadm)$ ]]; then
|
|
||||||
score=0
|
|
||||||
cmd=$(choose_template_cmd "$value")
|
|
||||||
if [ -n "$cmd" ]; then
|
|
||||||
record_template "$tgt" "$cmd" "$src"
|
|
||||||
else
|
|
||||||
debug "No supported template processor for template $src"
|
|
||||||
[ -n "$loud" ] && echo "No supported template processor for template $src"
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
# unsupported values
|
|
||||||
else
|
|
||||||
if [[ "${src##*/}" =~ .\#\#. ]]; then
|
|
||||||
INVALID_ALT+=("$src")
|
|
||||||
fi
|
|
||||||
score=0
|
score=0
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
score=$(( score + 1000 + delta ))
|
||||||
done
|
done
|
||||||
|
|
||||||
record_score "$score" "$tgt" "$src"
|
record_score "$score" "$target" "$source" "$template_cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
function record_score() {
|
function record_score() {
|
||||||
score="$1"
|
local score="$1"
|
||||||
tgt="$2"
|
local target="$2"
|
||||||
src="$3"
|
local source="$3"
|
||||||
|
local template_cmd="$4"
|
||||||
|
|
||||||
# record nothing if the score is zero
|
# record nothing if the score is zero
|
||||||
[ "$score" -eq 0 ] && return
|
[ "$score" -eq 0 ] && [ -z "$template_cmd" ] && return
|
||||||
|
|
||||||
# search for the index of this target, to see if we already are tracking it
|
# search for the index of this target, to see if we already are tracking it
|
||||||
index=-1
|
local -i index=$((${#alt_targets[@]} - 1))
|
||||||
for search_index in "${!alt_targets[@]}"; do
|
for (( ; index >= 0; --index )); do
|
||||||
if [ "${alt_targets[$search_index]}" = "$tgt" ]; then
|
if [ "${alt_targets[$index]}" = "$target" ]; then
|
||||||
index="$search_index"
|
break
|
||||||
break
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
# if we don't find an existing index, create one by appending to the array
|
|
||||||
if [ "$index" -eq -1 ]; then
|
if [ $index -lt 0 ]; then
|
||||||
# $YADM_CONFIG must be processed first, in case other templates lookup yadm configurations
|
# $YADM_CONFIG must be processed first, in case other templates lookup yadm configurations
|
||||||
if [ "$tgt" = "$YADM_CONFIG" ]; then
|
if [ "$target" = "$YADM_CONFIG" ]; then
|
||||||
alt_targets=("$tgt" "${alt_targets[@]}")
|
alt_targets=("$target" "${alt_targets[@]}")
|
||||||
alt_sources=("$src" "${alt_sources[@]}")
|
|
||||||
alt_scores=(0 "${alt_scores[@]}")
|
alt_sources=("$source" "${alt_sources[@]}")
|
||||||
index=0
|
alt_scores=("$score" "${alt_scores[@]}")
|
||||||
# increase the index of any existing alt_template_cmds
|
alt_template_cmds=("$template_cmd" "${alt_template_cmds[@]}")
|
||||||
new_cmds=()
|
|
||||||
for cmd_index in "${!alt_template_cmds[@]}"; do
|
|
||||||
new_cmds[cmd_index+1]="${alt_template_cmds[$cmd_index]}"
|
|
||||||
done
|
|
||||||
alt_template_cmds=()
|
|
||||||
for cmd_index in "${!new_cmds[@]}"; do
|
|
||||||
alt_template_cmds[cmd_index]="${new_cmds[$cmd_index]}"
|
|
||||||
done
|
|
||||||
else
|
else
|
||||||
alt_targets+=("$tgt")
|
alt_targets+=("$target")
|
||||||
# set index to the last index (newly created one)
|
|
||||||
for index in "${!alt_targets[@]}"; do :; done
|
|
||||||
# and set its initial score to zero
|
|
||||||
alt_scores[index]=0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# record nothing if a template command is registered for this file
|
alt_sources+=("$source")
|
||||||
[ "${alt_template_cmds[$index]+isset}" ] && return
|
alt_scores+=("$score")
|
||||||
|
alt_template_cmds+=("$template_cmd")
|
||||||
# record higher scoring sources
|
|
||||||
if [ "$score" -gt "${alt_scores[$index]}" ]; then
|
|
||||||
alt_scores[index]="$score"
|
|
||||||
alt_sources[index]="$src"
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function record_template() {
|
|
||||||
tgt="$1"
|
|
||||||
cmd="$2"
|
|
||||||
src="$3"
|
|
||||||
|
|
||||||
# search for the index of this target, to see if we already are tracking it
|
|
||||||
index=-1
|
|
||||||
for search_index in "${!alt_targets[@]}"; do
|
|
||||||
if [ "${alt_targets[$search_index]}" = "$tgt" ]; then
|
|
||||||
index="$search_index"
|
|
||||||
break
|
|
||||||
fi
|
fi
|
||||||
done
|
return
|
||||||
# if we don't find an existing index, create one by appending to the array
|
|
||||||
if [ "$index" -eq -1 ]; then
|
|
||||||
alt_targets+=("$tgt")
|
|
||||||
# set index to the last index (newly created one)
|
|
||||||
for index in "${!alt_targets[@]}"; do :; done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# record the template command, last one wins
|
if [[ -n "${alt_template_cmds[$index]}" ]]; then
|
||||||
alt_template_cmds[index]="$cmd"
|
if [[ -z "$template_cmd" || "$score" -lt "${alt_scores[$index]}" ]]; then
|
||||||
alt_sources[index]="$src"
|
# No template command, or template command but lower score
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
elif [[ -z "$template_cmd" && "$score" -le "${alt_scores[$index]}" ]]; then
|
||||||
|
# No template command and too low score
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Record new alt
|
||||||
|
alt_sources[index]="$source"
|
||||||
|
alt_scores[index]="$score"
|
||||||
|
alt_template_cmds[index]="$template_cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
function choose_template_cmd() {
|
function choose_template_cmd() {
|
||||||
kind="$1"
|
local kind="$1"
|
||||||
|
|
||||||
if [ "$kind" = "default" ] || [ "$kind" = "" ] && awk_available; then
|
if [ "$kind" = "default" ] || [ "$kind" = "" ]; then
|
||||||
echo "template_default"
|
awk_available && echo "template_default"
|
||||||
elif [ "$kind" = "esh" ] && esh_available; then
|
elif [ "$kind" = "esh" ]; then
|
||||||
echo "template_esh"
|
esh_available && echo "template_esh"
|
||||||
elif [ "$kind" = "j2cli" ] || [ "$kind" = "j2" ] && j2cli_available; then
|
elif [ "$kind" = "j2cli" ] || [ "$kind" = "j2" ] && j2cli_available; then
|
||||||
echo "template_j2cli"
|
echo "template_j2cli"
|
||||||
elif [ "$kind" = "envtpl" ] || [ "$kind" = "j2" ] && envtpl_available; then
|
elif [ "$kind" = "envtpl" ] || [ "$kind" = "j2" ] && envtpl_available; then
|
||||||
|
@ -488,7 +439,7 @@ EOF
|
||||||
-v distro="$local_distro" \
|
-v distro="$local_distro" \
|
||||||
-v distro_family="$local_distro_family" \
|
-v distro_family="$local_distro_family" \
|
||||||
-v source="$input" \
|
-v source="$input" \
|
||||||
-v source_dir="$(dirname "$input")" \
|
-v source_dir="$(builtin_dirname "$input")" \
|
||||||
"$awk_pgm" \
|
"$awk_pgm" \
|
||||||
"$input" "${local_classes[@]}" > "$temp_file" || rm -f "$temp_file"
|
"$input" "${local_classes[@]}" > "$temp_file" || rm -f "$temp_file"
|
||||||
|
|
||||||
|
@ -599,29 +550,45 @@ function alt() {
|
||||||
# determine all tracked files
|
# determine all tracked files
|
||||||
local tracked_files=()
|
local tracked_files=()
|
||||||
local IFS=$'\n'
|
local IFS=$'\n'
|
||||||
for tracked_file in $("$GIT_PROGRAM" ls-files | LC_ALL=C sort); do
|
for tracked_file in $("$GIT_PROGRAM" ls-files -- '*##*'); do
|
||||||
tracked_files+=("$tracked_file")
|
tracked_files+=("$tracked_file")
|
||||||
done
|
done
|
||||||
|
|
||||||
# generate data for removing stale links
|
local alt_targets=()
|
||||||
local possible_alts=()
|
local alt_sources=()
|
||||||
local IFS=$'\n'
|
local alt_scores=()
|
||||||
for possible_alt in "${tracked_files[@]}" "${ENCRYPT_INCLUDE_FILES[@]}"; do
|
local alt_template_cmds=()
|
||||||
if [[ $possible_alt =~ .\#\#. ]]; then
|
|
||||||
base_alt="${possible_alt%%##*}"
|
# For removing stale links
|
||||||
yadm_alt="${YADM_BASE}/${base_alt}"
|
local possible_alt_targets=()
|
||||||
if [ "${yadm_alt#"$YADM_ALT/"}" != "${yadm_alt}" ]; then
|
|
||||||
base_alt="${yadm_alt#"$YADM_ALT/"}"
|
local alt_source
|
||||||
fi
|
for alt_source in "${tracked_files[@]}" "${ENCRYPT_INCLUDE_FILES[@]}"; do
|
||||||
possible_alts+=("$YADM_BASE/${base_alt}")
|
local conditions="${alt_source#*##}"
|
||||||
|
if [ "$alt_source" = "$conditions" ]; then
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local target_base="${alt_source%%##*}"
|
||||||
|
alt_source="${YADM_BASE}/${target_base}##${conditions%%/*}"
|
||||||
|
local alt_target="${YADM_BASE}/${target_base}"
|
||||||
|
if [ "${alt_target#"$YADM_ALT/"}" != "$alt_target" ]; then
|
||||||
|
target_base="${alt_target#"$YADM_ALT/"}"
|
||||||
|
fi
|
||||||
|
alt_target="${YADM_BASE}/${target_base}"
|
||||||
|
|
||||||
|
if ! in_list "$alt_target" "${possible_alt_targets[@]}"; then
|
||||||
|
possible_alt_targets+=("$alt_target")
|
||||||
|
fi
|
||||||
|
|
||||||
|
score_file "$alt_source" "$alt_target"
|
||||||
done
|
done
|
||||||
|
|
||||||
local alt_linked=()
|
local alt_linked=()
|
||||||
|
|
||||||
alt_linking
|
alt_linking
|
||||||
remove_stale_links
|
remove_stale_links
|
||||||
report_invalid_alts
|
report_invalid_alts
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function report_invalid_alts() {
|
function report_invalid_alts() {
|
||||||
|
@ -662,7 +629,7 @@ function remove_stale_links() {
|
||||||
# if a possible alt IS linked, but it's source is not part of alt_linked,
|
# if a possible alt IS linked, but it's source is not part of alt_linked,
|
||||||
# remove it.
|
# remove it.
|
||||||
if readlink_available; then
|
if readlink_available; then
|
||||||
for stale_candidate in "${possible_alts[@]}"; do
|
for stale_candidate in "${possible_alt_targets[@]}"; do
|
||||||
if [ -L "$stale_candidate" ]; then
|
if [ -L "$stale_candidate" ]; then
|
||||||
src=$(readlink "$stale_candidate" 2>/dev/null)
|
src=$(readlink "$stale_candidate" 2>/dev/null)
|
||||||
if [ -n "$src" ]; then
|
if [ -n "$src" ]; then
|
||||||
|
@ -681,8 +648,8 @@ function set_local_alt_values() {
|
||||||
local -a all_classes
|
local -a all_classes
|
||||||
all_classes=$(config --get-all local.class)
|
all_classes=$(config --get-all local.class)
|
||||||
while IFS='' read -r class; do
|
while IFS='' read -r class; do
|
||||||
local_classes+=("$class")
|
local_classes+=("$class")
|
||||||
local_class="$class"
|
local_class="$class"
|
||||||
done <<< "$all_classes"
|
done <<< "$all_classes"
|
||||||
|
|
||||||
local_arch="$(config local.arch)"
|
local_arch="$(config local.arch)"
|
||||||
|
@ -712,50 +679,38 @@ function set_local_alt_values() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function alt_linking() {
|
function alt_linking() {
|
||||||
|
local -i index
|
||||||
|
for (( index = 0; index < ${#alt_targets[@]}; ++index )); do
|
||||||
|
local target="${alt_targets[$index]}"
|
||||||
|
local source="${alt_sources[$index]}"
|
||||||
|
local template_cmd="${alt_template_cmds[$index]}"
|
||||||
|
|
||||||
local alt_scores=()
|
if [[ -L "$target" ]]; then
|
||||||
local alt_targets=()
|
rm -f "$target"
|
||||||
local alt_sources=()
|
elif [[ -d "$target" ]]; then
|
||||||
local alt_template_cmds=()
|
echo "Skipping alt $source as $target is a directory"
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
assert_parent "$target"
|
||||||
|
fi
|
||||||
|
|
||||||
for alt_path in $(for tracked in "${tracked_files[@]}"; do printf "%s\n" "$tracked" "${tracked%/*}"; done | LC_ALL=C sort -u) "${ENCRYPT_INCLUDE_FILES[@]}"; do
|
if [[ -n "$template_cmd" ]]; then
|
||||||
alt_path="$YADM_BASE/$alt_path"
|
debug "Creating $target from template $source"
|
||||||
if [[ "$alt_path" =~ .\#\#. ]]; then
|
[[ -n "$loud" ]] && echo "Creating $target from template $source"
|
||||||
if [ -e "$alt_path" ] ; then
|
|
||||||
score_file "$alt_path"
|
"$template_cmd" "$source" "$target"
|
||||||
fi
|
elif [[ "$do_copy" -eq 1 ]]; then
|
||||||
|
debug "Copying $source to $target"
|
||||||
|
[[ -n "$loud" ]] && echo "Copying $source to $target"
|
||||||
|
|
||||||
|
cp -f "$source" "$target"
|
||||||
|
else
|
||||||
|
debug "Linking $source to $target"
|
||||||
|
[[ -n "$loud" ]] && echo "Linking $source to $target"
|
||||||
|
|
||||||
|
ln_relative "$source" "$target"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
for index in "${!alt_targets[@]}"; do
|
|
||||||
tgt="${alt_targets[$index]}"
|
|
||||||
src="${alt_sources[$index]}"
|
|
||||||
template_cmd="${alt_template_cmds[$index]}"
|
|
||||||
if [ -n "$template_cmd" ]; then
|
|
||||||
# a template is defined, process the template
|
|
||||||
debug "Creating $tgt from template $src"
|
|
||||||
[ -n "$loud" ] && echo "Creating $tgt from template $src"
|
|
||||||
# ensure the destination path exists
|
|
||||||
assert_parent "$tgt"
|
|
||||||
# remove any existing symlink before processing template
|
|
||||||
[ -L "$tgt" ] && rm -f "$tgt"
|
|
||||||
"$template_cmd" "$src" "$tgt"
|
|
||||||
elif [ -n "$src" ]; then
|
|
||||||
# a link source is defined, create symlink
|
|
||||||
debug "Linking $src to $tgt"
|
|
||||||
[ -n "$loud" ] && echo "Linking $src to $tgt"
|
|
||||||
# ensure the destination path exists
|
|
||||||
assert_parent "$tgt"
|
|
||||||
if [ "$do_copy" -eq 1 ]; then
|
|
||||||
# remove any existing symlink before copying
|
|
||||||
[ -L "$tgt" ] && rm -f "$tgt"
|
|
||||||
cp -f "$src" "$tgt"
|
|
||||||
else
|
|
||||||
ln_relative "$src" "$tgt"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ln_relative() {
|
function ln_relative() {
|
||||||
|
@ -765,7 +720,7 @@ function ln_relative() {
|
||||||
local rel_source
|
local rel_source
|
||||||
rel_source=$(relative_path "$(builtin_dirname "$target")" "$source")
|
rel_source=$(relative_path "$(builtin_dirname "$target")" "$source")
|
||||||
|
|
||||||
ln -nfs "$rel_source" "$target"
|
ln -fs "$rel_source" "$target"
|
||||||
alt_linked+=("$rel_source")
|
alt_linked+=("$rel_source")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
yadm.1
2
yadm.1
|
@ -595,7 +595,7 @@ If no "##default" version exists and no files have valid conditions, then no
|
||||||
link will be created.
|
link will be created.
|
||||||
|
|
||||||
Links are also created for directories named this way, as long as they have at
|
Links are also created for directories named this way, as long as they have at
|
||||||
least one yadm managed file within them (at the top level).
|
least one yadm managed file within them.
|
||||||
|
|
||||||
yadm will automatically create these links by default. This can be disabled
|
yadm will automatically create these links by default. This can be disabled
|
||||||
using the
|
using the
|
||||||
|
|
Loading…
Reference in a new issue