Add safety features for file writing and enhance split command with options
This commit is contained in:
parent
dd73f3d71c
commit
75b750b662
|
|
@ -6,7 +6,7 @@ Next:
|
||||||
|
|
||||||
# Stack Language Specification
|
# Stack Language Specification
|
||||||
|
|
||||||
**Version**: 0.8
|
**Version**: 0.8.1
|
||||||
**Status**: Draft Specification
|
**Status**: Draft Specification
|
||||||
**Changes**:
|
**Changes**:
|
||||||
- 0.5 (AI)
|
- 0.5 (AI)
|
||||||
|
|
@ -75,5 +75,7 @@ Next:
|
||||||
6. **Tutorial content** - Added beginner tutorials to Appendix G
|
6. **Tutorial content** - Added beginner tutorials to Appendix G
|
||||||
7. **Trait reference** - Consolidated all trait definitions in Appendix B
|
7. **Trait reference** - Consolidated all trait definitions in Appendix B
|
||||||
8. **Grammar simplification** - Referenced Implementable trait instead of repeating
|
8. **Grammar simplification** - Referenced Implementable trait instead of repeating
|
||||||
|
- 0.8.1 (Human)
|
||||||
|
1. Added links
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
|
||||||
filenames = [
|
filenames = [
|
||||||
"docs/changes.md",
|
"docs/changes.md",
|
||||||
|
|
@ -72,7 +73,37 @@ def combine_markdown(file_inputs, output_combined, output_meta_json):
|
||||||
print(f"Combined file saved as: {output_combined}")
|
print(f"Combined file saved as: {output_combined}")
|
||||||
print(f"Metadata JSON saved as: {output_meta_json}")
|
print(f"Metadata JSON saved as: {output_meta_json}")
|
||||||
|
|
||||||
def split_with_front_matter(input_combined, output_dir, metadata_file):
|
def write_with_safety(path, content, force=False, backup=False):
|
||||||
|
"""Write a file safely with force/backup options and diff-aware prompt."""
|
||||||
|
if path.exists():
|
||||||
|
current = path.read_text(encoding='utf-8')
|
||||||
|
if current == content:
|
||||||
|
print(f"No changes for: {path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if backup and not force:
|
||||||
|
backup_path = path.with_suffix(path.suffix + ".bak")
|
||||||
|
shutil.copy2(path, backup_path)
|
||||||
|
print(f"Backup created: {backup_path}")
|
||||||
|
elif not force:
|
||||||
|
while True:
|
||||||
|
choice = input(f"{path} has changed. [y] overwrite, [b] backup+overwrite, [n] skip? ").strip().lower()
|
||||||
|
if choice in ("y", "yes"):
|
||||||
|
break
|
||||||
|
elif choice in ("b", "backup"):
|
||||||
|
backup_path = path.with_suffix(path.suffix + ".bak")
|
||||||
|
shutil.copy2(path, backup_path)
|
||||||
|
print(f"Backup created: {backup_path}")
|
||||||
|
break
|
||||||
|
elif choice in ("n", "no", ""):
|
||||||
|
print(f"Skipped: {path}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print("Please choose [y], [b], or [n].")
|
||||||
|
path.write_text(content, encoding='utf-8')
|
||||||
|
print(f"Wrote: {path}")
|
||||||
|
|
||||||
|
def split_with_front_matter(input_combined, output_dir, metadata_file, force=False, backup=False):
|
||||||
"""Split a combined markdown file back into original files, restoring front matter."""
|
"""Split a combined markdown file back into original files, restoring front matter."""
|
||||||
content = Path(input_combined).read_text(encoding='utf-8')
|
content = Path(input_combined).read_text(encoding='utf-8')
|
||||||
|
|
||||||
|
|
@ -81,13 +112,15 @@ def split_with_front_matter(input_combined, output_dir, metadata_file):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
meta_info = json.loads(Path(metadata_file).read_text(encoding='utf-8'))
|
meta_info = json.loads(Path(metadata_file).read_text(encoding='utf-8'))
|
||||||
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
# Find all sections between <!-- START filename.md --> and <!-- END filename.md -->
|
|
||||||
pattern = r'<!-- START (.*?) -->\n(.*?)\n<!-- END \1 -->'
|
pattern = r'<!-- START (.*?) -->\n(.*?)\n<!-- END \1 -->'
|
||||||
matches = re.findall(pattern, content, flags=re.DOTALL)
|
matches = re.findall(pattern, content, flags=re.DOTALL)
|
||||||
|
|
||||||
|
total_written = 0
|
||||||
|
total_skipped = 0
|
||||||
|
total_backups = 0
|
||||||
|
|
||||||
for filename, body in matches:
|
for filename, body in matches:
|
||||||
body = body.strip()
|
body = body.strip()
|
||||||
output_path = Path(output_dir, filename)
|
output_path = Path(output_dir, filename)
|
||||||
|
|
@ -99,26 +132,35 @@ def split_with_front_matter(input_combined, output_dir, metadata_file):
|
||||||
else:
|
else:
|
||||||
restored = body + "\n"
|
restored = body + "\n"
|
||||||
|
|
||||||
output_path.write_text(restored, encoding='utf-8')
|
before = output_path.exists()
|
||||||
print(f"Restored: {output_path}")
|
write_with_safety(output_path, restored, force=force, backup=backup)
|
||||||
|
|
||||||
print("Split complete.")
|
if backup and before:
|
||||||
|
total_backups += 1
|
||||||
|
if output_path.exists():
|
||||||
|
total_written += 1
|
||||||
|
else:
|
||||||
|
total_skipped += 1
|
||||||
|
|
||||||
|
print(f"Split complete. {total_written} files written, {total_skipped} skipped, {total_backups} backups made.")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Usage:")
|
print("Usage:")
|
||||||
print(" Combine files: python manage_docs.py combine")
|
print(" Combine: python manage_docs.py combine")
|
||||||
print(" Split files: python manage_docs.py split")
|
print(" Split: python manage_docs.py split [--force|--backup]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
command = sys.argv[1].lower()
|
command = sys.argv[1].lower()
|
||||||
|
force = "--force" in sys.argv
|
||||||
|
backup = "--backup" in sys.argv
|
||||||
|
|
||||||
if command == "combine":
|
if command == "combine":
|
||||||
combine_markdown(filenames, "stack_lang_spec.md", "metadata.json")
|
combine_markdown(filenames, "stack_lang_spec.md", "metadata.json")
|
||||||
|
|
||||||
elif command == "split":
|
elif command == "split":
|
||||||
split_with_front_matter("stack_lang_spec.md", "docs", "metadata.json")
|
split_with_front_matter("stack_lang_spec.md", "docs", "metadata.json",
|
||||||
|
force=force, backup=backup)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("Unknown command. Use 'combine' or 'split'.")
|
print("Unknown command. Use 'combine' or 'split'.")
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<!-- START changes.md -->
|
<!-- START changes.md -->
|
||||||
# Stack Language Specification
|
# Stack Language Specification
|
||||||
|
|
||||||
**Version**: 0.8
|
**Version**: 0.8.1
|
||||||
**Status**: Draft Specification
|
**Status**: Draft Specification
|
||||||
**Changes**:
|
**Changes**:
|
||||||
- 0.5 (AI)
|
- 0.5 (AI)
|
||||||
|
|
@ -70,6 +70,8 @@
|
||||||
6. **Tutorial content** - Added beginner tutorials to Appendix G
|
6. **Tutorial content** - Added beginner tutorials to Appendix G
|
||||||
7. **Trait reference** - Consolidated all trait definitions in Appendix B
|
7. **Trait reference** - Consolidated all trait definitions in Appendix B
|
||||||
8. **Grammar simplification** - Referenced Implementable trait instead of repeating
|
8. **Grammar simplification** - Referenced Implementable trait instead of repeating
|
||||||
|
- 0.8.1 (Human)
|
||||||
|
1. Added links
|
||||||
|
|
||||||
---
|
---
|
||||||
<!-- END changes.md -->
|
<!-- END changes.md -->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue