Allow storing alternates elsewhere (#90)
This change allows alternates to be stored in "$YADM_DIR/alt". The correct path within the work tree will be symlinked. Storing alternates within the work tree is still allowed. Both locations will be considered when choosing an appropriate alternate file.
This commit is contained in:
parent
aeb6a54ad7
commit
4ea3ed9e2a
4 changed files with 76 additions and 33 deletions
|
@ -9,6 +9,7 @@ TEST_PATHS = [utils.ALT_FILE1, utils.ALT_FILE2, utils.ALT_DIR]
|
|||
|
||||
|
||||
@pytest.mark.usefixtures('ds1_copy')
|
||||
@pytest.mark.parametrize('yadm_alt', [True, False], ids=['alt', 'worktree'])
|
||||
@pytest.mark.parametrize(
|
||||
'tracked,encrypt,exclude', [
|
||||
(False, False, False),
|
||||
|
@ -17,32 +18,39 @@ TEST_PATHS = [utils.ALT_FILE1, utils.ALT_FILE2, utils.ALT_DIR]
|
|||
(False, True, True),
|
||||
], ids=['untracked', 'tracked', 'encrypted', 'excluded'])
|
||||
def test_alt_source(
|
||||
runner, yadm_y, paths,
|
||||
tracked, encrypt, exclude):
|
||||
runner, paths,
|
||||
tracked, encrypt, exclude,
|
||||
yadm_alt):
|
||||
"""Test yadm alt operates on all expected sources of alternates"""
|
||||
yadm_dir = setup_standard_yadm_dir(paths)
|
||||
|
||||
utils.create_alt_files(
|
||||
paths, '##default', tracked=tracked, encrypt=encrypt, exclude=exclude)
|
||||
run = runner(yadm_y('alt'))
|
||||
paths, '##default', tracked=tracked, encrypt=encrypt, exclude=exclude,
|
||||
yadm_alt=yadm_alt, yadm_dir=yadm_dir)
|
||||
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
||||
assert run.success
|
||||
assert run.err == ''
|
||||
linked = utils.parse_alt_output(run.out)
|
||||
|
||||
basepath = yadm_dir.join('alt') if yadm_alt else paths.work
|
||||
|
||||
for link_path in TEST_PATHS:
|
||||
source_file = link_path + '##default'
|
||||
source_file_content = link_path + '##default'
|
||||
source_file = basepath.join(source_file_content)
|
||||
link_file = paths.work.join(link_path)
|
||||
if tracked or (encrypt and not exclude):
|
||||
assert paths.work.join(link_path).islink()
|
||||
target = py.path.local(paths.work.join(link_path).readlink())
|
||||
assert link_file.islink()
|
||||
target = py.path.local(link_file.readlink())
|
||||
if target.isfile():
|
||||
assert paths.work.join(link_path).read() == source_file
|
||||
assert str(paths.work.join(source_file)) in linked
|
||||
assert link_file.read() == source_file_content
|
||||
assert str(source_file) in linked
|
||||
else:
|
||||
assert paths.work.join(link_path).join(
|
||||
utils.CONTAINED).read() == source_file
|
||||
assert str(paths.work.join(source_file)) in linked
|
||||
assert link_file.join(
|
||||
utils.CONTAINED).read() == source_file_content
|
||||
assert str(source_file) in linked
|
||||
else:
|
||||
assert not paths.work.join(link_path).exists()
|
||||
assert str(paths.work.join(source_file)) not in linked
|
||||
assert not link_file.exists()
|
||||
assert str(source_file) not in linked
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('ds1_copy')
|
||||
|
@ -55,9 +63,10 @@ def test_alt_source(
|
|||
'##u.$tst_user', '##user.$tst_user',
|
||||
])
|
||||
def test_alt_conditions(
|
||||
runner, yadm_y, paths,
|
||||
runner, paths,
|
||||
tst_sys, tst_distro, tst_host, tst_user, suffix):
|
||||
"""Test conditions supported by yadm alt"""
|
||||
yadm_dir = setup_standard_yadm_dir(paths)
|
||||
|
||||
# set the class
|
||||
tst_class = 'testclass'
|
||||
|
@ -72,7 +81,7 @@ def test_alt_conditions(
|
|||
)
|
||||
|
||||
utils.create_alt_files(paths, suffix)
|
||||
run = runner(yadm_y('alt'))
|
||||
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
||||
assert run.success
|
||||
assert run.err == ''
|
||||
linked = utils.parse_alt_output(run.out)
|
||||
|
@ -94,12 +103,13 @@ def test_alt_conditions(
|
|||
@pytest.mark.parametrize('kind', ['builtin', '', 'envtpl', 'j2cli', 'j2'])
|
||||
@pytest.mark.parametrize('label', ['t', 'template', 'yadm', ])
|
||||
def test_alt_templates(
|
||||
runner, yadm_y, paths, kind, label):
|
||||
runner, paths, kind, label):
|
||||
"""Test templates supported by yadm alt"""
|
||||
yadm_dir = setup_standard_yadm_dir(paths)
|
||||
|
||||
suffix = f'##{label}.{kind}'
|
||||
utils.create_alt_files(paths, suffix)
|
||||
run = runner(yadm_y('alt'))
|
||||
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
||||
assert run.success
|
||||
assert run.err == ''
|
||||
created = utils.parse_alt_output(run.out, linked=False)
|
||||
|
@ -220,3 +230,11 @@ def test_template_overwrite_symlink(runner, yadm_y, paths, tst_sys):
|
|||
assert not link.islink()
|
||||
assert target.read().strip() == 'target'
|
||||
assert link.read().strip() == 'test-data'
|
||||
|
||||
|
||||
def setup_standard_yadm_dir(paths):
|
||||
"""Configure a yadm home within the work tree"""
|
||||
std_yadm_dir = paths.work.mkdir('.config').mkdir('yadm')
|
||||
std_yadm_dir.join('repo.git').mksymlinkto(paths.repo, absolute=1)
|
||||
std_yadm_dir.join('encrypt').mksymlinkto(paths.encrypt, absolute=1)
|
||||
return std_yadm_dir
|
||||
|
|
|
@ -32,7 +32,8 @@ def set_local(paths, variable, value):
|
|||
def create_alt_files(paths, suffix,
|
||||
preserve=False, tracked=True,
|
||||
encrypt=False, exclude=False,
|
||||
content=None, includefile=False):
|
||||
content=None, includefile=False,
|
||||
yadm_alt=False, yadm_dir=None):
|
||||
"""Create new files, and add to the repo
|
||||
|
||||
This is used for testing alternate files. In each case, a suffix is
|
||||
|
@ -40,17 +41,19 @@ def create_alt_files(paths, suffix,
|
|||
repo handling are dependent upon the function arguments.
|
||||
"""
|
||||
|
||||
basepath = yadm_dir.join('alt') if yadm_alt else paths.work
|
||||
|
||||
if not preserve:
|
||||
for remove_path in (ALT_FILE1, ALT_FILE2, ALT_DIR):
|
||||
if paths.work.join(remove_path).exists():
|
||||
paths.work.join(remove_path).remove(rec=1, ignore_errors=True)
|
||||
assert not paths.work.join(remove_path).exists()
|
||||
if basepath.join(remove_path).exists():
|
||||
basepath.join(remove_path).remove(rec=1, ignore_errors=True)
|
||||
assert not basepath.join(remove_path).exists()
|
||||
|
||||
new_file1 = paths.work.join(ALT_FILE1 + suffix)
|
||||
new_file1 = basepath.join(ALT_FILE1 + suffix)
|
||||
new_file1.write(ALT_FILE1 + suffix, ensure=True)
|
||||
new_file2 = paths.work.join(ALT_FILE2 + suffix)
|
||||
new_file2 = basepath.join(ALT_FILE2 + suffix)
|
||||
new_file2.write(ALT_FILE2 + suffix, ensure=True)
|
||||
new_dir = paths.work.join(ALT_DIR + suffix).join(CONTAINED)
|
||||
new_dir = basepath.join(ALT_DIR + suffix).join(CONTAINED)
|
||||
new_dir.write(ALT_DIR + suffix, ensure=True)
|
||||
|
||||
# Do not test directory support for jinja alternates
|
||||
|
@ -65,9 +68,11 @@ def create_alt_files(paths, suffix,
|
|||
test_path.write('\n' + content, mode='a', ensure=True)
|
||||
assert test_path.exists()
|
||||
|
||||
_create_includefiles(includefile, paths, test_paths)
|
||||
_create_includefiles(includefile, test_paths, basepath)
|
||||
_create_tracked(tracked, test_paths, paths)
|
||||
_create_encrypt(encrypt, test_names, suffix, paths, exclude)
|
||||
|
||||
prefix = '.config/yadm/alt/' if yadm_alt else ''
|
||||
_create_encrypt(encrypt, test_names, suffix, paths, exclude, prefix)
|
||||
|
||||
|
||||
def parse_alt_output(output, linked=True):
|
||||
|
@ -86,10 +91,10 @@ def parse_alt_output(output, linked=True):
|
|||
return parsed_list.values()
|
||||
|
||||
|
||||
def _create_includefiles(includefile, paths, test_paths):
|
||||
def _create_includefiles(includefile, test_paths, basepath):
|
||||
if includefile:
|
||||
for dpath in INCLUDE_DIRS:
|
||||
incfile = paths.work.join(dpath + '/' + INCLUDE_FILE)
|
||||
incfile = basepath.join(dpath + '/' + INCLUDE_FILE)
|
||||
incfile.write(INCLUDE_CONTENT, ensure=True)
|
||||
test_paths += [incfile]
|
||||
|
||||
|
@ -101,9 +106,11 @@ def _create_tracked(tracked, test_paths, paths):
|
|||
os.system(f'GIT_DIR={str(paths.repo)} git commit -m "Add test files"')
|
||||
|
||||
|
||||
def _create_encrypt(encrypt, test_names, suffix, paths, exclude):
|
||||
def _create_encrypt(encrypt, test_names, suffix, paths, exclude, prefix):
|
||||
if encrypt:
|
||||
for encrypt_name in test_names:
|
||||
paths.encrypt.write(f'{encrypt_name + suffix}\n', mode='a')
|
||||
paths.encrypt.write(
|
||||
f'{prefix + encrypt_name + suffix}\n', mode='a')
|
||||
if exclude:
|
||||
paths.encrypt.write(f'!{encrypt_name + suffix}\n', mode='a')
|
||||
paths.encrypt.write(
|
||||
f'!{prefix + encrypt_name + suffix}\n', mode='a')
|
||||
|
|
7
yadm
7
yadm
|
@ -33,6 +33,7 @@ YADM_ENCRYPT="encrypt"
|
|||
YADM_ARCHIVE="files.gpg"
|
||||
YADM_BOOTSTRAP="bootstrap"
|
||||
YADM_HOOKS="hooks"
|
||||
YADM_ALT="alt"
|
||||
|
||||
HOOK_COMMAND=""
|
||||
FULL_COMMAND=""
|
||||
|
@ -137,6 +138,11 @@ function score_file() {
|
|||
target="$1"
|
||||
filename="${target%%##*}"
|
||||
conditions="${target#*##}"
|
||||
|
||||
if [ "${filename#$YADM_ALT/}" != "${filename}" ]; then
|
||||
filename="${YADM_WORK}/${filename#$YADM_ALT/}"
|
||||
fi
|
||||
|
||||
score=0
|
||||
IFS=',' read -ra fields <<< "$conditions"
|
||||
for field in "${fields[@]}"; do
|
||||
|
@ -1223,6 +1229,7 @@ function configure_paths() {
|
|||
YADM_ARCHIVE="$YADM_DIR/$YADM_ARCHIVE"
|
||||
YADM_BOOTSTRAP="$YADM_DIR/$YADM_BOOTSTRAP"
|
||||
YADM_HOOKS="$YADM_DIR/$YADM_HOOKS"
|
||||
YADM_ALT="$YADM_DIR/$YADM_ALT"
|
||||
|
||||
# independent overrides for paths
|
||||
if [ -n "$YADM_OVERRIDE_REPO" ]; then
|
||||
|
|
13
yadm.1
13
yadm.1
|
@ -478,6 +478,12 @@ condition. The number of conditions is the next largest factor in scoring.
|
|||
Files with more conditions will always be favored. Any invalid condition will
|
||||
disqualify that file completely.
|
||||
|
||||
If you don't care to have all versions of alternates stored in the same
|
||||
directory as the generated symlink, you can place them in the
|
||||
.I $HOME/.config/yadm/alt
|
||||
directory. The generated symlink or processed template will be created using
|
||||
same relative path.
|
||||
|
||||
Alternate linking may best be demonstrated by example. Assume the following
|
||||
files are managed by yadm's repository:
|
||||
|
||||
|
@ -771,7 +777,7 @@ Otherwise it will be
|
|||
.IR "$HOME/.config/yadm" .
|
||||
|
||||
The following are the default paths yadm uses for its own data.
|
||||
These paths can be altered using universal options.
|
||||
Most of these paths can be altered using universal options.
|
||||
See the OPTIONS section for details.
|
||||
.TP
|
||||
.I $HOME/.config/yadm
|
||||
|
@ -781,6 +787,11 @@ directory.
|
|||
.I $YADM_DIR/config
|
||||
Configuration file for yadm.
|
||||
.TP
|
||||
.I $YADM_DIR/alt
|
||||
This is a directory to keep "alternate files" without having them side-by-side
|
||||
with the resulting symlink or processed template. Alternate files placed in
|
||||
this directory will be created relative to $HOME instead.
|
||||
.TP
|
||||
.I $YADM_DIR/repo.git
|
||||
Git repository used by yadm.
|
||||
.TP
|
||||
|
|
Loading…
Reference in a new issue