|
1 | 1 | import logging |
2 | 2 | import os |
| 3 | +import re |
3 | 4 | import shutil |
4 | 5 | import subprocess |
5 | 6 | import tempfile |
6 | 7 | from typing import Any, Mapping |
| 8 | +from urllib.parse import unquote |
7 | 9 |
|
8 | 10 | from jinja2 import Environment, PackageLoader |
9 | 11 | from openedu_builder import path_utils |
@@ -244,10 +246,10 @@ def _parse_copy( |
244 | 246 | def _parse_sidebar(k, v, path=""): |
245 | 247 | retval = {} |
246 | 248 |
|
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("/")) |
251 | 253 |
|
252 | 254 | retval["id"] = path + k |
253 | 255 | if isinstance(v, list): |
@@ -295,12 +297,123 @@ def _parse_sidebar(k, v, path=""): |
295 | 297 | "sidebar": sidebar, |
296 | 298 | } |
297 | 299 |
|
| 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 | + |
298 | 405 | def run(self): |
299 | 406 | if self.config.get("structure") is None and self.sidebar == "js": |
300 | 407 | raise PluginRunError( |
301 | 408 | "structure option is required for this plugin when using js sidebar" |
302 | 409 | ) |
303 | 410 |
|
| 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 | + |
304 | 417 | # Run init command |
305 | 418 | os.chdir(self.output_dir) |
306 | 419 | p = subprocess.run(self.init_command, capture_output=True) |
@@ -335,7 +448,7 @@ def run(self): |
335 | 448 | # Copy or link documentation in the right place |
336 | 449 | # self._parse_structure() |
337 | 450 | self._organize_files() |
338 | | - # self._resolve_links() |
| 451 | + self._resolve_links() |
339 | 452 |
|
340 | 453 | self._copy_extra_files() |
341 | 454 |
|
|
0 commit comments