Skip to content

Commit 55acc45

Browse files
committed
Change handling of dirs with alt conditions
Instead of creating symlinks pointing at the directory, create individual symlinks for each file within the dir alternate (fixes #490). Also rework how stale symlinks are removed. Now a (stale) symlink will only be removed if it's pointing at a file that's an altnerate file (fixes #236).
1 parent 7eabaee commit 55acc45

6 files changed

+238
-228
lines changed

test/test_alt.py

+105-45
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ def test_alt_source(runner, paths, tracked, encrypt, exclude, yadm_alt):
4040
source_file_content = link_path + "##default"
4141
source_file = basepath.join(source_file_content)
4242
link_file = paths.work.join(link_path)
43+
if link_path == utils.ALT_DIR:
44+
source_file = source_file.join(utils.CONTAINED)
45+
link_file = link_file.join(utils.CONTAINED)
4346
if tracked or (encrypt and not exclude):
4447
assert link_file.islink()
4548
target = py.path.local(os.path.realpath(link_file))
46-
if target.isfile():
47-
assert link_file.read() == source_file_content
48-
assert str(source_file) in linked
49-
else:
50-
assert link_file.join(utils.CONTAINED).read() == source_file_content
51-
assert str(source_file) in linked
49+
assert target.isfile()
50+
assert link_file.read() == source_file_content
51+
assert str(source_file) in linked
5252
else:
5353
assert not link_file.exists()
5454
assert str(source_file) not in linked
@@ -73,6 +73,9 @@ def test_relative_link(runner, paths, yadm_alt):
7373
source_file_content = link_path + "##default"
7474
source_file = basepath.join(source_file_content)
7575
link_file = paths.work.join(link_path)
76+
if link_path == utils.ALT_DIR:
77+
source_file = source_file.join(utils.CONTAINED)
78+
link_file = link_file.join(utils.CONTAINED)
7679
link = link_file.readlink()
7780
relpath = os.path.relpath(source_file, start=os.path.dirname(link_file))
7881
assert link == relpath
@@ -128,15 +131,17 @@ def test_alt_conditions(runner, paths, tst_arch, tst_sys, tst_distro, tst_distro
128131
linked = utils.parse_alt_output(run.out)
129132

130133
for link_path in TEST_PATHS:
131-
source_file = link_path + suffix
132-
assert paths.work.join(link_path).islink()
133-
target = py.path.local(os.path.realpath(paths.work.join(link_path)))
134-
if target.isfile():
135-
assert paths.work.join(link_path).read() == source_file
136-
assert str(paths.work.join(source_file)) in linked
137-
else:
138-
assert paths.work.join(link_path).join(utils.CONTAINED).read() == source_file
139-
assert str(paths.work.join(source_file)) in linked
134+
source_file_content = link_path + suffix
135+
source_file = paths.work.join(source_file_content)
136+
link_file = paths.work.join(link_path)
137+
if link_path == utils.ALT_DIR:
138+
source_file = source_file.join(utils.CONTAINED)
139+
link_file = link_file.join(utils.CONTAINED)
140+
assert link_file.islink()
141+
target = py.path.local(os.path.realpath(link_file))
142+
assert target.isfile()
143+
assert link_file.read() == source_file_content
144+
assert str(source_file) in linked
140145

141146

142147
@pytest.mark.usefixtures("ds1_copy")
@@ -156,18 +161,23 @@ def test_alt_templates(runner, paths, kind, label):
156161
suffix = f"##{label}.{kind}"
157162
if kind is None:
158163
suffix = f"##{label}"
164+
159165
utils.create_alt_files(paths, suffix)
160166
run = runner([paths.pgm, "-Y", yadm_dir, "--yadm-data", yadm_data, "alt"])
161167
assert run.success
162168
assert run.err == ""
163169
created = utils.parse_alt_output(run.out, linked=False)
164170

165171
for created_path in TEST_PATHS:
166-
if created_path != utils.ALT_DIR:
167-
source_file = created_path + suffix
168-
assert paths.work.join(created_path).isfile()
169-
assert paths.work.join(created_path).read().strip() == source_file
170-
assert str(paths.work.join(source_file)) in created
172+
source_file_content = created_path + suffix
173+
source_file = paths.work.join(source_file_content)
174+
created_file = paths.work.join(created_path)
175+
if created_path == utils.ALT_DIR:
176+
source_file = source_file.join(utils.CONTAINED)
177+
created_file = created_file.join(utils.CONTAINED)
178+
assert created_file.isfile()
179+
assert created_file.read().strip() == source_file_content
180+
assert str(source_file) in created
171181

172182

173183
@pytest.mark.usefixtures("ds1_copy")
@@ -201,20 +211,22 @@ def test_auto_alt(runner, yadm_cmd, paths, autoalt):
201211
linked = utils.parse_alt_output(run.out)
202212

203213
for link_path in TEST_PATHS:
204-
source_file = link_path + "##default"
214+
source_file_content = link_path + "##default"
215+
source_file = paths.work.join(source_file_content)
216+
link_file = paths.work.join(link_path)
217+
if link_path == utils.ALT_DIR:
218+
source_file = source_file.join(utils.CONTAINED)
219+
link_file = link_file.join(utils.CONTAINED)
220+
205221
if autoalt == "false":
206-
assert not paths.work.join(link_path).exists()
222+
assert not link_file.exists()
207223
else:
208-
assert paths.work.join(link_path).islink()
209-
target = py.path.local(os.path.realpath(paths.work.join(link_path)))
210-
if target.isfile():
211-
assert paths.work.join(link_path).read() == source_file
212-
# no linking output when run via auto-alt
213-
assert str(paths.work.join(source_file)) not in linked
214-
else:
215-
assert paths.work.join(link_path).join(utils.CONTAINED).read() == source_file
216-
# no linking output when run via auto-alt
217-
assert str(paths.work.join(source_file)) not in linked
224+
assert link_file.islink()
225+
target = py.path.local(os.path.realpath(link_file))
226+
assert target.isfile()
227+
assert link_file.read() == source_file_content
228+
# no linking output when run via auto-alt
229+
assert str(source_file) not in linked
218230

219231

220232
@pytest.mark.usefixtures("ds1_copy")
@@ -236,6 +248,8 @@ def test_alt_exclude(runner, yadm_cmd, paths, autoexclude):
236248
status = run.out.split("\0")
237249

238250
for link_path in TEST_PATHS:
251+
if link_path == utils.ALT_DIR:
252+
link_path = f"{link_path}/{utils.CONTAINED}"
239253
flags = "??" if autoexclude == "false" else "!!"
240254
assert f"{flags} {link_path}" in status
241255

@@ -262,16 +276,18 @@ def test_stale_link_removal(runner, yadm_cmd, paths):
262276
linked = utils.parse_alt_output(run.out)
263277

264278
# assert the proper linking has occurred
265-
for stale_path in TEST_PATHS:
266-
source_file = stale_path + "##class." + tst_class
267-
assert paths.work.join(stale_path).islink()
268-
target = py.path.local(os.path.realpath(paths.work.join(stale_path)))
269-
if target.isfile():
270-
assert paths.work.join(stale_path).read() == source_file
271-
assert str(paths.work.join(source_file)) in linked
272-
else:
273-
assert paths.work.join(stale_path).join(utils.CONTAINED).read() == source_file
274-
assert str(paths.work.join(source_file)) in linked
279+
for link_path in TEST_PATHS:
280+
source_file_content = link_path + f"##class.{tst_class}"
281+
source_file = paths.work.join(source_file_content)
282+
link_file = paths.work.join(link_path)
283+
if link_path == utils.ALT_DIR:
284+
source_file = source_file.join(utils.CONTAINED)
285+
link_file = link_file.join(utils.CONTAINED)
286+
assert link_file.islink()
287+
target = py.path.local(os.path.realpath(link_file))
288+
assert target.isfile()
289+
assert link_file.read() == source_file_content
290+
assert str(source_file) in linked
275291

276292
# change the class so there are no valid alternates
277293
utils.set_local(paths, "class", "changedclass")
@@ -284,9 +300,53 @@ def test_stale_link_removal(runner, yadm_cmd, paths):
284300

285301
# assert the linking is removed
286302
for stale_path in TEST_PATHS:
287-
source_file = stale_path + "##class." + tst_class
288-
assert not paths.work.join(stale_path).exists()
289-
assert str(paths.work.join(source_file)) not in linked
303+
source_file_content = stale_path + f"##class.{tst_class}"
304+
source_file = paths.work.join(source_file_content)
305+
stale_file = paths.work.join(stale_path)
306+
if stale_path == utils.ALT_DIR:
307+
source_file = source_file.join(utils.CONTAINED)
308+
stale_file = stale_file.join(utils.CONTAINED)
309+
assert not stale_file.exists()
310+
assert str(source_file) not in linked
311+
312+
313+
@pytest.mark.usefixtures("ds1_copy")
314+
def test_legacy_dir_link_removal(runner, yadm_cmd, paths):
315+
"""Legacy link to alternative dir is removed
316+
317+
This test ensures that a legacy dir alternative (i.e. symlink to the dir
318+
itself) is converted to indiividual links.
319+
"""
320+
321+
utils.create_alt_files(paths, "##default")
322+
323+
# Create legacy link
324+
link_dir = paths.work.join(utils.ALT_DIR)
325+
link_dir.mksymlinkto(link_dir.basename + "##default")
326+
assert link_dir.islink()
327+
328+
# run alt to trigger linking
329+
run = runner(yadm_cmd("alt"))
330+
assert run.success
331+
assert run.err == ""
332+
linked = utils.parse_alt_output(run.out)
333+
334+
# assert legacy link is removed
335+
assert not link_dir.islink()
336+
337+
# assert the proper linking has occurred
338+
for link_path in TEST_PATHS:
339+
source_file_content = link_path + "##default"
340+
source_file = paths.work.join(source_file_content)
341+
link_file = paths.work.join(link_path)
342+
if link_path == utils.ALT_DIR:
343+
source_file = source_file.join(utils.CONTAINED)
344+
link_file = link_file.join(utils.CONTAINED)
345+
assert link_file.islink()
346+
target = py.path.local(os.path.realpath(link_file))
347+
assert target.isfile()
348+
assert link_file.read() == source_file_content
349+
assert str(source_file) in linked
290350

291351

292352
@pytest.mark.usefixtures("ds1_repo_copy")

test/test_unit_remove_stale_links.py

-39
This file was deleted.

0 commit comments

Comments
 (0)