mirror of
https://github.com/mkdocs/mkdocs.git
synced 2026-03-27 09:58:31 +07:00
Restore the ability to watch files through relative symlinks
Restore the ability to watch files through relative symlinks (i.e. symlinks that have a non-absolute path as the target) This was not fully fixed in #2427. Switch from os.path.realpath to pathlib.Path.resolve
This commit is contained in:
@@ -101,29 +101,26 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
|
||||
|
||||
def schedule(path):
|
||||
seen.add(path)
|
||||
if os.path.isfile(path):
|
||||
if path.is_file():
|
||||
# Watchdog doesn't support watching files, so watch its directory and filter by path
|
||||
handler = watchdog.events.FileSystemEventHandler()
|
||||
handler.on_any_event = lambda event: callback(event, allowed_path=path)
|
||||
handler.on_any_event = lambda event: callback(event, allowed_path=os.fspath(path))
|
||||
|
||||
parent = os.path.dirname(path)
|
||||
parent = path.parent
|
||||
log.debug(f"Watching file '{path}' through directory '{parent}'")
|
||||
self.observer.schedule(handler, parent)
|
||||
else:
|
||||
log.debug(f"Watching directory '{path}'")
|
||||
self.observer.schedule(dir_handler, path, recursive=recursive)
|
||||
|
||||
schedule(os.path.realpath(path))
|
||||
schedule(pathlib.Path(path).resolve())
|
||||
|
||||
def watch_symlink_targets(path_obj): # path is os.DirEntry or pathlib.Path
|
||||
if path_obj.is_symlink():
|
||||
# The extra `readlink` is needed due to https://bugs.python.org/issue9949
|
||||
target = os.path.realpath(os.readlink(os.fspath(path_obj)))
|
||||
if target in seen or not os.path.exists(target):
|
||||
path_obj = pathlib.Path(path_obj).resolve()
|
||||
if path_obj in seen or not path_obj.exists():
|
||||
return
|
||||
schedule(target)
|
||||
|
||||
path_obj = pathlib.Path(target)
|
||||
schedule(path_obj)
|
||||
|
||||
if path_obj.is_dir() and recursive:
|
||||
with os.scandir(os.fspath(path_obj)) as scan:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import contextlib
|
||||
import email
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -496,6 +497,28 @@ class BuildTests(unittest.TestCase):
|
||||
Path(tmp_dir, "file_dest_unused.md").write_text("edited")
|
||||
self.assertFalse(started_building.wait(timeout=0.2))
|
||||
|
||||
@tempdir(prefix="site_dir")
|
||||
@tempdir(["docs/unused.md", "README.md"], prefix="origin_dir")
|
||||
def test_watches_through_relative_symlinks(self, origin_dir, site_dir):
|
||||
docs_dir = Path(origin_dir, "docs")
|
||||
old_cwd = os.getcwd()
|
||||
os.chdir(docs_dir)
|
||||
try:
|
||||
Path(docs_dir, "README.md").symlink_to(Path("..", "README.md"))
|
||||
except NotImplementedError: # PyPy on Windows
|
||||
self.skipTest("Creating symlinks not supported")
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
|
||||
started_building = threading.Event()
|
||||
|
||||
with testing_server(docs_dir, started_building.set) as server:
|
||||
server.watch(docs_dir)
|
||||
time.sleep(0.01)
|
||||
|
||||
Path(origin_dir, "README.md").write_text("edited")
|
||||
self.assertTrue(started_building.wait(timeout=10))
|
||||
|
||||
@tempdir()
|
||||
def test_watch_with_broken_symlinks(self, docs_dir):
|
||||
Path(docs_dir, "subdir").mkdir()
|
||||
@@ -503,7 +526,6 @@ class BuildTests(unittest.TestCase):
|
||||
try:
|
||||
if sys.platform != "win32":
|
||||
Path(docs_dir, "subdir", "circular").symlink_to(Path(docs_dir))
|
||||
Path(docs_dir, "self_link").symlink_to(Path(docs_dir, "self_link"))
|
||||
|
||||
Path(docs_dir, "broken_1").symlink_to(Path(docs_dir, "oh no"))
|
||||
Path(docs_dir, "broken_2").symlink_to(Path(docs_dir, "oh no"), target_is_directory=True)
|
||||
|
||||
Reference in New Issue
Block a user