Built archives have commit hash and date added to version.
[QuestHelper.git] / Development / build
blob456f985b86a6f140114729b08ab9ade55d299903
1 #!/usr/bin/env lua
3 local compile=true
4 local external=true
5 local archive_zip=true
6 local archive_7z=false
8 for i, a in ipairs({...}) do
9   local mode, option = select(3, string.find(a, "^([%+%-]?)(.*)$"))
10   
11   mode = mode ~= "-"
12   
13   if option == "zip" then archive_zip = mode
14   elseif option == "7z" then archive_7z = mode
15   elseif option == "compile" then compile = mode
16   elseif option == "external" then external = mode
17   else
18     print("Unknown option: "..option)
19     return 1
20   end
21 end
23 cache = {}
24 local cache_loader = loadfile("build-cache.lua")
25 if cache_loader then
26   cache_loader()
27   cache_loader = nil
28 end
30 if not cache.removed then cache.removed = {} end
31 if not cache.known then cache.known = {} end
32 if not cache.ignored then cache.ignored = {} end
33 if not cache.uid then cache.uid = {} end
35 local file2uid = {}
36 for uid, data in pairs(cache.uid) do file2uid[data.file] = uid end
38 loadfile("dump.lua")()
39 loadfile("fileutil.lua")()
40 loadfile("../upgrade.lua")()
41 loadfile("compiler.lua")()
42 --loadfile("external.lua")()
44 QuestHelper_BuildZoneLookup()
46 if external then
47   FileUtil.updateSVNRepo("http://svn.esamynn.org/astrolabe/trunk", "../Astrolabe")
48   FileUtil.updateSVNRepo("http://svn.wowace.com/wowace/trunk/ChatThrottleLib", "../ChatThrottleLib")
49 end
51 if compile then
52   local function saveCache()
53     local stream = io.open("build-cache.lua", "w")
54     local buffer, prebuf = CreateBuffer(), CreateBuffer()
55     DumpVariable(buffer, prebuf, cache, "cache")
56     stream:write(DumpingComplete(buffer, prebuf))
57     io.close(stream)
58   end
60   local all_input_files, unknown_input_files = {}, {}
62   FileUtil.forEachFile("LocalInput", function (name)
63     if FileUtil.extension(name) == "lua" or 
64        FileUtil.extension(name) == "bak" then
65       local hash = FileUtil.fileHash(name)
66       if cache.ignored[hash] then return end
67       cache.ignored[hash] = true
68       
69       local input = loadfile(name)
70       if input then
71         local data = {}
72         setfenv(input, data)
73         if pcall(input) then
74           if not (data.QuestHelper_Locale and data.QuestHelper_Objectives) then
75             print("! "..name.." isn't a QuestHelper SavedVariables file.")
76             return
77           end
78           
79           local tempname = os.tmpname()
80           local stream = io.open(tempname, "w")
81           if stream then
82             print("Copying/Sorting "..name)
83             stream:write(ScanAndDumpVariable(data, nil, true) or "")
84             io.close(stream)
85             hash = FileUtil.fileHash(tempname)
86             if hash then
87               local input_name = "Input/"..hash..".lua"
88               if not cache.removed[input_name] then
89                 if not cache.known[input_name] then
90                   FileUtil.copyFile(tempname, input_name)
91                   unknown_input_files[input_name] = name
92                 else
93                   cache.known[input_name] = name
94                 end
95               else
96                 cache.removed[input_name] = name
97               end
98             else
99               print("!!! Can't get hash of "..tempname..", for "..name)
100             end
101             FileUtil.unlinkFile(tempname)
102           end
103         else
104           print("!!! "..name.." couldn't be executed.")
105         end
106       else
107         print("!!! "..name.." couldn't be loaded.")
108       end
109     end
110   end)
112   FileUtil.forEachFile("Input", function (name)
113     if cache.removed[name] then
114       print("!!! Obsolete: ", cache.removed[name].." ("..name..")")
115       os.remove(name)
116     else
117       if not cache.known[name] then
118         unknown_input_files[name] = unknown_input_files[name] or name
119       end
120       
121       all_input_files[name] = cache.known[name] or unknown_input_files[name]
122     end
123   end)
125   local function ProcessObjective(category, name, objective, result)
126     local istring = "obj."..category.."."..name
127     
128     if category ~= "item" then
129       local seen = 0
130       if objective.pos then for i, pos in pairs(objective.pos) do
131         seen = seen + pos[4]
132       end end
133       
134       result[istring..".seen"] = (result[istring..".seen"] or 0) + seen
135     end
136     
137     if objective.vendor then
138       result[istring..".vend"] = (result[istring..".vend"] or 0) + #objective.vendor
139     end
140     
141     if objective.drop then for monster, count in pairs(objective.drop) do
142       result[istring] = (result[istring] or 0) + count
143     end end
144   end
146   local function ProcessQuest(faction, level, name, quest, result)
147     local qstring = "quest."..faction.."."..level.."."..name
148     result[qstring] = (result[qstring] or 0)+((quest.finish or quest.pos) and 1 or 0)
149     
150     if quest.item then for item_name, data in pairs(quest.item) do
151       ProcessObjective("item", item_name, data, result)
152     end end
153     
154     if quest.alt then for _, quest2 in pairs(quest.alt) do
155       ProcessQuest(faction, level, name, quest2, result)
156     end end
157   end
159   local function LoadFile(file)
160     local data = loadfile(file)
161     local result = {}
162     if data then
163       local loaded = {}
164       setfenv(data, loaded)
165       data()
166       
167       QuestHelper_UpgradeDatabase(loaded)
168       
169       if loaded.QuestHelper_UID then
170         result.uid = loaded.QuestHelper_UID
171         result.time = loaded.QuestHelper_SaveDate
172       else
173         if type(loaded.QuestHelper_Quests) == "table" then for faction, levels in pairs(loaded.QuestHelper_Quests) do
174           if type(levels) == "table" then for level, quest_list in pairs(levels) do
175             if type(quest_list) == "table" then for name, quest in pairs(quest_list) do
176               ProcessQuest(faction, level, name, quest, result)
177             end end
178           end end
179         end end
180         
181         if type(loaded.QuestHelper_Objectives) == "table" then for category, objectives in pairs(loaded.QuestHelper_Objectives) do
182           if type(objectives) == "table" then for name, objective in pairs(objectives) do
183             ProcessObjective(category, name, objective, result)
184           end end
185         end end
186       end
187     end
188     
189     return result
190   end
192   local function ObsoletedBy(data1, data2)
193     if data1.uid or data2.uid then
194       return data1.loc == data2.loc and data1.uid == data2.uid and (data1.time or 0) >= (data2.time or 0)
195     end
196     
197     for key, value in pairs(data1) do
198       local value2 = data2[key]
199       if value2 == nil or value2 < value then
200         return false
201       end
202     end
203     return true
204   end
206   local checked = {}
207   local file_data = {}
209   for new_name, original_name in pairs(unknown_input_files) do
210     print("Checking: ", original_name)
211     local data = file_data[new_name]
212     if not data then
213       data = LoadFile(new_name)
214       file_data[new_name] = data
215     end
216     cache.known[new_name] = original_name
217     checked[new_name] = true
218     
219     local uid, last_save = data.uid, data.time
220     
221     if uid then
222       local existing = cache.uid[uid]
223       if not existing then
224         cache.uid[uid] = {file=new_name, save=last_save}
225         file2uid[new_name] = uid
226       else
227         if existing.save >= last_save then
228           print("!!! Obsolete: ", original_name)
229           print("!!!       By: ", all_input_files[existing.file])
230           print("")
231           os.remove(new_name)
232           file_data[new_name] = nil
233           all_input_files[new_name] = nil
234           cache.removed[new_name] = original_name
235           cache.known[new_name] = nil
236           unknown_input_files[new_name] = nil
237         else
238           print("!!! Obsolete: ", all_input_files[existing.file])
239           print("!!!       By: ", original_name)
240           print("")
241           
242           os.remove(existing.file)
243           file_data[existing.file] = nil
244           file2uid[existing.file] = nil
245           file2uid[new_name] = uid
246           cache.removed[existing.file] = all_input_files[existing.file]
247           all_input_files[existing.file] = nil
248           cache.known[existing.file] = nil
249           existing.file = new_name
250         end
251       end
252     else
253       for existing_name, existing_original_name in pairs(all_input_files) do
254         if not checked[existing_name] and not file2uid[existing_name] then
255           local data2 = file_data[existing_name]
256           if not data2 then
257             data2 = LoadFile(existing_name)
258             file_data[existing_name] = data2
259           end
260           
261           if not data2.uid then
262             if ObsoletedBy(data, data2) then
263               print("!!! Obsolete: ", original_name)
264               print("!!!       By: ", existing_original_name)
265               print("")
266               
267               os.remove(new_name)
268               file_data[new_name] = nil
269               all_input_files[new_name] = nil
270               cache.removed[new_name] = original_name
271               cache.known[new_name] = nil
272               unknown_input_files[new_name] = nil
273               break
274             elseif ObsoletedBy(data2, data) then
275               print("!!! Obsolete: ", existing_original_name)
276               print("!!!       By: ", original_name)
277               print("")
278               
279               os.remove(existing_name)
280               file_data[existing_name] = nil
281               all_input_files[existing_name] = nil
282               cache.removed[existing_name] = existing_original_name
283               cache.known[existing_name] = nil
284               unknown_input_files[existing_name] = nil
285             end
286           end
287         end
288       end
289     end
290   end
292   checked, file_data = nil, nil
294   saveCache()
296   --print("Compiling Lightheaded/eql3 data. . .")
297   --ProcessExternal()
299   for name, origin in pairs(all_input_files) do
300     print("Compiling: ", origin)
301     CompileInputFile(name)
302   end
304   print("Writing: ../static.lua")
306   local stream = io.open("../static.lua", "w")
307   stream:write(ScanAndDumpVariable(CompileFinish(), "QuestHelper_StaticData"))
308   io.close(stream)
309 elseif not FileUtil.fileExists("../static.lua") then
310   print("../static.lua doesn't exist; you can't skip the compile step.")
311   return 1
314 print("Creating: Icons.tga")
315 if not FileUtil.fileExists("../Art/Icons.tga") then
316   print("You'll need to manually create Art/Icons.tga, ImageMagick's SVG support seems to have been broken recently.")
318 --FileUtil.convertImage("Data/art.svg", "../Art/Icons.tga")
320 if archive_zip or archive_7z then
321   FileUtil.unlinkFile("QuestHelper")
322   
323   FileUtil.createDirectory("QuestHelper")
324   FileUtil.createDirectory("QuestHelper/Art")
325   FileUtil.createDirectory("QuestHelper/Astrolabe")
326   FileUtil.createDirectory("QuestHelper/ChatThrottleLib")
327   
328   FileUtil.forEachFile("..", function (file)
329     local ext = FileUtil.extension(file)
330     if ext == "lua" then
331       FileUtil.copyFile(file, "QuestHelper")
332     elseif ext == "toc" then
333       -- Modify the version to include the date and hash of the most recent commit.
334       
335       local info = nil
336       local stream = io.popen("git-log -1 --pretty=\"format:, %h, %ai\"", "r")
337       if stream then
338         info = stream:read("*line")
339         io.close(stream)
340       end
341       
342       FileUtil.copyFile(file, "QuestHelper", "^(##%s-Version%s-:.*)$", "%1"..(info or ", unknown revision"))
343     end
344   end)
345   
346   FileUtil.forEachFile("../Art", function (file)
347     local ext = FileUtil.extension(file)
348     if ext == "blp" or ext == "tga" then
349       FileUtil.copyFile(file, "QuestHelper/Art")
350     end
351   end)
352   
353   for i, dir in ipairs({"Astrolabe", "ChatThrottleLib"}) do
354     FileUtil.forEachFile("../"..dir, function (file)
355       FileUtil.copyFile(file, "QuestHelper/"..dir)
356     end)
357   end
358   
359   if archive_zip then
360     print("Creating QuestHelper.zip")
361     FileUtil.unlinkFile("../QuestHelper.zip")
362     FileUtil.createZipArchive("QuestHelper", "../QuestHelper.zip")
363   end
364   
365   if archive_7z then
366     print("Creating QuestHelper.7z")
367     FileUtil.unlinkFile("../QuestHelper.7z")
368     FileUtil.create7zArchive("QuestHelper", "../QuestHelper.7z")
369   end
370   
371   FileUtil.unlinkFile("QuestHelper")
374 print("Done!")