aboutsummaryrefslogtreecommitdiff
path: root/src/lib/builder.lua
blob: 1a9b0af924dd8840ebd8cfad9119922ee909b0c9 (plain)
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
Builder = {}

function Builder:from_template(path)
	local builder = {
		template = loadfile(
			tostring(path),
			nil,
			Env.Sandbox {
				Template = Template
			}
		)(),
		source = path,
	}

	if not builder.template or getmetatable(builder.template) ~= Template then
		error('invalid template')
	end

	builder.source_directory = builder.source:parent()

	setmetatable(builder, self)
	self.__index = self

	local argument_template = {
		strict = true,
		{ name = "target" },
		{ name = "template", description = "some description", kind = "property", required = true },
	};

	for key, value in pairs(builder.template.options) do
		argument_template[#argument_template + 1] = value
	end

	local args = require('arg')(argument_template)

	for key, _ in pairs(builder.template.options) do
		builder.template.arguments[key] = args[key]
	end

	return builder
end

function Builder:entries()
	local entries = {}

	for _, value in ipairs(self.template.files) do
		entries[#entries + 1] = {
			path = self.source_directory / value.path,
			env = value.env,
		}
	end

	for _, value in ipairs(self.template.directories) do
		for entry in (self.source_directory / value.path):children() do
			entries[#entries + 1] = {
				path = entry,
				env = value.env,
			}
		end
	end

	local i = 1
	return function()
		local value = entries[i]
		i = i + 1
		return value
	end
end

function Builder:build(args)
	local instance = Instance:new()

	for entry in self:entries() do
		instance:register(
			entry.path:relative_to_parent(self.source_directory),
			not entry.path:is_directory() and self:process_file(entry) or nil
		)
	end

	return instance
end

function Builder:process_file(file)
	if not file.path:exists() then
		error(tostring(file.path) .. ' does not exist.')
	end

	local f = file.path:open("r")
	local raw = f:read("*all")
	f:close()

	local content = ''

	for _, split in ipairs(raw:split_into_template_blocks()) do
		if split.kind == 'text' then
			content = content .. split.content
		else
			local func, err = load(
				'return ' .. split.content,
				'macro ' .. tostring(file.path),
				't',
				Env.Sandbox(file.env)
			)

			if err then
				error(err)
			end

			local value = func()
			if type(value) == 'function' then
				content = content .. tostring(value())
			else
				content = content .. tostring(value)
			end
		end
	end

	return content
end