|
2 | 2 | page for "science" sites, to allow those sites to load a tutorial
|
3 | 3 | document on startup.
|
4 | 4 |
|
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. |
9 | 9 |
|
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. |
12 | 13 |
|
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. |
16 | 17 | """
|
17 | 18 |
|
18 | 19 | import json
|
| 20 | +import shutil |
19 | 21 | from typing import Any, Self
|
20 | 22 |
|
21 | 23 | from .exceptions import (
|
@@ -52,31 +54,25 @@ def _precheck(self) -> None:
|
52 | 54 | )
|
53 | 55 |
|
54 | 56 | 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) |
57 | 58 |
|
58 |
| - def _link_files(self) -> None: |
| 59 | + def _copy_files(self) -> None: |
59 | 60 | for src in self._source_files:
|
60 | 61 | dest = self._dest_dir / src.name
|
61 | 62 | 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. |
68 | 69 | 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)) |
73 | 72 | else:
|
74 | 73 | # It's...a device, or a named pipe, or ... something?
|
75 | 74 | 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) |
80 | 76 |
|
81 | 77 | def _edit_settings(self) -> None:
|
82 | 78 | settings_dir = (
|
@@ -109,7 +105,7 @@ def go(self) -> None:
|
109 | 105 | """Do the deed."""
|
110 | 106 | self._precheck()
|
111 | 107 | self._provision_tutorial_directories()
|
112 |
| - self._link_files() |
| 108 | + self._copy_files() |
113 | 109 | self._edit_settings()
|
114 | 110 |
|
115 | 111 | @classmethod
|
|
0 commit comments