Project

General

Profile

Download (21.4 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / compute_scripts.awk @ 57ce414c

1 b590eaa2 Wojtek Kosior
#!/usr/bin/awk -f
2
#
3 6106c789 Wojtek Kosior
# SPDX-License-Identifier: CC0-1.0
4
#
5
# Process javascript files and resolve dependencies between them
6
#
7
# This file is part of Haketilo
8
#
9
# Copyright (C) 2021, Wojtek Kosior
10
#
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the CC0 1.0 Universal License as published by
13
# the Creative Commons Corporation.
14
#
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
# CC0 1.0 Universal License for more details.
19
20 b590eaa2 Wojtek Kosior
BEGIN {
21
    true = 1
22
    false = 0
23
}
24
25
BEGIN {
26 c71ebff8 Wojtek Kosior
    identifier_re    = "[_a-zA-Z][_a-zA-Z0-9]*"
27
    path_dir_re      = "([-_a-zA-Z0-9][-._a-zA-Z0-9]*/)*"
28
    path_ext_re      = "(\\.[-_.a-zA-Z0-9]*)?"
29
    path_re_noanchor = path_dir_re identifier_re path_ext_re
30
    path_re          = "^" path_re_noanchor "$"
31 b590eaa2 Wojtek Kosior
32 702eefd2 Wojtek Kosior
    if_clause_re = "!?" identifier_re
33
    if_AND_re    = "([[:space:]]+&&[[:space:]]+" if_clause_re ")*"
34
    if_OR_re     = "([[:space:]]+[|][|][[:space:]]+" if_clause_re ")*"
35
36
    directive_args_patterns["IF"]      = ("^" if_clause_re \
37
					  "(" if_AND_re "|" if_OR_re ")$")
38 b590eaa2 Wojtek Kosior
    directive_args_patterns["ENDIF"]   = "^$"
39
    directive_args_patterns["ELSE"]    = "^$"
40
    directive_args_patterns["ELIF"]    = "^(NOT[[:space:]]+)?" identifier_re "$"
41 448820a1 Wojtek Kosior
    directive_args_patterns["DEFINE"]  = "^" identifier_re "$"
42
    directive_args_patterns["UNDEF"]   = "^" identifier_re "$"
43 b590eaa2 Wojtek Kosior
    directive_args_patterns["ERROR"]   = "^.*$"
44
    directive_args_patterns["COPY"]    = "^[^[:space:]]+$"
45
    directive_args_patterns["INCLUDE"] = "^[^[:space:]]+$"
46
    directive_args_patterns["INCLUDE_VERBATIM"] = "^[^[:space:]]+$"
47
48
    AS_re                = "AS[[:space:]]+" identifier_re
49
    maybe_AS_re          = "([[:space:]]+" AS_re ")?"
50
    FROM_clause_re       = identifier_re maybe_AS_re
51
    more_FROM_clauses_re = "([[:space:]]*,[[:space:]]*" FROM_clause_re ")*"
52
    FROM_IMPORT_re       = "[^[:space:]]+[[:space:]]+IMPORT[[:space:]]+"
53
    EXPORT_AS_re         = ".*[^[:space:]][[:space:]]+" AS_re
54
55
    directive_args_patterns["IMPORT"] = "^[^[:space:]]+" maybe_AS_re "$"
56
    directive_args_patterns["FROM"]   = ("^" FROM_IMPORT_re FROM_clause_re \
57
					 more_FROM_clauses_re "$")
58
    directive_args_patterns["EXPORT"] = "^(" EXPORT_AS_re "|" identifier_re ")$"
59
60
    directive_args_patterns["LOADJS"] = "^[^[:space:]]+$"
61 a00926f1 Wojtek Kosior
    directive_args_patterns["LOADCSS"] = "^[^[:space:]]+$"
62 448820a1 Wojtek Kosior
63
    directive_args_patterns["LOADHTML"] = "^[^[:space:]]+$"
64 b590eaa2 Wojtek Kosior
}
65
66
function validate_path(read_path, path, line) {
67
    if (path !~ (path_re)) {
68
	printf "ERROR: File path in %s does not match '%s': %s\n",
69
	    read_path, path_re, line > "/dev/stderr"
70
	return 1
71
    }
72
73
    return 0
74
}
75
76
function identifier_from_path(path) {
77
    sub("^" path_dir_re, "", path)
78
    sub(path_ext_re "$", "", path)
79
80
    return path
81
}
82
83
function last_token(line) {
84
    sub("^.*[[:space:]]", "", line)
85
86
    return line
87
}
88
89
function first_token(line) {
90
    sub("[[:space:]].*$", "", line)
91
92
    return line
93
}
94
95
function is_empty(array,    key) {
96
    for (key in array)
97
	return false
98
    return true
99
}
100 6106c789 Wojtek Kosior
101 b590eaa2 Wojtek Kosior
function clear_array(array,    key) {
102
    for (key in array)
103
	delete array[key]
104
}
105
106
function add_line(path, line, where) {
107
    if (where != "amalgamation_root_file")
108
	lines[path,++lines_count[path]] = line
109
110
    if (where != "non_amalgamation_file" &&
111
	path == js_to_amalgamate)
112
	main_js_lines[++main_js_lines_count] = line
113
}
114
115
BEGIN {
116
    delete page_js_deps[0]
117
    page_js_deps_count = 0
118
}
119
120
function process_file(path, read_path, mode,
121
		      line, result, line_part, directive, directive_args,
122 5acb2499 Wojtek Kosior
		      if_nesting, if_nesting_true, if_branch_processed) {
123 b590eaa2 Wojtek Kosior
    if (path in modes && modes[path] != mode) {
124
	printf "ERROR: File %s used multiple times in different contexts\n",
125
	    path > "/dev/stderr"
126
	return 1
127
    }
128
129
    if (mode == "html" && path == read_path) {
130
	clear_array(page_js_deps)
131
	page_js_deps_count = 0
132 a00926f1 Wojtek Kosior
	clear_array(page_css_deps)
133 b590eaa2 Wojtek Kosior
    }
134
135
    modes[path] = mode
136
137
    if (!(path in reading)) {
138
	if (path in lines_count)
139
	    return 0
140
	lines_count[path]
141
    }
142
143
    reading[read_path]
144
145
    if (mode == "js" && path == read_path) {
146
	add_line(path, "\"use strict\";")
147
	add_line(path, "this.haketilo_exports = this.haketilo_exports || {};")
148
	add_line(path, "this.haketilo_exports[\"" path "\"] = {};")
149
150
	add_line(path, "window.globalThis = this", "amalgamation_root_file")
151
152
	add_line(path, "")
153
154
	add_line(path, "(function() {", "non_amalgamation_file")
155
	add_line(path, "var globalThis = this.haketilo_this",
156
		                        "non_amalgamation_file")
157
	add_line(path, "{",             "non_amalgamation_file")
158
    }
159
160
    while (true) {
161
	result = (getline line < read_path)
162 6106c789 Wojtek Kosior
	if (result < 0) {
163 b590eaa2 Wojtek Kosior
	    printf "ERROR: Could not read %s\n", read_path > "/dev/stderr"
164
	    return 1
165 6106c789 Wojtek Kosior
	}
166 01e977f9 Wojtek Kosior
	if (result == 0) {
167 c71ebff8 Wojtek Kosior
	    if (!(path in appended_lines_counts) || \
168 5acb2499 Wojtek Kosior
		additional_line_nr[path] == appended_lines_counts[path])
169 01e977f9 Wojtek Kosior
		break
170
171 5acb2499 Wojtek Kosior
	    line = appended_lines[path,++additional_line_nr[path]]
172 01e977f9 Wojtek Kosior
	}
173 6106c789 Wojtek Kosior
174 b590eaa2 Wojtek Kosior
	if (line !~ /^#/) {
175
	    if (if_nesting_true == if_nesting)
176
		add_line(path, line)
177
	    continue
178
	}
179 6106c789 Wojtek Kosior
180 b590eaa2 Wojtek Kosior
	while (line ~ /\\$/) {
181
	    sub(/\\$/, "", line)
182 6106c789 Wojtek Kosior
183 b590eaa2 Wojtek Kosior
	    result = (getline line_part < read_path)
184
	    if (result < 0) {
185
		printf "ERROR: Could not read %s\n", read_path > "/dev/stderr"
186
		return 1
187
	    }
188
	    if (result == 0) {
189 c71ebff8 Wojtek Kosior
		if (path in appended_lines_counts && \
190 5acb2499 Wojtek Kosior
		    additional_line_nr[path] < appended_lines_counts[path]) {
191
		    line_part = appended_lines[path,++additional_line_nr[path]]
192 01e977f9 Wojtek Kosior
		} else {
193
		    printf "ERROR: Unexpected EOF in %s\n",
194
			read_path > "/dev/stderr"
195
		    return 1
196
		}
197 b590eaa2 Wojtek Kosior
	    }
198
199
	    line = line " " line_part
200
	}
201
202
	directive = substr(line, 2)
203
	sub(/[[:space:]].*$/, "", directive)
204
205
	if (directive !~ \
206 448820a1 Wojtek Kosior
	    /^(IF|ENDIF|ELSE|ELIF|DEFINE|UNDEF|ERROR|INCLUDE|INCLUDE_VERBATIM|COPY_FILE)$/ &&
207 b590eaa2 Wojtek Kosior
	    (mode != "js" || directive !~ /^(IMPORT|FROM|EXPORT)$/) &&
208 a00926f1 Wojtek Kosior
	    (mode != "html" || directive !~ /^(LOADJS|LOADCSS)$/) &&
209 b590eaa2 Wojtek Kosior
	    (mode != "manifest" || directive !~ /^(LOADJS|LOADHTML)$/)) {
210
	    printf "ERROR: Invalid # directive in %s: %s\n",
211
		read_path, line > "/dev/stderr"
212
	    return 1
213
	}
214
215
	directive_args = line
216
	sub(/^#[^[:space:]]*[[:space:]]*/, "", directive_args)
217
	sub(/[[:space:]]*$/, "", directive_args)
218
219
	if (directive_args !~ directive_args_patterns[directive]) {
220
	    printf "ERROR: #%s arguments in %s do not match '%s': %s\n",
221
		directive, read_path, directive_args_patterns[directive], line \
222
		> "/dev/stderr"
223
	    return 1
224 6106c789 Wojtek Kosior
	}
225 b590eaa2 Wojtek Kosior
226
	if (directive == "IF") {
227
	    if (if_nesting_true == if_nesting) {
228 448820a1 Wojtek Kosior
		if (if_condition_true(directive_args, path))
229 b590eaa2 Wojtek Kosior
		    if_nesting_true++
230
		else
231
		    if_branch_processed = false
232 6106c789 Wojtek Kosior
	    }
233
234 b590eaa2 Wojtek Kosior
	    if_nesting++
235
	} else if (directive == "ENDIF") {
236
	    if (if_nesting == 0) {
237
		printf "ERROR: Spurious #ENDIF in %s\n",
238
		    read_path > "/dev/stderr"
239
		return 1
240
	    }
241
242
	    if (if_nesting_true == if_nesting)
243
		if_nesting_true--
244
245
	    if_nesting--
246
	} else if (directive == "ELSE") {
247
	    if (if_nesting == 0) {
248
		printf "ERROR: Spurious #ELSE in %s\n",
249
		    read_path > "/dev/stderr"
250
		return 1
251
	    }
252
253
	    if (if_nesting == if_nesting_true + 1 && !if_branch_processed) {
254
		if_nesting_true++
255
	    } else if (if_nesting == if_nesting_true) {
256
		if_branch_processed = true
257
		if_nesting_true--
258
	    }
259
	} else if (directive == "ELIF") {
260
	    if (if_nesting == 0) {
261
		printf "ERROR: Spurious #ELIF in %s\n",
262
		    read_path > "/dev/stderr"
263
		return 1
264
	    }
265
266
	    if (if_nesting == if_nesting_true + 1 && !if_branch_processed &&
267 448820a1 Wojtek Kosior
		if_condition_true(directive_args, path)) {
268 b590eaa2 Wojtek Kosior
		if_nesting_true++
269
	    } else if (if_nesting == if_nesting_true) {
270
		if_branch_processed = true
271
		if_nesting_true--
272
	    }
273
	} else if (if_nesting_true != if_nesting) {
274
	    continue
275 448820a1 Wojtek Kosior
	} else if (directive == "DEFINE") {
276
	    defines[path,directive_args]
277
	} else if (directive == "UNDEF") {
278
	    delete defines[path,directive_args]
279 b590eaa2 Wojtek Kosior
	} else if (directive == "ERROR") {
280
	    printf "ERROR: File %s says: %s\n",
281
		read_path, directive_args > "/dev/stderr"
282
	    return 1
283
	} else if (directive == "INCLUDE") {
284
	    if (include_file(path, read_path, directive_args, line))
285
		return 1
286
	} else if (directive == "INCLUDE_VERBATIM") {
287
	    if (include_file(path, read_path, directive_args, line, true))
288
		return 1
289
	} else if (directive == "COPY_FILE") {
290
	    if (mark_copy_file(path, read_path, directive_args, line))
291
		return 1
292
	} else if (directive == "IMPORT") {
293
	    if (import_js_file(path, read_path, directive_args, line))
294
		return 1
295
	} else if (directive == "FROM") {
296
	    if (import_from_js_file(path, read_path, directive_args, line))
297
		return 1
298
	} else if (directive == "EXPORT") {
299
	    if (export_from_js_file(path, read_path, directive_args, line))
300
		return 1
301
	} else if (directive == "LOADJS") {
302
	    if (mode == "html") {
303
		page_js_deps_count = \
304
		    load_js_file(path, read_path, directive_args, line,
305
				 page_js_deps, page_js_deps_count)
306
		if (page_js_deps_count < 1)
307
		    return 1
308
	    } else if (mode == "manifest") {
309
		if (load_js_file(path, read_path, directive_args, line) < 1)
310
		    return 1
311
	    }
312 a00926f1 Wojtek Kosior
	} else if (directive == "LOADCSS") {
313
	    if (load_css_file(path, read_path, directive_args, line,
314
			      page_css_deps))
315
		return 1
316 b590eaa2 Wojtek Kosior
	} else if (directive == "LOADHTML") {
317
	    if (load_html_file(path, read_path, directive_args, line))
318
		return 1
319 6106c789 Wojtek Kosior
	}
320 b590eaa2 Wojtek Kosior
    }
321
322
    close(read_path)
323 6106c789 Wojtek Kosior
324 b590eaa2 Wojtek Kosior
    if (if_nesting) {
325
	printf "ERROR: Unterminated #IF in %s\n", read_path > "/dev/stderr"
326
	return 1
327 6106c789 Wojtek Kosior
    }
328
329 b590eaa2 Wojtek Kosior
    if (mode == "js" && path == read_path) {
330
	add_line(path, "}",         "non_amalgamation_file")
331
	add_line(path, "}).call({", "non_amalgamation_file")
332
	add_line(path, "    haketilo_exports: this.haketilo_exports,",
333
		                    "non_amalgamation_file")
334
	add_line(path, "    haketilo_this:    this",
335
		                    "non_amalgamation_file")
336
	add_line(path, "});",       "non_amalgamation_file")
337 6106c789 Wojtek Kosior
    }
338
339 b590eaa2 Wojtek Kosior
    delete reading[read_path]
340 6106c789 Wojtek Kosior
}
341
342 448820a1 Wojtek Kosior
function if_condition_true(directive_args, path,
343 702eefd2 Wojtek Kosior
			   result, bool, first_iter, word, negated, alt) {
344
    first_iter = true
345
346
    while (directive_args) {
347
	word = first_token(directive_args)
348
	sub(/^[^[:space:]]+[[:space:]]*/, "", directive_args)
349
	alt = alt || directive_args ~ /^[|][|]/
350
	sub(/^[^[:space:]]+[[:space:]]*/, "", directive_args)
351
352
	negated = word ~ /^!/
353
	sub(/^!/, "", word)
354 448820a1 Wojtek Kosior
	bool = (word in defines || (path,word) in defines) != negated
355 702eefd2 Wojtek Kosior
356
	if (first_iter) {
357
	    result = bool
358
	    first_iter = false
359
	    continue
360
	}
361
362
	if (alt)
363
	    result = result || bool
364
	else # if (directive_args ~ /^AND/)
365
	    result = result && bool
366
    }
367
368
    return result
369
}
370
371 b590eaa2 Wojtek Kosior
function include_file(root_path, read_path, included_path, line, verbatim,
372
		      read_line, result) {
373
    if (included_path in reading) {
374
	printf "ERROR: Inclusion loop when including %s in %s\n",
375
	    included_path, read_path > "/dev/stderr"
376
	return 1
377
    }
378
379
    if (verbatim) {
380
	while(true) {
381
	    result = (getline read_line < included_path)
382
	    if (result > 0)
383
		add_line(root_path, read_line)
384
	    else
385
		break
386
	}
387
388
	if (result == 0) {
389
	    close(included_path)
390
	    return 0
391
	}
392 6106c789 Wojtek Kosior
393 b590eaa2 Wojtek Kosior
	printf "ERROR: Could not read %s\n", included_path > "/dev/stderr"
394
    } else {
395
	if (process_file(root_path, included_path, modes[root_path]) == 0)
396
	    return 0
397
    }
398
399
    printf "       when including %s in %s\n",
400
	included_path, read_path > "/dev/stderr"
401
402
    return 1
403 6106c789 Wojtek Kosior
}
404
405 b590eaa2 Wojtek Kosior
function mark_copy_file(root_path, read_path, copied_path, line) {
406
    if (validate_path(read_path, copied_path, line))
407
	return 1
408
409
    to_copy[copied_path]
410
411
    return 0
412
}
413
414
function satisfy_import(root_path, imported_path, as, what,
415
			added_line, description, count) {
416
    if ((root_path,as) in imports_from) {
417
	printf "ERROR: Multiple items imported under the name '%s' in %s\n",
418
	    as, root_path > "/dev/stderr"
419
	return 1
420 6106c789 Wojtek Kosior
    }
421 b590eaa2 Wojtek Kosior
422
    added_line = " " as " = haketilo_exports[\"" imported_path "\"]"
423
    if (what)
424
	added_line = added_line "." what
425
426
    add_line(root_path, "const" added_line ";", "non_amalgamation_file")
427
    add_line(root_path, "let"   added_line ";", "amalgamation_root_file")
428
429
    count = ++import_counts[root_path]
430
431
    imports_as  [root_path,count] = as
432
    imports_from[root_path,as]    = imported_path
433
    imports_what[root_path,as]    = what
434
435
    if (what)
436
	description = "'" what "' from " imported_path
437
    else
438
	description = imported_path
439
440
    description = description " needed by " root_path
441
442
    if (imported_path in reading) {
443
	printf "ERROR: dependency loop when importing %s\n",
444
	    description > "/dev/stderr"
445
	return 1
446
    } else if (process_file(imported_path, imported_path, "js")) {
447
	printf "       when importing %s\n", description > "/dev/stderr"
448
	return 1
449
    }
450
451
    if (what && !((imported_path,what) in exports)) {
452
	printf "ERROR: %s doesn't export '%s' needed by %s\n",
453
	    imported_path, what, root_path > "/dev/stderr"
454
	return 1
455
    }
456
457
    return 0
458 6106c789 Wojtek Kosior
}
459
460 b590eaa2 Wojtek Kosior
function import_js_file(root_path, read_path, directive_args, line,
461
			imported_path, as) {
462
    imported_path = first_token(directive_args)
463
    if (validate_path(read_path, imported_path, line))
464
	return 1
465
466
    if (line ~ (AS_re "$"))
467
	as = last_token(directive_args)
468
    else
469
	as = identifier_from_path(imported_path)
470
471
    return satisfy_import(root_path, imported_path, as)
472
}
473
474
function import_from_js_file(root_path, read_path, directive_args, line,
475
			     imported_path, args_copy, FROM_clause, as) {
476
    imported_path = first_token(directive_args)
477
    if (validate_path(read_path, imported_path, line))
478
	return 1
479
480
    args_copy = directive_args
481
    sub("^" FROM_IMPORT_re, "", args_copy)
482
    args_copy = "," args_copy
483
484
    while (args_copy ~ /,/) {
485
	sub(/^[^,]*,[[:space:]]*/, "", args_copy)
486
487
	FROM_clause = args_copy
488
	sub(/[[:space:]]*,.*$/, "", FROM_clause)
489
490
	if (satisfy_import(root_path, imported_path,
491
			   last_token(FROM_clause), first_token(FROM_clause)))
492
	    return 1
493 6106c789 Wojtek Kosior
    }
494 b590eaa2 Wojtek Kosior
495
    return 0
496 6106c789 Wojtek Kosior
}
497
498 b590eaa2 Wojtek Kosior
function export_from_js_file(root_path, read_path, directive_args, line,
499
			     as, exported_item, added_line) {
500
    as = last_token(directive_args)
501
502
    if (directive_args ~ ("^" identifier_re "$")) {
503
	exported_item = as
504
    } else {
505
	exported_item = directive_args
506
	sub("[[:space:]]+" AS_re "$", "", exported_item)
507
    }
508
509
    if ((root_path,as) in exports) {
510
	printf "ERROR: Multiple values exported under the name '%s' in %s\n",
511
	    as, root_path > "/dev/stderr"
512
	return 1
513
    }
514 9a7623de Wojtek Kosior
515 b590eaa2 Wojtek Kosior
    added_line = \
516
    "this.haketilo_exports[\"" root_path "\"]." as " = (" exported_item ");"
517
    add_line(root_path, added_line)
518 6106c789 Wojtek Kosior
519 b590eaa2 Wojtek Kosior
    exports[root_path,as]
520 6106c789 Wojtek Kosior
521 b590eaa2 Wojtek Kosior
    return 0
522 93dd7360 Wojtek Kosior
}
523
524 b590eaa2 Wojtek Kosior
function compute_deps(js_path, dependencies, count, dependencies_added,
525
		      i_max, i, as, next_path) {
526
    delete dependencies_added[0]
527 93dd7360 Wojtek Kosior
528 b590eaa2 Wojtek Kosior
    if (process_file(js_path, js_path, "js"))
529
	return 0
530 93dd7360 Wojtek Kosior
531 b590eaa2 Wojtek Kosior
    i_max = import_counts[js_path]
532
    for (i = 1; i <= i_max; i++) {
533
	as = imports_as[js_path,i]
534
	next_path = imports_from[js_path,as]
535
	if (next_path in dependencies_added)
536
	    continue
537
538
	count = compute_deps(next_path, dependencies, count, dependencies_added)
539
	if (count < 1)
540
	    return 0
541
    }
542
543
    dependencies_added[js_path]
544
    dependencies[++count] = js_path
545
546
    return count
547 6106c789 Wojtek Kosior
}
548
549 b590eaa2 Wojtek Kosior
# Here js_deps and js_deps_count are optional args, used when loading scripts
550 a00926f1 Wojtek Kosior
# into an HTML page to avoid having the same script loaded twice in multiple
551 b590eaa2 Wojtek Kosior
# places.
552
function load_js_file(root_path, read_path, loaded_path, line,
553
		      js_deps, js_deps_count,
554
		      js_deps_already_added, i, added_line) {
555
    delete js_deps[""]
556
    delete js_deps_already_added[0]
557
558
    if (validate_path(read_path, loaded_path, line))
559 6106c789 Wojtek Kosior
	return 0
560
561 b590eaa2 Wojtek Kosior
    for (i = 1; i <= js_deps_count; i++)
562
	js_deps_already_added[js_deps[i]]
563
564
    i = js_deps_count
565
566
    js_deps_count = compute_deps(loaded_path, js_deps,
567
				 js_deps_count, js_deps_already_added)
568
569
    if (js_deps_count < 1) {
570
	printf "       when loading %s from %s\n",
571
	    loaded_path, read_path > "/dev/stderr"
572
	return 0
573
    }
574
575
    while (++i <= js_deps_count) {
576
	if (modes[root_path] == "html") {
577
	    added_line = "<script src=\"/" js_deps[i] "\"></script>"
578
	} else { #if (modes[root_path] == "manifest") {
579
	    added_line = "\"" js_deps[i] "\""
580
	    if (i != js_deps_count)
581
		added_line = added_line ","
582
	}
583
	add_line(root_path, added_line)
584
    }
585
586
    return js_deps_count
587
}
588
589 a00926f1 Wojtek Kosior
# css_deps is an array used to avoid having the same stylesheet loaded twice in
590
# multiple places in a single HTML page.
591
function load_css_file(root_path, read_path, loaded_path, line, css_deps) {
592
    delete css_deps[""]
593
594
    if (validate_path(read_path, loaded_path, line))
595
	return 1
596
597
    if (!(loaded_path in css_deps)) {
598
	css_deps[loaded_path]
599
	to_copy[loaded_path]
600
	added_line = ("<link rel=\"stylesheet\" type=\"text/css\" "	\
601
		      "href=\"/" loaded_path "\" />")
602
	add_line(root_path, added_line)
603
    }
604
605
    return 0
606
}
607
608 b590eaa2 Wojtek Kosior
function load_html_file(root_path, read_path, loaded_path, line) {
609
    if (validate_path(read_path, loaded_path, line))
610
	return 1
611
612
    if (process_file(loaded_path, loaded_path, "html")) {
613
	printf "       when loading %s from %s\n",
614
	    loaded_path, read_path, line > "/dev/stderr"
615 6106c789 Wojtek Kosior
	return 1
616
    }
617
618 b590eaa2 Wojtek Kosior
    return 0
619
}
620 6106c789 Wojtek Kosior
621 b590eaa2 Wojtek Kosior
function print_amalgamation(js_deps, js_deps_count,
622
			    js_dep_nr, path, max_line_nr, line_nr) {
623
    delete js_deps[0]
624 6106c789 Wojtek Kosior
625 b590eaa2 Wojtek Kosior
    js_deps_count = compute_deps(js_to_amalgamate, js_deps, 0)
626
    if (js_deps_count < 1)
627
	return 1
628
629
    # '<' instead of '<=' because we print the main js file below instead
630
    for (js_dep_nr = 1; js_dep_nr < js_deps_count; js_dep_nr++) {
631
	path = js_deps[js_dep_nr]
632
	max_line_nr = lines_count[path]
633
634
	for (line_nr = 1; line_nr <= max_line_nr; line_nr++)
635
	    print lines[path, line_nr]
636 6106c789 Wojtek Kosior
    }
637
638 b590eaa2 Wojtek Kosior
    for (line_nr = 1; line_nr <= main_js_lines_count; line_nr++)
639
	    print main_js_lines[line_nr]
640 6106c789 Wojtek Kosior
641
    return 0
642
}
643
644
function print_usage() {
645 5acb2499 Wojtek Kosior
    printf "USAGE: %s compute_scripts.awk -- [-D PREPROCESSOR_DEFINITION]... [-M manifest/to/process/manifest.json]... [-H html/to/process.html]... [-J js/to/process.js]... [-A file/to/append/to.js:appended_code]... [--help|-h] [--output-dir=./build] [--write-js-deps] [--write-html-deps] [--output=files-to-copy|--output=amalgamate-js:js/to/process.js]\n",
646 6106c789 Wojtek Kosior
	ARGV[0] > "/dev/stderr"
647
}
648
649 b590eaa2 Wojtek Kosior
BEGIN {
650
    option_arg_patterns["D"] = "^" identifier_re "$"
651
    option_arg_patterns["M"] = path_re
652
    option_arg_patterns["H"] = path_re
653
    option_arg_patterns["J"] = path_re
654 c71ebff8 Wojtek Kosior
    option_arg_patterns["A"] = "^" path_re_noanchor ":"
655 6106c789 Wojtek Kosior
}
656
657 c71ebff8 Wojtek Kosior
function main(i, j, path, letter, dir, max_line_nr, js_deps, js_deps_count,
658 3840192d Wojtek Kosior
	      code, tmp_lines) {
659 b590eaa2 Wojtek Kosior
    output_dir = "./build"
660
    write_js_deps = false
661
    write_html_deps = false
662 6106c789 Wojtek Kosior
663 c71ebff8 Wojtek Kosior
    delete appended_lines[0]
664
    delete appended_lines_counts[0]
665 3840192d Wojtek Kosior
    delete tmp_lines[0]
666 c71ebff8 Wojtek Kosior
667
    delete lines[0]
668 3840192d Wojtek Kosior
    delete lines_count[0]
669 c71ebff8 Wojtek Kosior
670 b590eaa2 Wojtek Kosior
    output = ""
671
    js_to_amalgamate = ""
672
    delete main_js_lines[0]
673 6106c789 Wojtek Kosior
674 b590eaa2 Wojtek Kosior
    delete manifests_to_process[0]
675
    delete html_to_process[0]
676
    delete js_to_process[0]
677 6106c789 Wojtek Kosior
678 b590eaa2 Wojtek Kosior
    delete explicitly_requested[0]
679 6106c789 Wojtek Kosior
680 b590eaa2 Wojtek Kosior
    for (i = 1; i < ARGC; i++) {
681 c71ebff8 Wojtek Kosior
	if (ARGV[i] ~ /^-[DMHJA]$/) {
682 b590eaa2 Wojtek Kosior
	    letter = substr(ARGV[i++], 2)
683
	    if (i == ARGC || ARGV[i] !~ option_arg_patterns[letter]) {
684
		printf "ERROR: '-%s' option should be followed by an argument matching '%s'\n",
685
		    letter, option_arg_patterns[letter] > "/dev/stderr"
686
		return 1
687
	    }
688 6106c789 Wojtek Kosior
689 b590eaa2 Wojtek Kosior
	    if (letter == "D")
690
		defines[ARGV[i]]
691
	    else
692
		explicitly_requested[ARGV[i]]
693
694
	    if (letter == "M")
695
		manifests_to_process[ARGV[i]]
696
	    if (letter == "H")
697
		html_to_process[ARGV[i]]
698
	    if (letter == "J")
699
		js_to_process[ARGV[i]]
700 c71ebff8 Wojtek Kosior
701
	    if (letter == "A") {
702
		path = ARGV[i]
703
		sub(/:.*$/, "", path)
704
		if (path in appended_lines_counts) {
705
		    printf "ERROR: The same file %s given to the '-A' option multiple times\n",
706
			path > "/dev/stderr"
707
		    return 1
708
		}
709
710 3840192d Wojtek Kosior
		clear_array(tmp_lines)
711 c71ebff8 Wojtek Kosior
		code = ARGV[i]
712
		sub(/^[^:]+:/, "", code)
713 3840192d Wojtek Kosior
		appended_lines_counts[path] = split(code, tmp_lines, "\n")
714 c71ebff8 Wojtek Kosior
		for (j = appended_lines_counts[path]; j > 0; j--)
715 3840192d Wojtek Kosior
		    appended_lines[path,j] = tmp_lines[j]
716 c71ebff8 Wojtek Kosior
	    }
717 b590eaa2 Wojtek Kosior
	} else if (ARGV[i] ~ /^-(-help|h)$/ ) {
718
	    print_usage()
719
	    return 0
720
	} else if (ARGV[i] ~ /^--output-dir=/) {
721
	    output_dir = ARGV[i]
722
	    sub(/^--output-dir=/, "", output_dir)
723
	} else if (ARGV[i] ~ /^--write-js-deps$/) {
724
	    write_js_deps = true
725
	} else if (ARGV[i] ~ /^--write-html-deps$/) {
726
	    write_html_deps = true
727
	} else if (ARGV[i] ~ /^--output=files-to-copy$/) {
728
	    output = "files-to-copy"
729
	} else if (ARGV[i] ~ /^--output=amalgamate-js:/) {
730
	    output = "amalgamate-js"
731 c71ebff8 Wojtek Kosior
	    js_to_amalgamate = ARGV[i]
732
	    sub(/^--output=amalgamate-js:/, "", js_to_amalgamate)
733 b590eaa2 Wojtek Kosior
	    if (js_to_amalgamate !~ path_re) {
734
		printf "ERROR: amalgamate-js path does not match '%s': %s\n",
735
		    path_re, js_to_amalgamate > "/dev/stderr"
736
		return 1
737
	    }
738
	} else {
739
		printf "ERROR: Unknown option '%s'\n", ARGV[i] > "/dev/stderr"
740
		print_usage()
741
		return 1
742
	}
743 6106c789 Wojtek Kosior
    }
744
745 b590eaa2 Wojtek Kosior
    if (is_empty(explicitly_requested) && output != "amalgamate-js") {
746
	explicitly_requested["manifest.json"]
747
	manifests_to_process["manifest.json"]
748 6106c789 Wojtek Kosior
    }
749 b590eaa2 Wojtek Kosior
750
    for (path in manifests_to_process) {
751
	if (process_file(path, path, "manifest"))
752
	    return 1
753
    }
754
    for (path in html_to_process) {
755
	if (process_file(path, path, "html"))
756
	    return 1
757
    }
758
    for (path in js_to_process) {
759
	if (process_file(path, path, "js"))
760
	    return 1
761
    }
762
763
    for (path in lines_count) {
764
	if (!(path in explicitly_requested) &&
765
	    !(modes[path] == "js" && write_js_deps) &&
766
	    !(modes[path] == "html" && write_html_deps))
767
	    continue
768
769
	dir = path
770
	sub(/[^/]*$/, "", dir)
771
	dir = output_dir "/" dir
772
	sub("'", "'\\''", dir)
773
774
	system("mkdir -p '" dir "'")
775
776
	printf "" > (output_dir "/" path)
777
778
	max_line_nr = lines_count[path]
779
	for (i = 1; i <= max_line_nr; i++)
780
	    print lines[path, i] >> (output_dir "/" path)
781
    }
782
783
    if (output == "files-to-copy") {
784
	for (path in to_copy)
785
	    print path
786
    }
787
788
    if (output == "amalgamate-js") {
789
	if (print_amalgamation())
790
	    return 1
791
    }
792
793
    return 0
794
}
795
796
BEGIN {
797
    exit main()
798 6106c789 Wojtek Kosior
}