Coverage for src / layout / clone.py: 10%
60 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-21 16:36 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-21 16:36 +0000
1import os
2import shutil
3import sys
5import jinja2
6from boltons import fileutils
9# TODO: properly copy all modes and stats
10#
11def _clone_file(env, ctx, src, dst):
12 try:
13 with open(src, encoding="UTF-8") as fdr, open(dst, mode="w", encoding="UTF-8") as fdw:
14 dst_contents = fdr.read()
15 dst_contents = env.from_string(dst_contents).render(**ctx)
16 fdw.write(str(dst_contents or ""))
17 shutil.copymode(src, dst)
19 except UnicodeDecodeError:
20 with open(src, mode="rb") as fdr, open(dst, mode="wb") as fdw:
21 dst_contents = fdr.read()
22 fdw.write(dst_contents)
23 shutil.copystat(src, dst)
24 shutil.copymode(src, dst)
26 except jinja2.exceptions.UndefinedError as err:
27 sys.exit(f'error: while rendering "{src}", encountered template error: {err}')
28 except jinja2.exceptions.TemplateSyntaxError as err:
29 sys.exit(f'error: while rendering "{src}", encountered template error: {err}')
32def _clone(tpl, env, ctx, output_dir):
33 def templatize(src, string):
34 # Change templates in file name
35 try:
36 return str(env.from_string(string).render(**ctx))
37 except jinja2.exceptions.UndefinedError as err:
38 sys.exit(f'error: templating error during "{src}" file: {err}')
40 if not os.path.isdir(output_dir):
41 fileutils.mkdir_p(output_dir)
43 src_path = tpl.workpath
44 src_path = os.path.join(src_path, "template")
45 src_path = os.path.abspath(src_path)
47 if not os.path.isdir(src_path):
48 print(
49 'warning: no "template" named folder found in source template directory. No templating can be done',
50 file=sys.stderr,
51 )
53 for src in fileutils.iter_find_files(src_path, "*", include_dirs=True):
54 dst = os.path.relpath(src, src_path)
55 dst = templatize(src, dst)
56 dst = os.path.join(output_dir, dst)
58 if os.path.islink(src):
59 # Read the target, and if templatized target is the same
60 # as original target, then we can just copy the link over
61 target_src = os.readlink(src)
62 target_dst = templatize(src, target_src)
63 if target_src == target_dst:
64 if os.path.exists(dst):
65 os.unlink(dst)
66 shutil.copyfile(src, dst, follow_symlinks=False)
67 else:
68 # TODO: make a new link in dst that targets a
69 # templatized value
70 sys.exit("error: changing link is not implemented while handling {src}")
71 elif os.path.isdir(src):
72 fileutils.mkdir_p(dst)
73 elif os.path.isfile(src):
74 fileutils.mkdir_p(os.path.dirname(dst))
75 _clone_file(env, ctx, src, dst)
76 else:
77 sys.exit(f'error: path copy failed. File "{src}" of unknown type')
79 return tpl, ctx
82def clone(tpl, env, ctx, **kwargs):
83 output_dir = kwargs["output_dir"]
85 items = reversed(tpl.includes)
86 for item in items:
87 _clone(item, env, ctx, output_dir)
89 return tpl