-
Notifications
You must be signed in to change notification settings - Fork 181
/
Copy pathgenerate-profile.lic
127 lines (102 loc) · 3.51 KB
/
generate-profile.lic
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
=begin
This script must be trusted in order to run (;trust generate-profile).
This script takes partial YAMLs from profile-gen/ and resolves all %INCLUDE
directives to produce new YAML files in profiles/ .
Main yaml files must be named like
Mychar-foo.yaml (where Mychar is your character name).
The output files will have the same names as the these input files.
Included yamls must either be named as:
Mychar-foo-include.yaml (where Mychar is your character name), or
ALL-foo-include.yaml
In both cases these would be included into another YAML via:
%INCLUDE foo
See Risima-* in profile-gen for an example usage.
=end
class ProfileGenerator
def initialize
arg_definitions = [
[
{ name: 'debug', regex: /debug/, optional: true, description: 'Emit debug messages.' }
]
]
args = parse_args(arg_definitions)
@debug = args.debug
profiles = load_profilegen
resolve_includes!(profiles)
write_profiles(profiles)
end
def load_profilegen
profiles = {}
paths = Dir[File.join(SCRIPT_DIR, 'profile-gen/*.yaml')].map { |item| File.path(item) }
paths.select! { |p| p.include?("#{checkname}-") || p.include?('ALL-') }
paths.each do |path|
file = File.basename(path)
echo("Loading file #{file}") if @debug
unless (match = /^(#{checkname}|ALL)-(.+?)(-include)?\.yaml$/.match(file))
raise ArgumentError, "Bad filename: #{file}"
end
name = match[2]
is_include = !!match[3]
if match[1] == 'ALL' && !is_include
raise ArgumentError, 'Files starting in ALL- must be includes.'
end
body = File.readlines(File.join(SCRIPT_DIR, "profile-gen/#{file}"))
profiles[name] = {
file: file,
name: name,
include: is_include,
src: body
}
end
profiles
end
def resolve_includes!(profiles)
profiles.each do |name, profile|
profile[:deps] = []
profile[:subs] = {}
profile[:src].each_with_index do |line, line_num|
next unless (match = /^%INCLUDE (.+?)\s*$/.match(line))
dep = match[1]
profile[:deps] << dep
profile[:subs][line_num] = dep
unless profiles[dep] && profiles[dep][:include]
raise ArgumentError, "(#{name}, #{line_num}): include \"#{dep}\" not found."
end
end
end
# Gather dependencies
to_process = profiles.values.reject { |profile| profile[:include] }
while (next_file = to_process.pop)
echo("Processing #{next_file[:file]}") if @debug
next_file[:seen] = true
next if next_file[:visited]
deps_needed = next_file[:deps].map { |dep| profiles[dep] }
.reject { |dep| dep[:visited] }
raise ArgumentError, 'File contains circular dependency' if deps_needed.any? { |dep| dep[:seen] }
if deps_needed.empty?
resolve_file!(next_file, profiles)
next_file[:visited] = true
else
to_process << next_file
to_process += deps_needed
end
end
end
def resolve_file!(file, profiles)
file[:src] = file[:src].each_with_index.map do |line, index|
if file[:subs][index]
profiles[file[:subs][index]][:src]
else
line
end
end.flatten
end
def write_profiles(profiles)
profiles.values.reject { |profile| profile[:include] }.each do |profile|
filename = File.join(SCRIPT_DIR, "profiles/#{profile[:file]}")
echo("Writing #{filename}") if @debug
File.open(filename, 'wb') { |f| f.puts(profile[:src]) }
end
end
end
ProfileGenerator.new