Skip to content

Commit 7bef7aa

Browse files
committed
Add link resolving
Add url decoding for sections
1 parent 25cbb0d commit 7bef7aa

File tree

1 file changed

+118
-5
lines changed

1 file changed

+118
-5
lines changed

openedu_builder/plugins/docusaurus.py

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import logging
22
import os
3+
import re
34
import shutil
45
import subprocess
56
import tempfile
67
from typing import Any, Mapping
8+
from urllib.parse import unquote
79

810
from jinja2 import Environment, PackageLoader
911
from openedu_builder import path_utils
@@ -244,10 +246,10 @@ def _parse_copy(
244246
def _parse_sidebar(k, v, path=""):
245247
retval = {}
246248

247-
if dir := os.path.dirname(k):
248-
retval["title"] = dir
249-
else:
250-
retval["title"] = k
249+
# if dir := os.path.dirname(k):
250+
# retval["title"] = unquote(dir)
251+
# else:
252+
retval["title"] = unquote(k.strip("/"))
251253

252254
retval["id"] = path + k
253255
if isinstance(v, list):
@@ -295,12 +297,123 @@ def _parse_sidebar(k, v, path=""):
295297
"sidebar": sidebar,
296298
}
297299

300+
def _resolve_links(self):
301+
# Create mappings
302+
src_to_dst = {}
303+
dst_to_src = {}
304+
305+
for src, dst in self.structure["to_copy"]:
306+
_src, _dst = src.rstrip("/"), dst.rstrip("/")
307+
if os.path.isfile(src) and os.path.isdir(_dst):
308+
_dst = os.path.join(_dst, os.path.basename(src))
309+
310+
src_to_dst[_src] = _dst
311+
dst_to_src[_dst] = _src
312+
313+
log.debug(src_to_dst)
314+
log.debug(dst_to_src)
315+
316+
md_link_regex = re.compile(r"\[.*?\]\((\.(?:\.)?\/.*?)\)")
317+
318+
dst_files = []
319+
320+
def _walk_struct(structure):
321+
if children := structure.get("children"):
322+
for child in children:
323+
_walk_struct(child)
324+
else:
325+
dst_files.append(structure.get("id"))
326+
327+
for item in self.structure["sidebar"]:
328+
_walk_struct(item)
329+
330+
log.debug(dst_files)
331+
332+
for file in dst_files:
333+
# Replace relative links in markdown files that have been moved,
334+
# using the src_to_dst and dst_to_src directory mappings.
335+
# File is already at the destination location. src_to_dst and dst_to_src
336+
# contain mappings of directories that have been moved.
337+
_file = os.path.join(self.docusaurus_dir, "docs", file + ".md")
338+
if not os.path.exists(_file):
339+
_file = os.path.join(self.docusaurus_dir, "docs", file + ".mdx")
340+
341+
log.debug(f"Trying to open {_file}")
342+
343+
if _nfile := dst_to_src.get(_file):
344+
src_dir = os.path.dirname(_nfile)
345+
else:
346+
src_dir = dst_to_src[os.path.dirname(_file)]
347+
dst_dir = os.path.dirname(_file)
348+
349+
_possible_src = sorted(
350+
src_to_dst.keys(),
351+
key=lambda x: len(x.strip("/").split(os.path.sep)),
352+
reverse=True,
353+
)
354+
355+
if os.path.exists(_file):
356+
with open(_file, "r") as f:
357+
content = f.read()
358+
359+
for match in re.finditer(md_link_regex, content):
360+
src_link = match.group(1)
361+
log.info(f"Found link {src_link}")
362+
# dst_link = src_to_dst[path_utils.real_join(src_dir, src_link)]
363+
# dst_link = os.path.relpath(dst_dir, dst_link)
364+
src_ref = path_utils.real_join(src_dir, src_link)
365+
log.debug(f"Link {src_link} refers to {src_ref}")
366+
try:
367+
_src_ref = next(
368+
x for x in _possible_src if src_ref.startswith(x)
369+
)
370+
src_ref_dir = (
371+
os.path.dirname(_src_ref)
372+
if os.path.isfile(_src_ref)
373+
else _src_ref
374+
)
375+
log.debug(f"File {src_ref} found under {src_ref_dir}")
376+
except StopIteration:
377+
log.warning(
378+
f"Couldn't find {src_ref} in source files. Perhaps you didn't copy it? Skipping link {src_link}."
379+
)
380+
continue
381+
382+
_dst_ref = src_to_dst[_src_ref]
383+
dst_ref_dir = (
384+
os.path.dirname(_dst_ref)
385+
if os.path.isfile(_dst_ref)
386+
else _dst_ref
387+
)
388+
log.debug(
389+
f"File {src_ref} should be copied under {dst_ref_dir} at the destination."
390+
)
391+
dst_ref = path_utils.real_join(
392+
dst_ref_dir, src_ref.removeprefix(src_ref_dir).lstrip("/")
393+
)
394+
log.debug(
395+
f"File {src_ref} should be copied to {dst_ref} at the destination."
396+
)
397+
dst_link = os.path.relpath(dst_ref, dst_dir)
398+
log.info(f"New link should be {dst_link}")
399+
400+
content = content.replace(src_link, dst_link)
401+
402+
with open(_file, "w") as f:
403+
f.write(content)
404+
298405
def run(self):
299406
if self.config.get("structure") is None and self.sidebar == "js":
300407
raise PluginRunError(
301408
"structure option is required for this plugin when using js sidebar"
302409
)
303410

411+
self._parse_structure()
412+
413+
log.debug(self.structure["raw"])
414+
log.debug(self.structure["to_copy"])
415+
log.debug(self.structure["sidebar"])
416+
304417
# Run init command
305418
os.chdir(self.output_dir)
306419
p = subprocess.run(self.init_command, capture_output=True)
@@ -335,7 +448,7 @@ def run(self):
335448
# Copy or link documentation in the right place
336449
# self._parse_structure()
337450
self._organize_files()
338-
# self._resolve_links()
451+
self._resolve_links()
339452

340453
self._copy_extra_files()
341454

0 commit comments

Comments
 (0)