mirror of
https://github.com/rendercv/rendercv.git
synced 2026-04-17 13:33:53 -04:00
Fix #673: Make copied template files writable for immutable distros
On NixOS and other immutable distributions, package files in the store are read-only. shutil.copytree preserves source permissions, so copied template files remain read-only. This causes PermissionError when create-theme tries to write __init__.py into the copied directory. Added make_tree_writable() that adds user-write permission to all files and directories after copying. Called automatically by copy_templates().
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import stat
|
||||
from typing import Literal
|
||||
|
||||
|
||||
@@ -29,3 +31,23 @@ def copy_templates(
|
||||
copy_templates_to,
|
||||
ignore=shutil.ignore_patterns("__init__.py", "__pycache__"),
|
||||
)
|
||||
make_tree_writable(copy_templates_to)
|
||||
|
||||
|
||||
def make_tree_writable(path: pathlib.Path) -> None:
|
||||
"""Add user-write permission to all files and directories in a tree.
|
||||
|
||||
Why:
|
||||
On immutable distributions like NixOS, package files are read-only.
|
||||
shutil.copytree preserves source permissions, so copied files remain
|
||||
read-only. Users need write access to customize templates.
|
||||
|
||||
Args:
|
||||
path: Root directory to make writable.
|
||||
"""
|
||||
for dirpath, _, filenames in os.walk(path):
|
||||
dp = pathlib.Path(dirpath)
|
||||
dp.chmod(dp.stat().st_mode | stat.S_IWUSR)
|
||||
for filename in filenames:
|
||||
fp = dp / filename
|
||||
fp.chmod(fp.stat().st_mode | stat.S_IWUSR)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import os
|
||||
import pathlib
|
||||
import stat
|
||||
|
||||
import pytest
|
||||
|
||||
from rendercv.cli.copy_templates import copy_templates
|
||||
from rendercv.cli.copy_templates import copy_templates, make_tree_writable
|
||||
|
||||
|
||||
@pytest.mark.parametrize("template_type", ["markdown", "typst"])
|
||||
@@ -14,3 +18,42 @@ def test_copy_templates(template_type, tmp_path):
|
||||
assert not (destination / "__pycache__").exists()
|
||||
# Check that at least some files were copied
|
||||
assert any(destination.iterdir())
|
||||
|
||||
|
||||
def test_copy_templates_produces_writable_files(tmp_path):
|
||||
destination = tmp_path / "templates"
|
||||
|
||||
copy_templates("typst", destination)
|
||||
|
||||
for dirpath, _, filenames in os.walk(destination):
|
||||
dp = pathlib.Path(dirpath)
|
||||
assert dp.stat().st_mode & stat.S_IWUSR, f"Directory {dp} is not user-writable"
|
||||
for filename in filenames:
|
||||
fp = dp / filename
|
||||
assert fp.stat().st_mode & stat.S_IWUSR, f"File {fp} is not user-writable"
|
||||
|
||||
|
||||
def test_make_tree_writable(tmp_path):
|
||||
# Create a tree with read-only files and directories
|
||||
subdir = tmp_path / "readonly_dir"
|
||||
subdir.mkdir()
|
||||
test_file = subdir / "test.txt"
|
||||
test_file.write_text("content")
|
||||
nested = subdir / "nested"
|
||||
nested.mkdir()
|
||||
nested_file = nested / "nested.txt"
|
||||
nested_file.write_text("nested content")
|
||||
|
||||
# Make everything read-only
|
||||
nested_file.chmod(stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
|
||||
nested.chmod(stat.S_IRUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH)
|
||||
test_file.chmod(stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
|
||||
subdir.chmod(stat.S_IRUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH)
|
||||
|
||||
make_tree_writable(subdir)
|
||||
|
||||
# All should be user-writable now
|
||||
assert subdir.stat().st_mode & stat.S_IWUSR
|
||||
assert test_file.stat().st_mode & stat.S_IWUSR
|
||||
assert nested.stat().st_mode & stat.S_IWUSR
|
||||
assert nested_file.stat().st_mode & stat.S_IWUSR
|
||||
|
||||
Reference in New Issue
Block a user