Skip to content

Commit 4bedaaa

Browse files
authored
Merge pull request #83 from lsst-sqre/tickets/DM-49959B
tickets/DM-49959B: landing page fixes
2 parents 75a0276 + 9dd18f7 commit 4bedaaa

File tree

3 files changed

+47
-42
lines changed

3 files changed

+47
-42
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!-- Delete the sections that don't apply -->
2+
3+
### Bug fixes
4+
5+
- Make landing page files files rather than symlinks.
6+
- Don't create extraneous directories.

src/lsst/rsp/startup/services/landing_page/provisioner.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22
page for "science" sites, to allow those sites to load a tutorial
33
document on startup.
44
5-
It has two phases: first, it creates links to the landing page and the
6-
files that page needs, and second, if the user default for opening the
7-
file is not the Markdown Viewer already, it writes out configuration
8-
for that.
5+
It has two phases: first, it creates copies of the landing page and
6+
supporting files, and second, if the user default for opening the file
7+
is not the Markdown Viewer already, it writes out configuration for
8+
that.
99
10-
The links need to be somewhere the lab container documentManager can
11-
access then, therefore inside the homedir and not hidden dot files.
10+
The files must be somewhere that the Notebook container can open them, and
11+
must be writeable files (not symlinks to a read-only target) if the
12+
Save-All or Save-And-Quite functionality is to work.
1213
13-
It is expected to be running in the context of the current user, as
14-
part of an initContainer running after the user home directories are
15-
provisioned, but before the user lab container begins to start.
14+
The tool is expected to be running in the context of the current user,
15+
as part of an initContainer running after the user home directories
16+
are provisioned, but before the user lab container begins to start.
1617
"""
1718

1819
import json
20+
import shutil
1921
from typing import Any, Self
2022

2123
from .exceptions import (
@@ -52,31 +54,25 @@ def _precheck(self) -> None:
5254
)
5355

5456
def _provision_tutorial_directories(self) -> None:
55-
t_dir = self._dest_dir / "notebooks" / "tutorials"
56-
t_dir.mkdir(mode=0o755, exist_ok=True, parents=True)
57+
self._dest_dir.mkdir(mode=0o755, exist_ok=True, parents=True)
5758

58-
def _link_files(self) -> None:
59+
def _copy_files(self) -> None:
5960
for src in self._source_files:
6061
dest = self._dest_dir / src.name
6162
if dest.exists(follow_symlinks=False):
62-
if dest.is_dir():
63-
raise DestinationIsDirectoryError(str(dest))
64-
if dest.is_file():
65-
# Remediation from a past attempt. If it's a file,
66-
# it shouldn't be, it should be a symlink. Remove
67-
# and recreate.
63+
if dest.is_symlink() or dest.is_file():
64+
# Turns out a symlink to a read-only file isn't going
65+
# to work.
66+
#
67+
# Remove and recopy. It's probably imperceptibly slower
68+
# than trying to be clever about it.
6869
dest.unlink()
69-
elif dest.is_symlink():
70-
current_target = dest.readlink()
71-
if current_target != src:
72-
dest.unlink()
70+
elif dest.is_dir():
71+
raise DestinationIsDirectoryError(str(dest))
7372
else:
7473
# It's...a device, or a named pipe, or ... something?
7574
raise DestinationError(str(dest))
76-
# If we get here and it still exists, it's a symlink pointing
77-
# to the right target, so we just leave it alone.
78-
if not dest.exists(follow_symlinks=False):
79-
dest.symlink_to(src)
75+
shutil.copy(src, dest)
8076

8177
def _edit_settings(self) -> None:
8278
settings_dir = (
@@ -109,7 +105,7 @@ def go(self) -> None:
109105
"""Do the deed."""
110106
self._precheck()
111107
self._provision_tutorial_directories()
112-
self._link_files()
108+
self._copy_files()
113109
self._edit_settings()
114110

115111
@classmethod

tests/provisioner_test.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ def test_provisioner_basic() -> None:
3838
pr.go()
3939

4040
for outf in outfiles:
41-
assert outf.is_symlink()
41+
assert outf.is_file()
42+
43+
dest_files = list(pr._dest_dir.glob("*"))
44+
assert len(dest_files) == 1
4245

4346
assert settings.is_file()
4447
s_obj = json.loads(settings.read_text())
@@ -77,8 +80,7 @@ def test_bad_destination() -> None:
7780
if destfile.exists():
7881
# I mean technically you don't HAVE to run all the tests in order.
7982
# So you might not already have the file here.
80-
assert destfile.is_symlink()
81-
assert destfile.readlink() == source_file
83+
assert destfile.is_file()
8284
destfile.unlink()
8385

8486
# Directory
@@ -93,18 +95,19 @@ def test_bad_destination() -> None:
9395
pr.go()
9496
destfile.unlink()
9597

96-
# File
97-
destfile.write_text("!dlroW olleH\n")
98-
assert destfile.is_file()
99-
pr.go()
100-
assert destfile.is_symlink()
101-
assert destfile.readlink() == source_file
102-
destfile.unlink()
103-
104-
# Link, but wrong
98+
# Symlink
10599
destfile.symlink_to(Path("broken_link"))
106100
assert destfile.is_symlink()
107-
assert destfile.readlink() != source_file
108101
pr.go()
109-
assert destfile.is_symlink()
110-
assert destfile.readlink() == source_file
102+
assert destfile.is_file()
103+
104+
# File requiring overwrite.
105+
bad_text = "!dlroW olleH\n"
106+
destfile.write_text(bad_text)
107+
source_text = source_file.read_text()
108+
assert source_text != bad_text
109+
assert destfile.is_file()
110+
pr.go()
111+
assert destfile.is_file()
112+
assert destfile.read_text() == source_text
113+
destfile.unlink()

0 commit comments

Comments
 (0)