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

1import os 

2import shutil 

3import sys 

4 

5import jinja2 

6from boltons import fileutils 

7 

8 

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) 

18 

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) 

25 

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}') 

30 

31 

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}') 

39 

40 if not os.path.isdir(output_dir): 

41 fileutils.mkdir_p(output_dir) 

42 

43 src_path = tpl.workpath 

44 src_path = os.path.join(src_path, "template") 

45 src_path = os.path.abspath(src_path) 

46 

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 ) 

52 

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) 

57 

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') 

78 

79 return tpl, ctx 

80 

81 

82def clone(tpl, env, ctx, **kwargs): 

83 output_dir = kwargs["output_dir"] 

84 

85 items = reversed(tpl.includes) 

86 for item in items: 

87 _clone(item, env, ctx, output_dir) 

88 

89 return tpl