Skip to content

Commit 102ba5d

Browse files
Preserve file mode of template (yadm-dev#193)
Any processed templates will inherit the file mode of the source template.
1 parent 6654e29 commit 102ba5d

5 files changed

+120
-4
lines changed

test/test_unit_copy_perms.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Unit tests: copy_perms"""
2+
import os
3+
import pytest
4+
5+
OCTAL = '7654'
6+
NON_OCTAL = '9876'
7+
8+
9+
@pytest.mark.parametrize(
10+
'stat_broken', [True, False], ids=['normal', 'stat broken'])
11+
def test_copy_perms(runner, yadm, tmpdir, stat_broken):
12+
"""Test function copy_perms"""
13+
src_mode = 0o754
14+
dst_mode = 0o644
15+
source = tmpdir.join('source')
16+
source.write('test', ensure=True)
17+
source.chmod(src_mode)
18+
19+
dest = tmpdir.join('dest')
20+
dest.write('test', ensure=True)
21+
dest.chmod(dst_mode)
22+
23+
override_stat = ''
24+
if stat_broken:
25+
override_stat = 'function stat() { echo broken; }'
26+
script = f"""
27+
YADM_TEST=1 source {yadm}
28+
{override_stat}
29+
copy_perms "{source}" "{dest}"
30+
"""
31+
run = runner(command=['bash'], inp=script)
32+
assert run.success
33+
assert run.err == ''
34+
assert run.out == ''
35+
expected = dst_mode if stat_broken else src_mode
36+
assert oct(os.stat(dest).st_mode)[-3:] == oct(expected)[-3:]
37+
38+
39+
@pytest.mark.parametrize(
40+
'stat_output', [OCTAL, NON_OCTAL], ids=['octal', 'non-octal'])
41+
def test_get_mode(runner, yadm, stat_output):
42+
"""Test function get_mode"""
43+
script = f"""
44+
YADM_TEST=1 source {yadm}
45+
function stat() {{ echo {stat_output}; }}
46+
mode=$(get_mode abc)
47+
echo "MODE:$mode"
48+
"""
49+
run = runner(command=['bash'], inp=script)
50+
assert run.success
51+
assert run.err == ''
52+
expected = OCTAL if stat_output == OCTAL else ""
53+
assert f'MODE:{expected}\n' in run.out

test/test_unit_template_default.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
"""Unit tests: template_default"""
2+
import os
3+
4+
FILE_MODE = 0o754
25

36
# these values are also testing the handling of bizarre characters
47
LOCAL_CLASS = "default_Test+@-!^Class"
@@ -91,6 +94,7 @@ def test_template_default(runner, yadm, tmpdir):
9194

9295
input_file = tmpdir.join('input')
9396
input_file.write(TEMPLATE, ensure=True)
97+
input_file.chmod(FILE_MODE)
9498
output_file = tmpdir.join('output')
9599

96100
script = f"""
@@ -107,13 +111,15 @@ def test_template_default(runner, yadm, tmpdir):
107111
assert run.success
108112
assert run.err == ''
109113
assert output_file.read() == EXPECTED
114+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
110115

111116

112117
def test_source(runner, yadm, tmpdir):
113118
"""Test yadm.source"""
114119

115120
input_file = tmpdir.join('input')
116121
input_file.write('{{yadm.source}}', ensure=True)
122+
input_file.chmod(FILE_MODE)
117123
output_file = tmpdir.join('output')
118124

119125
script = f"""
@@ -125,3 +131,4 @@ def test_source(runner, yadm, tmpdir):
125131
assert run.success
126132
assert run.err == ''
127133
assert output_file.read().strip() == str(input_file)
134+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode

test/test_unit_template_esh.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
"""Unit tests: template_esh"""
2+
import os
3+
4+
FILE_MODE = 0o754
25

36
LOCAL_CLASS = "esh_Test+@-!^Class"
47
LOCAL_SYSTEM = "esh_Test+@-!^System"
@@ -80,6 +83,7 @@ def test_template_esh(runner, yadm, tmpdir):
8083

8184
input_file = tmpdir.join('input')
8285
input_file.write(TEMPLATE, ensure=True)
86+
input_file.chmod(FILE_MODE)
8387
output_file = tmpdir.join('output')
8488

8589
script = f"""
@@ -95,13 +99,15 @@ def test_template_esh(runner, yadm, tmpdir):
9599
assert run.success
96100
assert run.err == ''
97101
assert output_file.read().strip() == str(EXPECTED).strip()
102+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
98103

99104

100105
def test_source(runner, yadm, tmpdir):
101106
"""Test YADM_SOURCE"""
102107

103108
input_file = tmpdir.join('input')
104109
input_file.write('<%= $YADM_SOURCE %>', ensure=True)
110+
input_file.chmod(FILE_MODE)
105111
output_file = tmpdir.join('output')
106112

107113
script = f"""
@@ -112,3 +118,4 @@ def test_source(runner, yadm, tmpdir):
112118
assert run.success
113119
assert run.err == ''
114120
assert output_file.read().strip() == str(input_file)
121+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode

test/test_unit_template_j2.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"""Unit tests: template_j2cli & template_envtpl"""
2+
import os
23
import pytest
34

5+
FILE_MODE = 0o754
6+
47
LOCAL_CLASS = "j2_Test+@-!^Class"
58
LOCAL_SYSTEM = "j2_Test+@-!^System"
69
LOCAL_HOST = "j2_Test+@-!^Host"
@@ -82,6 +85,7 @@ def test_template_j2(runner, yadm, tmpdir, processor):
8285

8386
input_file = tmpdir.join('input')
8487
input_file.write(TEMPLATE, ensure=True)
88+
input_file.chmod(FILE_MODE)
8589
output_file = tmpdir.join('output')
8690

8791
script = f"""
@@ -97,6 +101,7 @@ def test_template_j2(runner, yadm, tmpdir, processor):
97101
assert run.success
98102
assert run.err == ''
99103
assert output_file.read() == EXPECTED
104+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
100105

101106

102107
@pytest.mark.parametrize('processor', ('j2cli', 'envtpl'))
@@ -105,6 +110,7 @@ def test_source(runner, yadm, tmpdir, processor):
105110

106111
input_file = tmpdir.join('input')
107112
input_file.write('{{YADM_SOURCE}}', ensure=True)
113+
input_file.chmod(FILE_MODE)
108114
output_file = tmpdir.join('output')
109115

110116
script = f"""
@@ -115,3 +121,4 @@ def test_source(runner, yadm, tmpdir, processor):
115121
assert run.success
116122
assert run.err == ''
117123
assert output_file.read().strip() == str(input_file)
124+
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode

yadm

+46-4
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,11 @@ EOF
394394
-v source="$input" \
395395
"$awk_pgm" \
396396
"$input" > "$temp_file"
397-
[ -f "$temp_file" ] && mv -f "$temp_file" "$output"
397+
398+
if [ -f "$temp_file" ] ; then
399+
copy_perms "$input" "$temp_file"
400+
mv -f "$temp_file" "$output"
401+
fi
398402
}
399403

400404
function template_j2cli() {
@@ -409,7 +413,11 @@ function template_j2cli() {
409413
YADM_DISTRO="$local_distro" \
410414
YADM_SOURCE="$input" \
411415
"$J2CLI_PROGRAM" "$input" -o "$temp_file"
412-
[ -f "$temp_file" ] && mv -f "$temp_file" "$output"
416+
417+
if [ -f "$temp_file" ] ; then
418+
copy_perms "$input" "$temp_file"
419+
mv -f "$temp_file" "$output"
420+
fi
413421
}
414422

415423
function template_envtpl() {
@@ -424,7 +432,11 @@ function template_envtpl() {
424432
YADM_DISTRO="$local_distro" \
425433
YADM_SOURCE="$input" \
426434
"$ENVTPL_PROGRAM" --keep-template "$input" -o "$temp_file"
427-
[ -f "$temp_file" ] && mv -f "$temp_file" "$output"
435+
436+
if [ -f "$temp_file" ] ; then
437+
copy_perms "$input" "$temp_file"
438+
mv -f "$temp_file" "$output"
439+
fi
428440
}
429441

430442
function template_esh() {
@@ -440,7 +452,10 @@ function template_esh() {
440452
YADM_DISTRO="$local_distro" \
441453
YADM_SOURCE="$input"
442454

443-
[ -f "$temp_file" ] && mv -f "$temp_file" "$output"
455+
if [ -f "$temp_file" ] ; then
456+
copy_perms "$input" "$temp_file"
457+
mv -f "$temp_file" "$output"
458+
fi
444459
}
445460

446461
# ****** yadm Commands ******
@@ -1908,6 +1923,33 @@ function join_string {
19081923
printf "%s" "${*:2}"
19091924
}
19101925

1926+
function get_mode {
1927+
local filename="$1"
1928+
local mode
1929+
1930+
# most *nixes
1931+
mode=$(stat -c '%a' "$filename" 2>/dev/null)
1932+
if [ -z "$mode" ] ; then
1933+
# BSD-style
1934+
mode=$(stat -f '%A' "$filename" 2>/dev/null)
1935+
fi
1936+
1937+
# only accept results if they are octal
1938+
if [[ ! $mode =~ ^[0-7]+$ ]] ; then
1939+
mode=""
1940+
fi
1941+
1942+
echo "$mode"
1943+
}
1944+
1945+
function copy_perms {
1946+
local source="$1"
1947+
local dest="$2"
1948+
mode=$(get_mode "$source")
1949+
[ -n "$mode" ] && chmod "$mode" "$dest"
1950+
return 0
1951+
}
1952+
19111953
# ****** Prerequisites Functions ******
19121954

19131955
function require_archive() {

0 commit comments

Comments
 (0)