-
Notifications
You must be signed in to change notification settings - Fork 0
/
tparts
executable file
·376 lines (284 loc) · 13.3 KB
/
tparts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#!/usr/bin/awk -f
# The function arguments prefixed with an underscore character, e.g. '_cmd', imitate the function local scope.
# Takes file or directory path string. Returns symbolic links or canonical file name of the given path.
function readlink( \
path, \
_cmd, _dir \
) {
_cmd = "readlink -f " path
_cmd | getline _dir
close(_cmd)
return _dir
}
# Returns a string of a UNIX timestamp of the current time.
function timestamp_unix( \
_cmd, _timestamp \
) {
_cmd = "date +\"%s\""
_cmd | getline _timestamp
close(_cmd)
return _timestamp
}
# Takes HTML/XML format string. Returns the string where XML and HTML syntax characters are replaced with their character entity references.
function escape_ml(str) {
gsub(/&/, "\\&", str)
gsub(/</, "\\<", str)
gsub(/>/, "\\>", str)
gsub(/"/, "\\"", str)
gsub(/'/, "\\'", str)
return str
}
# Takes string. Returns the string with the last character removed.
function trim_last_char(str) {
return substr(str, 1, length(str) - 1)
}
# Takes multi-line string and a characted sequence. Prefixes the string lines with the given indentation char. sequence.
# Skips indenting on preformatted text lines wrapped in <pre> tags blocks.
function indent_lines( \
original_lines, indent, \
_indented_lines, _lines_arr, _preformatted_boundary_match, _i \
) {
split(original_lines, _lines_arr, "\n")
for (_i in _lines_arr) {
match(_lines_arr[_i], /(<pre>)|<\/pre>|(<pre( .*))/, _preformatted_boundary_match)
_indented_lines = _indented_lines ((_i == 1 || _preformatted_boundary_match[0]) ? "" : indent) _lines_arr[_i] "\n"
}
return trim_last_char(_indented_lines)
}
# Takes array of directory paths. Populates _values_files_index with the found template value files data.
function populate_values_files_index( \
paths_values_dirs_arr, \
_i \
) {
for (_i in paths_values_dirs_arr) {
if (! paths_values_dirs_arr[_i] in _values_files_index) {
_cmd_find = "find " paths_values_dirs_arr[_i] "/_* -maxdepth 0 -type f"
while ((_cmd_find | getline _find_path_result) > 0) {
match(_find_path_result, /[^\/]*$/, _basename_match)
_values_files_index[paths_values_dirs_arr[_i]][_basename_match[0]]["path"] = _find_path_result
match(_basename_match[0], /^_[a-z]*_/, _prefix_match)
if (_prefix_match[0]) {
_values_files_index[paths_values_dirs_arr[_i]][_basename_match[0]]["type"] = _prefix_match[0]
delete _prefix_match
}
_values_files_index[paths_values_dirs_arr[_i]][_basename_match[0]]["value"] = read_value_file(_values_files_index[paths_values_dirs_arr[_i]][_basename_match[0]])
delete _basename_match
}
close(_cmd_find)
}
}
}
# Takes a document data structure. Populates the document's values index entry in _values_files_index.
function document_populate_values_index( \
document, \
_value_name, _i, _prop \
) {
for (_i in document["paths_values_dir"]) for (_value_name in _values_files_index[document["paths_values_dir"][_i]]) {
for (_prop in _values_files_index[document["paths_values_dir"][_i]][_value_name]) {
document["values_index"][_value_name][_prop] = _values_files_index[document["paths_values_dir"][_i]][_value_name][_prop]
}
}
}
# Takes a value string, pointer to values index and a pointer to result array. Indexes in the result array the template value names that are found. Counts how many of template value names from the values index are present in the value string and returns the count.
function find_values_placeholders_in_str( \
str, values_index, result, \
_value_index, _count \
) {
for (_value_index in values_index) {
_value_count = match(str, "<!-- " _value_index " -->")
if (_value_count) result[_value_index] = 1
_count += _value_count
}
return _count
}
# Reads document single template value file. Returns the file as a string.
function read_value_file( \
value, \
_value_lines, _line, _util_line_match \
) {
switch (value["type"]) {
case "_inline_":
while((getline _line < (value["path"])) > 0) { _value_lines = _value_lines _line }
break
case "_pre_":
while((getline _line < (value["path"])) > 0) { _value_lines = _value_lines escape_ml(_line) "\n" }
break
case "_block_":
while((getline _line < (value["path"])) > 0) {
match(_line, /(<!-- prettier-ignore.*)/, _util_line_match)
! _util_line_match[0] && _value_lines = _value_lines _line "\n"
}
break
}
close(value["path"])
if (value["type"] == "_pre_") _value_lines = trim_last_char(_value_lines)
return _value_lines
}
# Single pass of replacing template placeholders names in a document with their respective value files contents.
function sub_values_placeholders_in_str( \
found_values, values_index, fragment, \
_fragment_out, _indent, _indent_match, _value_placeholder, _value, _i, _index_placeholder_start, _index_placeholder_end, _before_placeholder, _after_placeholder, _replacement \
) {
for (_value in found_values) {
split(fragment, _fragment_out_arr, "\n")
_fragment_out = ""
_value_placeholder = "<!-- " _value " -->"
for (_i in _fragment_out_arr) {
if (match(_fragment_out_arr[_i], _value_placeholder)) {
if (values_index[_value]["type"] == "_block_") {
# Maintains block spaces char. indentation in the document.
_indent = match(_fragment_out_arr[_i], /^\s+/, _indent_match) ? _indent_match[0] : ""
_replacement = indent_lines(trim_last_char(values_index[_value]["value"]), _indent)
} else _replacement = values_index[_value]["value"]
_index_placeholder_start = index(_fragment_out_arr[_i], _value_placeholder)
_index_placeholder_end = _index_placeholder_start + length(_value_placeholder)
_before_placeholder = substr(_fragment_out_arr[_i], 1, _index_placeholder_start - 1)
_after_placeholder = substr(_fragment_out_arr[_i], _index_placeholder_end)
_fragment_out_arr[_i] = _before_placeholder _replacement _after_placeholder
}
_fragment_out = _fragment_out _fragment_out_arr[_i] "\n"
}
_fragment_out = trim_last_char(_fragment_out)
}
return _fragment_out
}
# Finds and replaces template value placeholders in a document iteratively, with their respective value file contents.
function document_sub_placeholders_values( \
document, \
_fragment_out, _found_values, _i, _max_iterations \
) {
_fragment_out = document["values_index"]["_inline_build_entrypoint"]["value"]
_max_iterations = 100
while (find_values_placeholders_in_str(_fragment_out, document["values_index"], _found_values) > 0) {
if (_i > _max_iterations) {
print "Error: Possible circular template value placeholder use (" _max_iterations " iterations exceeded)"
exit 1
}
_fragment_out = sub_values_placeholders_in_str(_found_values, document["values_index"], _fragment_out)
delete _found_values
_i++
}
gsub(/\s+<!-- _block_.*-->/, "", _fragment_out)
document["fragment"] = _fragment_out
}
# Writes the specified document to it's build path.
function document_write( \
document, \
_path_dir_document_out, _path_file_document_out \
) {
_path_dir_document_out = _dir_dist "/" document["values_index"]["_inline_path"]["value"]
_path_file_document_out = _path_dir_document_out "/" document["values_index"]["_inline_filename"]["value"]
if (! system("mkdir -p " _path_dir_document_out)) {
print document["fragment"] >> _path_file_document_out
close(_path_file_document_out)
}
}
# Takes a document data structure and copies the document related static files into it's build directory.
function document_copy_static( \
document, \
_path_dir_src_static, _path_dir_dist_static \
) {
_path_dir_src_static = document["path_src"] "/static"
_path_dir_dist_static = _dir_dist "/" document["values_index"]["_inline_path"]["value"] "/"
if (! system("test -d " _path_dir_src_static)) system("cp -r " _path_dir_src_static "/* " _path_dir_dist_static)
}
# ------------------------------------------------------------------------------
BEGIN {
# ARGV[1] - source files directory path.
# ARGV[2] - build directory path.
if (! ARGV[1] || ! ARGV[2]) {
print "Error: Must provide paths of site and dist directories"
exit 1
}
_dir_site = readlink(ARGV[1])
_dir_dist = readlink(ARGV[2])
_dir_tmp = _dir_dist "/tmp"
print "Site source directory " _dir_site
print "Site build destination directory " _dir_dist
print "Site build temporary files directory " _dir_tmp
_values_files_index[0] = ""
_children_sitemap = ""
_static_asset_caching_id = "cache_" timestamp_unix()
# ----------------------------------------------------------------------------
print "\nCreating site build destination and build temporary files directories and subdirectories " _dir_tmp "/sitemap"
system("rm -rf " _dir_dist " && mkdir -p " _dir_tmp "/sitemap" " && mkdir -p " _dir_tmp "/build_info")
print "Created site build destination and build temporary files directories and subdirectories " _dir_tmp "/sitemap"
# ----------------------------------------------------------------------------
print "\nWriting build info site values in " _dir_tmp "/build_info"
_path_file_static_asset_caching_id = _dir_tmp "/build_info/_inline_static_asset_caching_id"
print _static_asset_caching_id >> _path_file_static_asset_caching_id
close(_path_file_static_asset_caching_id)
print "\nCreated build info site values in " _dir_tmp "/build_info"
# ----------------------------------------------------------------------------
print "\nIndexing generic document paths"
_cmd_find_documents = "find " _dir_site "/documents/* -maxdepth 0 -type d"
_i = 0
while ((_cmd_find_documents | getline _path_dir_src_document ) > 0) {
print " Indexed path for document " _path_dir_src_document
_paths_src_generic_documents_arr[_i] = _path_dir_src_document
_i++
}
close(_cmd_find_documents)
print "Indexed generic document paths"
# ----------------------------------------------------------------------------
print "\nIndexing generic document values"
for (_i in _paths_src_generic_documents_arr) {
print " Indexing values for document " _paths_src_generic_documents_arr[_i]
_generic_documents[_i]["path_src"] = _paths_src_generic_documents_arr[_i]
_generic_documents[_i]["paths_values_dir"][1] = _dir_site
_generic_documents[_i]["paths_values_dir"][2] = _paths_src_generic_documents_arr[_i]
_generic_documents[_i]["paths_values_dir"][3] = _dir_tmp "/build_info"
populate_values_files_index(_generic_documents[_i]["paths_values_dir"])
document_populate_values_index(_generic_documents[_i])
print " Indexed values for document " _paths_src_generic_documents_arr[_i]
}
print "Indexed generic document values"
# ----------------------------------------------------------------------------
print "\nBuilding generic documents"
for (_i in _generic_documents) {
print " Building document " _generic_documents[_i]["path_src"]
document_sub_placeholders_values(_generic_documents[_i])
document_write(_generic_documents[_i])
document_copy_static(_generic_documents[_i])
print " Built document " _generic_documents[_i]["path_src"]
}
print "Built generic documents"
# ----------------------------------------------------------------------------
print "\nBuilding sitemap document entries for generic documents"
for (_i in _generic_documents) {
if (match(_generic_documents[_i]["values_index"]["_inline_filename"]["value"], /(403\.html$|404\.html$|manifest\.webmanifest$|robots\.txt$)/)) {
print " Skipped building sitemap document entry for generic document " _generic_documents[_i]["path_src"]
continue
}
print " Building sitemap document entry for generic document " _generic_documents[_i]["path_src"]
_sitemap_entry["paths_values_dir"][1] = _dir_site
_sitemap_entry["paths_values_dir"][2] = _generic_documents[_i]["path_src"]
_sitemap_entry["paths_values_dir"][3] = _dir_site "/sitemap/url"
populate_values_files_index(_sitemap_entry["paths_values_dir"])
document_populate_values_index(_sitemap_entry)
document_sub_placeholders_values(_sitemap_entry)
_children_sitemap = _children_sitemap _sitemap_entry["fragment"]
print " Built sitemap document entry for generic document " _generic_documents[_i]["path_src"]
}
_path_file_children_sitemap = _dir_tmp "/sitemap/_block_sitemap_children.xml"
print _children_sitemap >> _path_file_children_sitemap
close(_path_file_children_sitemap)
print "Built sitemap document entries for generic documents"
# ----------------------------------------------------------------------------
print "\nBuilding sitemap document"
_sitemap["paths_values_dir"][1] = _dir_site
_sitemap["paths_values_dir"][2] = _dir_site "/sitemap/document"
_sitemap["paths_values_dir"][3] = _dir_tmp "/sitemap"
populate_values_files_index(_sitemap["paths_values_dir"])
document_populate_values_index(_sitemap)
document_sub_placeholders_values(_sitemap)
document_write(_sitemap)
print "Built sitemap document"
# ----------------------------------------------------------------------------
print "\nRemoving site temporary files directory " _dir_tmp
system("rm -rf " _dir_tmp)
print "Removed site temporary files directory " _dir_tmp
# ----------------------------------------------------------------------------
print "\nDone!"
exit
}