mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-31 12:45:23 +08:00
Keep complete-source synchronization byte exact
This commit is contained in:
@@ -10,6 +10,8 @@ Add a source-fidelity ledger. Inventory every supplied fact, number, command, co
|
|||||||
|
|
||||||
Add a code inventory that identifies the complete core files to reproduce in the tutorial. Include the kernel-mode eBPF source, user-space source, and any shared header needed to understand their contract. Keep tests, generated skeletons, vendored code, and build boilerplate as links unless the teaching mechanism depends on them.
|
Add a code inventory that identifies the complete core files to reproduce in the tutorial. Include the kernel-mode eBPF source, user-space source, and any shared header needed to understand their contract. Keep tests, generated skeletons, vendored code, and build boilerplate as links unless the teaching mechanism depends on them.
|
||||||
|
|
||||||
|
Every inventoried source must be non-empty UTF-8 text with LF line endings and a final LF byte. A fenced Markdown block cannot represent the absence of the final newline without changing the payload, so the synchronizer rejects an empty source or a source without the final LF instead of silently changing it. Do not normalize or edit an implementation file merely to make documentation synchronization pass without explicit authorization.
|
||||||
|
|
||||||
## Establish the teaching path
|
## Establish the teaching path
|
||||||
|
|
||||||
Write one sentence for the tutorial's promise and one sentence for its reader. Map each planned section to a distinct reader question. Confirm that the path covers the problem, relevant background, whole-system flow, complete code, focused kernel explanation, brief user-space explanation, deeper concepts, compilation and execution, real output, requirements, failure and cleanup behavior, limitations, summary, and references.
|
Write one sentence for the tutorial's promise and one sentence for its reader. Map each planned section to a distinct reader question. Confirm that the path covers the problem, relevant background, whole-system flow, complete code, focused kernel explanation, brief user-space explanation, deeper concepts, compilation and execution, real output, requirements, failure and cleanup behavior, limitations, summary, and references.
|
||||||
|
|||||||
@@ -78,13 +78,19 @@ def render(
|
|||||||
raise ValueError(f"missing matching generated fence and {END!r} after {source_name}")
|
raise ValueError(f"missing matching generated fence and {END!r} after {source_name}")
|
||||||
|
|
||||||
language = LANGUAGES[source.suffix]
|
language = LANGUAGES[source.suffix]
|
||||||
source_text = source.read_bytes().decode("utf-8")
|
source_bytes = source.read_bytes()
|
||||||
|
if not source_bytes:
|
||||||
|
raise ValueError(f"complete source cannot be empty: {source_name}")
|
||||||
|
if not source_bytes.endswith(b"\n"):
|
||||||
|
raise ValueError(
|
||||||
|
f"complete source must end with an LF byte for exact fenced inclusion: {source_name}"
|
||||||
|
)
|
||||||
|
source_text = source_bytes.decode("utf-8")
|
||||||
if "\r" in source_text:
|
if "\r" in source_text:
|
||||||
raise ValueError(f"complete source must use LF line endings: {source_name}")
|
raise ValueError(f"complete source must use LF line endings: {source_name}")
|
||||||
max_backticks = max((len(run) for run in re.findall(r"`+", source_text)), default=0)
|
max_backticks = max((len(run) for run in re.findall(r"`+", source_text)), default=0)
|
||||||
generated_fence = "`" * max(3, max_backticks + 1)
|
generated_fence = "`" * max(3, max_backticks + 1)
|
||||||
if source_text.endswith("\n"):
|
source_text = source_text[:-1]
|
||||||
source_text = source_text[:-1]
|
|
||||||
rendered.extend(
|
rendered.extend(
|
||||||
[
|
[
|
||||||
lines[index],
|
lines[index],
|
||||||
|
|||||||
@@ -214,6 +214,50 @@ class SyncSourceBlocksTest(unittest.TestCase):
|
|||||||
self.assertEqual(first_english, english.read_bytes())
|
self.assertEqual(first_english, english.read_bytes())
|
||||||
self.assertEqual(first_chinese, chinese.read_bytes())
|
self.assertEqual(first_chinese, chinese.read_bytes())
|
||||||
|
|
||||||
|
def test_rejects_empty_source_without_changing_either_readme(self) -> None:
|
||||||
|
source = self.root / "src/lesson/tool.c"
|
||||||
|
source.write_bytes(b"")
|
||||||
|
english = self.write_readme("src/lesson/README.md")
|
||||||
|
chinese = self.write_readme("src/lesson/README.zh.md")
|
||||||
|
before = (english.read_bytes(), chinese.read_bytes())
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
"--readme", "src/lesson/README.md",
|
||||||
|
"--readme", "src/lesson/README.zh.md",
|
||||||
|
"--write",
|
||||||
|
)
|
||||||
|
self.assertEqual(1, result.returncode)
|
||||||
|
self.assertIn("complete source cannot be empty", result.stderr)
|
||||||
|
self.assertEqual(before, (english.read_bytes(), chinese.read_bytes()))
|
||||||
|
|
||||||
|
def test_rejects_source_without_final_lf(self) -> None:
|
||||||
|
source = self.root / "src/lesson/tool.c"
|
||||||
|
source.write_bytes(b"int value = 1;")
|
||||||
|
self.write_readme("src/lesson/README.md")
|
||||||
|
self.write_readme("src/lesson/README.zh.md")
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
"--readme", "src/lesson/README.md",
|
||||||
|
"--readme", "src/lesson/README.zh.md",
|
||||||
|
"--write",
|
||||||
|
)
|
||||||
|
self.assertEqual(1, result.returncode)
|
||||||
|
self.assertIn("must end with an LF byte", result.stderr)
|
||||||
|
|
||||||
|
def test_preserves_multiple_trailing_lfs(self) -> None:
|
||||||
|
source = self.root / "src/lesson/tool.c"
|
||||||
|
source.write_bytes(b"int value = 1;\n\n\n")
|
||||||
|
english = self.write_readme("src/lesson/README.md")
|
||||||
|
self.write_readme("src/lesson/README.zh.md")
|
||||||
|
|
||||||
|
result = self.run_script(
|
||||||
|
"--readme", "src/lesson/README.md",
|
||||||
|
"--readme", "src/lesson/README.zh.md",
|
||||||
|
"--write",
|
||||||
|
)
|
||||||
|
self.assertEqual(0, result.returncode, result.stderr)
|
||||||
|
self.assertIn("int value = 1;\n\n\n```", english.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
def test_requires_bilingual_pair(self) -> None:
|
def test_requires_bilingual_pair(self) -> None:
|
||||||
self.write_readme("src/lesson/README.md")
|
self.write_readme("src/lesson/README.md")
|
||||||
result = self.run_script(
|
result = self.run_script(
|
||||||
|
|||||||
Reference in New Issue
Block a user