复制代码
-
- --- The helper for update package.
- -- It can download resources and uncompress it,
- -- copy new package to res directory,
- -- and remove temporery directory.
- -- @author zrong(zengrong.net)
- -- Creation 2014-07-03
-
- require "lfs"
- local updater = {}
- updater.STATES = {
- kDownStart = "downloadStart",
- kDownDone = "downloadDone",
- kUncompressStart = "uncompressStart",
- kUncompressDone = "uncompressDone",
- unknown = "stateUnknown",
- }
-
- updater.ERRORS = {
- kCreateFile = "errorCreateFile",
- kNetwork = "errorNetwork",
- kNoNewVersion = "errorNoNewVersion",
- kUncompress = "errorUncompress",
- unknown = "errorUnknown";
- }
-
- function updater.isState(state)
- for k,v in pairs(updater.STATES) do
- if v == state then
- return true
- end
- end
- return false
- end
-
- function updater.clone(object)
- local lookup_table = {}
- local function _copy(object)
- if type(object) ~= "table" then
- return object
- elseif lookup_table[object] then
- return lookup_table[object]
- end
- local new_table = {}
- lookup_table[object] = new_table
- for key, value in pairs(object) do
- new_table[_copy(key)] = _copy(value)
- end
- return setmetatable(new_table, getmetatable(object))
- end
- return _copy(object)
- end
-
- function updater.vardump(object, label, returnTable)
- local lookupTable = {}
- local result = {}
-
- local function _v(v)
- if type(v) == "string" then
- v = "\"" .. v .. "\""
- end
- return tostring(v)
- end
-
- local function _vardump(object, label, indent, nest)
- label = label or ""
- local postfix = ""
- if nest > 1 then postfix = "," end
- if type(object) ~= "table" then
- if type(label) == "string" then
- result[#result +1] = string.format("%s[\"%s\"] = %s%s", indent, label, _v(object), postfix)
- else
- result[#result +1] = string.format("%s%s%s", indent, _v(object), postfix)
- end
- elseif not lookupTable[object] then
- lookupTable[object] = true
-
- if type(label) == "string" then
- result[#result +1 ] = string.format("%s%s = {", indent, label)
- else
- result[#result +1 ] = string.format("%s{", indent)
- end
- local indent2 = indent .. " "
- local keys = {}
- local values = {}
- for k, v in pairs(object) do
- keys[#keys + 1] = k
- values[k] = v
- end
- table.sort(keys, function(a, b)
- if type(a) == "number" and type(b) == "number" then
- return a < b
- else
- return tostring(a) < tostring(b)
- end
- end)
- for i, k in ipairs(keys) do
- _vardump(values[k], k, indent2, nest + 1)
- end
- result[#result +1] = string.format("%s}%s", indent, postfix)
- end
- end
- _vardump(object, label, "", 1)
-
- if returnTable then return result end
- return table.concat(result, "\n")
- end
-
- local u = nil
- local f = CCFileUtils:sharedFileUtils()
- -- The res index file in original package.
- local lresinfo = "res/resinfo.lua"
- local uroot = f:getWritablePath()
- -- The directory for save updated files.
- local ures = uroot.."res/"
- -- The package zip file what download from server.
- local uzip = uroot.."res.zip"
- -- The directory for uncompress res.zip.
- local utmp = uroot.."utmp/"
- -- The res index file in zip package for update.
- local zresinfo = utmp.."res/resinfo.lua"
-
- -- The res index file for final game.
- -- It combiled original lresinfo and zresinfo.
- local uresinfo = ures .. "resinfo.lua"
-
- local localResInfo = nil
- local remoteResInfo = nil
- local finalResInfo = nil
-
- local function _initUpdater()
- print("initUpdater, ", u)
- if not u then u = Updater:new() end
- print("after initUpdater:", u)
- end
-
- function updater.writeFile(path, content, mode)
- mode = mode or "w+b"
- local file = io.open(path, mode)
- if file then
- if file:write(content) == nil then return false end
- io.close(file)
- return true
- else
- return false
- end
- end
-
- function updater.readFile(path)
- return f:getFileData(path)
- end
-
- function updater.exists(path)
- return f:isFileExist(path)
- end
-
- --[[
- -- Departed, uses lfs instead.
- function updater._mkdir(path)
- _initUpdater()
- return u:createDirectory(path)
- end
-
- -- Departed, get a warning in ios simulator
- function updater._rmdir(path)
- _initUpdater()
- return u:removeDirectory(path)
- end
- --]]
-
- function updater.mkdir(path)
- if not updater.exists(path) then
- return lfs.mkdir(path)
- end
- return true
- end
-
- function updater.rmdir(path)
- print("updater.rmdir:", path)
- if updater.exists(path) then
- local function _rmdir(path)
- local iter, dir_obj = lfs.dir(path)
- while true do
- local dir = iter(dir_obj)
- if dir == nil then break end
- if dir ~= "." and dir ~= ".." then
- local curDir = path..dir
- local mode = lfs.attributes(curDir, "mode")
- if mode == "directory" then
- _rmdir(curDir.."/")
- elseif mode == "file" then
- os.remove(curDir)
- end
- end
- end
- local succ, des = os.remove(path)
- if des then print(des) end
- return succ
- end
- _rmdir(path)
- end
- return true
- end
-
- -- Is there a update.zip package in ures directory?
- -- If it is true, return its abstract path.
- function updater.hasNewUpdatePackage()
- local newUpdater = ures.."lib/update.zip"
- if updater.exists(newUpdater) then
- return newUpdater
- end
- return nil
- end
-
- -- Check local resinfo and remote resinfo, compare their version value.
- function updater.checkUpdate()
- localResInfo = updater.getLocalResInfo()
- local localVer = localResInfo.version
- print("localVer:", localVer)
- remoteResInfo = updater.getRemoteResInfo(localResInfo.update_url)
- local remoteVer = remoteResInfo.version
- print("remoteVer:", remoteVer)
- return remoteVer ~= localVer
- end
-
- -- Copy resinfo.lua from original package to update directory(ures)
- -- when it is not in ures.
- function updater.getLocalResInfo()
- print(string.format("updater.getLocalResInfo, lresinfo:%s, uresinfo:%s",
- lresinfo,uresinfo))
- local resInfoTxt = nil
- if updater.exists(uresinfo) then
- resInfoTxt = updater.readFile(uresinfo)
- else
- assert(updater.mkdir(ures), ures.." create error!")
- local info = updater.readFile(lresinfo)
- print("localResInfo:", info)
- assert(info, string.format("Can not get the constent from %s!", lresinfo))
- updater.writeFile(uresinfo, info)
- resInfoTxt = info
- end
- return assert(loadstring(resInfoTxt))()
- end
-
- function updater.getRemoteResInfo(path)
- _initUpdater()
- print("updater.getRemoteResInfo:", path)
- local resInfoTxt = u:getUpdateInfo(path)
- print("resInfoTxt:", resInfoTxt)
- return assert(loadstring(resInfoTxt))()
- end
-
- function updater.update(handler)
- assert(remoteResInfo and remoteResInfo.package, "Can not get remoteResInfo!")
- print("updater.update:", remoteResInfo.package)
- if handler then
- u:registerScriptHandler(handler)
- end
- updater.rmdir(utmp)
- u:update(remoteResInfo.package, uzip, utmp, false)
- end
-
- function updater._copyNewFile(resInZip)
- -- Create nonexistent directory in update res.
- local i,j = 1,1
- while true do
- j = string.find(resInZip, "/", i)
- if j == nil then break end
- local dir = string.sub(resInZip, 1,j)
- -- Save created directory flag to a table because
- -- the io operation is too slow.
- if not updater._dirList[dir] then
- updater._dirList[dir] = true
- local fullUDir = uroot..dir
- updater.mkdir(fullUDir)
- end
- i = j+1
- end
- local fullFileInURes = uroot..resInZip
- local fullFileInUTmp = utmp..resInZip
- print(string.format('copy %s to %s', fullFileInUTmp, fullFileInURes))
- local zipFileContent = updater.readFile(fullFileInUTmp)
- if zipFileContent then
- updater.writeFile(fullFileInURes, zipFileContent)
- return fullFileInURes
- end
- return nil
- end
-
- function updater._copyNewFilesBatch(resType, resInfoInZip)
- local resList = resInfoInZip[resType]
- if not resList then return end
- local finalRes = finalResInfo[resType]
- for __,v in ipairs(resList) do
- local fullFileInURes = updater._copyNewFile(v)
- if fullFileInURes then
- -- Update key and file in the finalResInfo
- -- Ignores the update package because it has been in memory.
- if v ~= "res/lib/update.zip" then
- finalRes[v] = fullFileInURes
- end
- else
- print(string.format("updater ERROR, copy file %s.", v))
- end
- end
- end
-
- function updater.updateFinalResInfo()
- assert(localResInfo and remoteResInfo,
- "Perform updater.checkUpdate() first!")
- if not finalResInfo then
- finalResInfo = updater.clone(localResInfo)
- end
- --do return end
- local resInfoTxt = updater.readFile(zresinfo)
- local zipResInfo = assert(loadstring(resInfoTxt))()
- if zipResInfo["version"] then
- finalResInfo.version = zipResInfo["version"]
- end
- -- Save a dir list maked.
- updater._dirList = {}
- updater._copyNewFilesBatch("lib", zipResInfo)
- updater._copyNewFilesBatch("oth", zipResInfo)
- -- Clean dir list.
- updater._dirList = nil
- updater.rmdir(utmp)
- local dumpTable = updater.vardump(finalResInfo, "local data", true)
- dumpTable[#dumpTable+1] = "return data"
- if updater.writeFile(uresinfo, table.concat(dumpTable, "\n")) then
- return true
- end
- print(string.format("updater ERROR, write file %s.", uresinfo))
- return false
- end
-
- function updater.getResCopy()
- if finalResInfo then return updater.clone(finalResInfo) end
- return updater.clone(localResInfo)
- end
-
- function updater.clean()
- if u then
- u:unregisterScriptHandler()
- u:delete()
- u = nil
- end
- updater.rmdir(utmp)
- localResInfo = nil
- remoteResInfo = nil
- finalResInfo = nil
- end
-
- return updater
|