Coverage for portality / cms / build_fragments.py: 73%
101 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-04 09:41 +0100
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-04 09:41 +0100
1# ~~CMSBuildFragments:Script->CMS:Script~~
2import os
3import random
4import string
6import markdown
7import shutil
8import yaml
10from copy import deepcopy
11from datetime import datetime
13from portality.cms import implied_attr_list
14from portality.lib import paths
16BASE = "cms"
17SRC = os.path.join(BASE, "pages")
18OUT = os.path.join(BASE, "fragments")
19FRONT_MATTER = os.path.join(BASE, "data/frontmatter.yml")
20ERROR = os.path.join(BASE, "error_fragments.txt")
23def _localise_paths(base_path=None):
24 now = datetime.utcnow().timestamp()
25 if base_path is None:
26 return BASE, SRC, OUT, OUT + "." + str(now), FRONT_MATTER, FRONT_MATTER + "." + str(now), ERROR
28 return (os.path.join(base_path, BASE),
29 os.path.join(base_path, SRC),
30 os.path.join(base_path, OUT),
31 os.path.join(base_path, OUT + "." + str(now)),
32 os.path.join(base_path, FRONT_MATTER),
33 os.path.join(base_path, FRONT_MATTER + "." + str(now)),
34 os.path.join(base_path, ERROR))
37def _clear_tree(dir):
38 if not os.path.exists(dir):
39 os.makedirs(dir)
40 for filename in os.listdir(dir):
41 filepath = os.path.join(dir, filename)
42 try:
43 shutil.rmtree(filepath)
44 except OSError:
45 os.remove(filepath)
48def create_random_str(n_char=10):
49 s = string.ascii_letters + string.digits
50 return ''.join(random.choices(s, k=n_char))
53def _swap(old, new):
54 def _rm_dir_if_exist(_dir):
55 if os.path.exists(_dir):
56 try:
57 shutil.rmtree(_dir)
58 except OSError:
59 os.remove(_dir)
61 tmp_old_dir = f'{old}.old.{create_random_str(20)}'
62 if os.path.exists(old):
63 _rm_dir_if_exist(tmp_old_dir)
64 os.rename(old, tmp_old_dir)
66 os.rename(new, old)
67 _rm_dir_if_exist(tmp_old_dir)
70def build(base_path=None):
71 #~~->CMSFragments:Build~~
72 base_dir, src_dir, out_dir, tmp_out_dir, fm_file, fm_tmp, error_file = None, None, None, None, None, None, None
73 try:
74 base_dir, src_dir, out_dir, tmp_out_dir, fm_file, fm_tmp, error_file = _localise_paths(base_path)
75 _clear_tree(tmp_out_dir)
76 if os.path.exists(error_file):
77 os.remove(error_file)
79 extensions = [
80 "full_yaml_metadata",
81 "toc",
82 "markdown.extensions.tables",
83 "markdown.extensions.fenced_code",
84 'attr_list',
85 'markdown_link_attr_modifier',
86 "mdx_truly_sane_lists",
87 "codehilite",
88 implied_attr_list.ImpliedAttrListExtension()
89 ]
91 cfg = {
92 'markdown_link_attr_modifier': {
93 "new_tab" : "external_only",
94 "no_referrer" : "external_only"
95 },
96 "codehilite" : {
97 "css_class" : "highlight"
98 }
99 }
101 fm = {}
103 # Do all the page fragments
104 for dirpath, dirnames, filenames in os.walk(src_dir):
105 for fn in filenames:
106 nfn = fn.rsplit(".", 1)[0] + ".html"
107 sub_path = dirpath[len(src_dir) + 1:]
108 file_ident = "/" + os.path.join(sub_path, nfn)
109 outdir = os.path.join(tmp_out_dir, sub_path)
110 out = os.path.join(outdir, nfn)
111 input = os.path.join(src_dir, sub_path, fn)
113 with open(input) as f:
114 md = markdown.Markdown(extensions=extensions, extension_configs=cfg)
115 body = md.convert(f.read())
117 nm = deepcopy(md.Meta)
118 if nm is None:
119 nm = {}
120 if nm.get("toc") is True:
121 nm["toc_tokens"] = md.toc_tokens
123 nm["frag"] = file_ident
124 fm[file_ident] = nm
126 if not os.path.exists(outdir):
127 os.makedirs(outdir)
128 with open(out, "w") as g:
129 g.write(body)
131 with open(fm_tmp, "w") as f:
132 f.write(yaml.dump(fm))
134 # we've got to here, so we are ready to shift everything into live position
135 _swap(out_dir, tmp_out_dir)
136 _swap(fm_file, fm_tmp)
138 except Exception as e:
139 try:
140 print("Error occurred building static pages")
141 if error_file:
142 with open(error_file, "w") as f:
143 f.write(str(e))
145 if tmp_out_dir and os.path.exists(tmp_out_dir):
146 shutil.rmtree(tmp_out_dir)
148 if out_dir and os.path.exists(out_dir + ".old"):
149 os.rename(out_dir + ".old", out_dir)
151 if fm_tmp and os.path.exists(fm_tmp):
152 os.remove(fm_tmp)
154 if fm_file and os.path.exists(fm_file + ".old"):
155 os.rename(fm_file + ".old", fm_file)
157 raise e
159 except:
160 print("Error occurred building static pages and could not complete cleanup")
161 raise e
164if __name__ == "__main__":
165 build(paths.get_project_root().as_posix())