Dateiendung angepasst
This commit is contained in:
@@ -41,12 +41,18 @@ mdlink .
|
||||
|
||||
## Interactive Redirect Rewrite
|
||||
|
||||
When a Markdown link redirects, `mdlink` prompts:
|
||||
Step 1: When a Markdown link redirects, `mdlink` prompts:
|
||||
|
||||
```text
|
||||
Replace old URL with final URL? [y/N]
|
||||
```
|
||||
|
||||
Step 2: For `http://` Markdown links without redirect, `mdlink` can test an `https://` variant and prompt:
|
||||
|
||||
```text
|
||||
Replace HTTP URL with HTTPS variant? [y/N]
|
||||
```
|
||||
|
||||
Only confirmed links are updated.
|
||||
|
||||
## Test File And Script
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
@@ -56,7 +57,51 @@ def _collect_redirects(records: list[LinkRecord], checks: dict[str, LinkCheckRes
|
||||
return redirects
|
||||
|
||||
|
||||
def _is_http_url(url: str) -> bool:
|
||||
return url.startswith("http://")
|
||||
|
||||
|
||||
def _to_https(url: str) -> str:
|
||||
return "https://" + url[len("http://") :]
|
||||
|
||||
|
||||
def _cached_check(
|
||||
checker: LinkChecker,
|
||||
cache: dict[str, LinkCheckResult],
|
||||
url: str,
|
||||
) -> LinkCheckResult:
|
||||
result = cache.get(url)
|
||||
if result is None:
|
||||
result = checker.check(url)
|
||||
cache[url] = result
|
||||
return result
|
||||
|
||||
|
||||
def _collect_https_candidates(
|
||||
records: list[LinkRecord],
|
||||
checks: dict[str, LinkCheckResult],
|
||||
) -> list[tuple[LinkRecord, str]]:
|
||||
candidates: list[tuple[LinkRecord, str]] = []
|
||||
seen: set[tuple[Path, str]] = set()
|
||||
for record in records:
|
||||
if record.kind != "markdown":
|
||||
continue
|
||||
if not _is_http_url(record.url):
|
||||
continue
|
||||
original_check = checks.get(record.url)
|
||||
if original_check and original_check.redirected:
|
||||
continue
|
||||
key = (record.file_path, record.url)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
candidates.append((record, _to_https(record.url)))
|
||||
return candidates
|
||||
|
||||
|
||||
def _handle_rewrites(
|
||||
records: list[LinkRecord],
|
||||
checks: dict[str, LinkCheckResult],
|
||||
redirects: list[tuple[LinkRecord, LinkCheckResult]],
|
||||
checker: LinkChecker,
|
||||
editor: ASTMarkdownEditor,
|
||||
@@ -64,6 +109,10 @@ def _handle_rewrites(
|
||||
) -> None:
|
||||
replacements_by_file: dict[Path, dict[str, str]] = defaultdict(dict)
|
||||
seen_pairs: set[tuple[Path, str, str]] = set()
|
||||
check_cache: dict[str, LinkCheckResult] = {}
|
||||
|
||||
if redirects:
|
||||
console.print("\n[bold]Redirect replacements[/bold]")
|
||||
|
||||
for record, result in redirects:
|
||||
if record.kind != "markdown":
|
||||
@@ -82,7 +131,7 @@ def _handle_rewrites(
|
||||
if answer != "y":
|
||||
continue
|
||||
|
||||
verification = checker.check(final_url)
|
||||
verification = _cached_check(checker=checker, cache=check_cache, url=final_url)
|
||||
if verification.status_code != 200:
|
||||
console.print(
|
||||
f"[red]Skip:[/red] final URL no longer valid ({verification.status_code or verification.error})"
|
||||
@@ -90,6 +139,39 @@ def _handle_rewrites(
|
||||
continue
|
||||
replacements_by_file[record.file_path][record.url] = final_url
|
||||
|
||||
https_candidates = _collect_https_candidates(records=records, checks=checks)
|
||||
if https_candidates:
|
||||
console.print("\n[bold]HTTPS upgrade candidates[/bold]")
|
||||
|
||||
for record, https_url in https_candidates:
|
||||
if replacements_by_file[record.file_path].get(record.url):
|
||||
continue
|
||||
https_check = _cached_check(checker=checker, cache=check_cache, url=https_url)
|
||||
if https_check.status_code != 200:
|
||||
continue
|
||||
final_url: Optional[str] = https_check.final_url or https_url
|
||||
if final_url == record.url:
|
||||
continue
|
||||
|
||||
pair = (record.file_path, record.url, final_url)
|
||||
if pair in seen_pairs:
|
||||
continue
|
||||
seen_pairs.add(pair)
|
||||
|
||||
console.print(f"\n[cyan]{record.file_path}:{record.line}[/cyan]")
|
||||
console.print(f"[yellow]{record.url}[/yellow] -> [green]{final_url}[/green]")
|
||||
answer = console.input("Replace HTTP URL with HTTPS variant? [y/N] ").strip().lower()
|
||||
if answer != "y":
|
||||
continue
|
||||
|
||||
verification = _cached_check(checker=checker, cache=check_cache, url=final_url)
|
||||
if verification.status_code != 200:
|
||||
console.print(
|
||||
f"[red]Skip:[/red] HTTPS URL no longer valid ({verification.status_code or verification.error})"
|
||||
)
|
||||
continue
|
||||
replacements_by_file[record.file_path][record.url] = final_url
|
||||
|
||||
for file_path, replacements in replacements_by_file.items():
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
updated = editor.replace_links(content, replacements)
|
||||
@@ -118,9 +200,15 @@ def main() -> None:
|
||||
console.print("No non-200 links found.")
|
||||
|
||||
redirects = _collect_redirects(records, checks)
|
||||
if redirects:
|
||||
editor = ASTMarkdownEditor()
|
||||
_handle_rewrites(redirects=redirects, checker=checker, editor=editor, console=console)
|
||||
editor = ASTMarkdownEditor()
|
||||
_handle_rewrites(
|
||||
records=records,
|
||||
checks=checks,
|
||||
redirects=redirects,
|
||||
checker=checker,
|
||||
editor=editor,
|
||||
console=console,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Iterable, Iterator
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
MARKDOWN_EXTENSIONS = {".md"}
|
||||
MARKDOWN_EXTENSIONS = {".md", ".markdown", ".mdown", ".mkd"}
|
||||
|
||||
|
||||
def iter_markdown_files(target: Path) -> Iterator[Path]:
|
||||
@@ -13,8 +13,8 @@ def iter_markdown_files(target: Path) -> Iterator[Path]:
|
||||
if target.suffix.lower() in MARKDOWN_EXTENSIONS:
|
||||
yield target
|
||||
return
|
||||
for path in sorted(target.rglob("*.md")):
|
||||
if path.is_file():
|
||||
for path in sorted(target.rglob("*")):
|
||||
if path.is_file() and path.suffix.lower() in MARKDOWN_EXTENSIONS:
|
||||
yield path
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user