Skip to content

Commit

Permalink
Allow storing alternates elsewhere (yadm-dev#90)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
TheLocehiliosan committed Oct 12, 2019
1 parent aeb6a54 commit 4ea3ed9
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 33 deletions.
54 changes: 36 additions & 18 deletions test/test_alt.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


@pytest.mark.usefixtures('ds1_copy')
@pytest.mark.parametrize('yadm_alt', [True, False], ids=['alt', 'worktree'])
@pytest.mark.parametrize(
'tracked,encrypt,exclude', [
(False, False, False),
Expand All @@ -17,32 +18,39 @@
(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')
Expand All @@ -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'
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
35 changes: 21 additions & 14 deletions test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,28 @@ 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
appended to two standard file paths. Particulars of the file creation and
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
Expand All @@ -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):
Expand All @@ -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]

Expand All @@ -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 changes: 7 additions & 0 deletions yadm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ YADM_ENCRYPT="encrypt"
YADM_ARCHIVE="files.gpg"
YADM_BOOTSTRAP="bootstrap"
YADM_HOOKS="hooks"
YADM_ALT="alt"

HOOK_COMMAND=""
FULL_COMMAND=""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion yadm.1
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 4ea3ed9

Please sign in to comment.