mirror of
https://github.com/Doodle3D/doodle3d-firmware.git
synced 2024-11-17 11:07:56 +01:00
More work on updater module (WIP): mainly added state and fixed bugs.
This commit is contained in:
parent
6225cd6062
commit
b5d980c52e
2
Makefile
2
Makefile
@ -100,7 +100,7 @@ define Package/wifibox/install
|
|||||||
$(CP) $(WIFIBOX_BASE_DIR)/util/*.lua $(1)/$(TGT_LUA_DIR_SUFFIX)/util/
|
$(CP) $(WIFIBOX_BASE_DIR)/util/*.lua $(1)/$(TGT_LUA_DIR_SUFFIX)/util/
|
||||||
|
|
||||||
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/d3d-updater.lua $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/d3d-updater.lua $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
||||||
$(LN) -s /$(TGT_LUA_DIR_SUFFIX)/script/d3d-updater.lua $(1)/bin
|
$(LN) -s /$(TGT_LUA_DIR_SUFFIX)/script/d3d-updater.lua $(1)/bin/d3d-updater
|
||||||
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/wifibox_init $(1)/etc/init.d/wifibox # copy directly to init dir (required for post-inst enabling)
|
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/wifibox_init $(1)/etc/init.d/wifibox # copy directly to init dir (required for post-inst enabling)
|
||||||
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/d3dapi $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/d3dapi $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
||||||
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/signin.sh $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
$(INSTALL_BIN) $(WIFIBOX_BASE_DIR)/script/signin.sh $(1)/$(TGT_LUA_DIR_SUFFIX)/script
|
||||||
|
1
src/FIRMWARE-VERSION
Normal file
1
src/FIRMWARE-VERSION
Normal file
@ -0,0 +1 @@
|
|||||||
|
0.9.0
|
@ -17,9 +17,9 @@ M.WWW_RENAME_NAME = '/www-regular'
|
|||||||
M.CONNECTING_FAILED = -1
|
M.CONNECTING_FAILED = -1
|
||||||
M.NOT_CONNECTED = 0
|
M.NOT_CONNECTED = 0
|
||||||
M.CONNECTING = 1
|
M.CONNECTING = 1
|
||||||
M.CONNECTED = 2
|
M.CONNECTED = 2
|
||||||
M.CREATING = 3
|
M.CREATING = 3
|
||||||
M.CREATED = 4
|
M.CREATED = 4
|
||||||
|
|
||||||
local function reloadBit(dlist, itemname)
|
local function reloadBit(dlist, itemname)
|
||||||
if dlist[itemname] == nil then dlist[itemname] = '' end
|
if dlist[itemname] == nil then dlist[itemname] = '' end
|
||||||
@ -259,15 +259,15 @@ end
|
|||||||
-- @tparam string ssid The SSID to use for the access point.
|
-- @tparam string ssid The SSID to use for the access point.
|
||||||
-- @return True on success or nil+msg on error.
|
-- @return True on success or nil+msg on error.
|
||||||
function M.setupAccessPoint(ssid)
|
function M.setupAccessPoint(ssid)
|
||||||
|
|
||||||
M.setStatus(M.CREATING,"Creating access point...");
|
M.setStatus(M.CREATING,"Creating access point...");
|
||||||
|
|
||||||
M.switchConfiguration{apnet="add_noreload"}
|
M.switchConfiguration{apnet="add_noreload"}
|
||||||
wifi.activateConfig(ssid)
|
wifi.activateConfig(ssid)
|
||||||
-- NOTE: dnsmasq must be reloaded after network or it will be unable to serve IP addresses
|
-- NOTE: dnsmasq must be reloaded after network or it will be unable to serve IP addresses
|
||||||
M.switchConfiguration{ wifiiface="add", network="reload", staticaddr="add", dhcppool="add_noreload", wwwredir="add", dnsredir="add" }
|
M.switchConfiguration{ wifiiface="add", network="reload", staticaddr="add", dhcppool="add_noreload", wwwredir="add", dnsredir="add" }
|
||||||
M.switchConfiguration{dhcp="reload"}
|
M.switchConfiguration{dhcp="reload"}
|
||||||
|
|
||||||
M.setStatus(M.CREATED,"Access point created");
|
M.setStatus(M.CREATED,"Access point created");
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -282,9 +282,9 @@ end
|
|||||||
-- @return True on success or nil+msg on error.
|
-- @return True on success or nil+msg on error.
|
||||||
function M.associateSsid(ssid, passphrase, recreate)
|
function M.associateSsid(ssid, passphrase, recreate)
|
||||||
log:info("netconfig:associateSsid: "..(ssid or "<nil>")..", "..(passphrase or "<nil>")..", "..(recreate or "<nil>"))
|
log:info("netconfig:associateSsid: "..(ssid or "<nil>")..", "..(passphrase or "<nil>")..", "..(recreate or "<nil>"))
|
||||||
|
|
||||||
M.setStatus(M.CONNECTING,"Connecting...");
|
M.setStatus(M.CONNECTING,"Connecting...");
|
||||||
|
|
||||||
-- see if previously configured network for given ssid exists
|
-- see if previously configured network for given ssid exists
|
||||||
local cfg = nil
|
local cfg = nil
|
||||||
for _, net in ipairs(wifi.getConfigs()) do
|
for _, net in ipairs(wifi.getConfigs()) do
|
||||||
@ -293,7 +293,7 @@ function M.associateSsid(ssid, passphrase, recreate)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if not, or if newly created configuration is requested, create a new configuration
|
-- if not, or if newly created configuration is requested, create a new configuration
|
||||||
if cfg == nil or recreate ~= nil then
|
if cfg == nil or recreate ~= nil then
|
||||||
local scanResult = wifi.getScanInfo(ssid)
|
local scanResult = wifi.getScanInfo(ssid)
|
||||||
@ -320,14 +320,14 @@ function M.associateSsid(ssid, passphrase, recreate)
|
|||||||
M.setStatus(M.CONNECTING_FAILED,msg);
|
M.setStatus(M.CONNECTING_FAILED,msg);
|
||||||
return nil,msg
|
return nil,msg
|
||||||
end
|
end
|
||||||
|
|
||||||
M.setStatus(M.CONNECTED,"Connected");
|
M.setStatus(M.CONNECTED,"Connected");
|
||||||
|
|
||||||
-- signin to connect.doodle3d.com
|
-- signin to connect.doodle3d.com
|
||||||
local success, output = signin.signin()
|
local success, output = signin.signin()
|
||||||
if success then
|
if success then
|
||||||
log:info("Signed in")
|
log:info("Signed in")
|
||||||
else
|
else
|
||||||
log:info("Signing in failed")
|
log:info("Signing in failed")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -340,13 +340,13 @@ end
|
|||||||
function M.disassociate()
|
function M.disassociate()
|
||||||
|
|
||||||
M.setStatus(M.NOT_CONNECTED,"Not connected");
|
M.setStatus(M.NOT_CONNECTED,"Not connected");
|
||||||
|
|
||||||
wifi.activateConfig()
|
wifi.activateConfig()
|
||||||
return wifi.restart()
|
return wifi.restart()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.getStatus()
|
function M.getStatus()
|
||||||
log:info("getStatus")
|
log:info("network:getStatus")
|
||||||
local file, error = io.open('/tmp/networkstatus.txt','r')
|
local file, error = io.open('/tmp/networkstatus.txt','r')
|
||||||
if file == nil then
|
if file == nil then
|
||||||
--log:error("Util:Access:Can't read controller file. Error: "..error)
|
--log:error("Util:Access:Can't read controller file. Error: "..error)
|
||||||
@ -355,8 +355,7 @@ function M.getStatus()
|
|||||||
local status = file:read('*a')
|
local status = file:read('*a')
|
||||||
--log:info(" status: "..utils.dump(status))
|
--log:info(" status: "..utils.dump(status))
|
||||||
file:close()
|
file:close()
|
||||||
local parts = {}
|
local code, msg = string.match(status, '([^|]+)|+(.*)')
|
||||||
local code, msg = string.match(status, "([^|]+)|+(.*)")
|
|
||||||
--log:info(" code: "..utils.dump(code))
|
--log:info(" code: "..utils.dump(code))
|
||||||
--log:info(" msg: "..utils.dump(msg))
|
--log:info(" msg: "..utils.dump(msg))
|
||||||
return code,msg
|
return code,msg
|
||||||
@ -364,7 +363,7 @@ function M.getStatus()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function M.setStatus(code,msg)
|
function M.setStatus(code,msg)
|
||||||
log:info("setStatus: "..code.." | "..msg)
|
log:info("network:setStatus: "..code.." | "..msg)
|
||||||
local file = io.open('/tmp/networkstatus.txt','w')
|
local file = io.open('/tmp/networkstatus.txt','w')
|
||||||
file:write(code.."|"..msg)
|
file:write(code.."|"..msg)
|
||||||
file:flush()
|
file:flush()
|
||||||
|
@ -1,27 +1,43 @@
|
|||||||
#!/usr/bin/env lua
|
#!/usr/bin/env lua
|
||||||
|
|
||||||
-- TODO/NOTES:
|
-- TODO/NOTES:
|
||||||
-- implement image removal
|
-- M.checkValidImage(verEnt) -> doet exists+fileSize/MD5 check
|
||||||
-- make sure downloaded files are overwritten, and never named with '.n' suffix
|
-- after download: (can use checkValidImage for this)
|
||||||
-- max 1 image tegelijk gedownload (zelfs dat is al link qua geheugengebruik? -> printen blokkeren vanaf download image?)
|
-- - remove file on fail
|
||||||
|
-- - check size or md5 and remove file on mismatch [osx: md5 -q <file>]
|
||||||
|
-- add to status: validImage: none|<version> (can use checkValidImage for this)
|
||||||
|
-- any more TODO's across this file?
|
||||||
|
-- max 1 image tegelijk (moet api doen), en rekening houden met printbuffer (printen blokkeren?)
|
||||||
|
-- API calls to add: update/status, update/download, update/install, update/clear
|
||||||
|
|
||||||
-- interpret wget return values more intelligently? or add function to run integrity check on index vs actually present files?
|
-- MAYBE/LATER:
|
||||||
-- after downloading anything, check whether it really exists?
|
-- wget: add provision (in verbose mode?) to use -v instead of -q and disable output redirection
|
||||||
-- document index file format (Version first, then in any order: Files: sysup; factory, ChangelogStart:, ..., ChangelogEnd:)
|
-- wget: configurable timeout?
|
||||||
-- can we also get rid of the .lua extension? (looks nicer on command-line)
|
-- max cache lifetime for index file?
|
||||||
|
-- document index file format (Version first, then in any order: Files: sysup; factory, FileSize: sysup; factory, MD5: sysup; factory, ChangelogStart:, ..., ChangelogEnd:)
|
||||||
-- remove /etc/wifibox-version on macbook...
|
-- remove /etc/wifibox-version on macbook...
|
||||||
-- perhaps create a function for each action and directly assign them in the arguments parser
|
-- copy improved fileSize back to utils (add unit tests!)
|
||||||
|
-- create new utils usable by updater as well as api? (remove dependencies on uci and logger etc)
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
-- NOTE: 'INSTALLED' will never be returned (and probably neither will 'INSTALLING') since in that case the device is flashing or rebooting
|
||||||
|
M.STATE = { NONE = 1, DOWNLOADING = 2, IMAGE_READY = 3, INSTALLING = 4, INSTALLED = 5, INSTALL_FAILED = 6 }
|
||||||
|
M.STATE_NAMES = {
|
||||||
|
[M.STATE.NONE] = 'none', [M.STATE.DOWNLOADING] = 'downloading', [M.STATE.IMAGE_READY] = 'image_ready',
|
||||||
|
[M.STATE.INSTALLING] = 'installing', [M.STATE.INSTALLED] = 'installed', [M.STATE.INSTALL_FAILED] = 'install_failed'
|
||||||
|
}
|
||||||
|
|
||||||
M.DEFAULT_BASE_URL = 'http://doodle3d.com/updates'
|
M.DEFAULT_BASE_URL = 'http://doodle3d.com/updates'
|
||||||
--M.DEFAULT_BASE_URL = 'http://localhost/~wouter/wifibox/updates'
|
--M.DEFAULT_BASE_URL = 'http://localhost/~USERNAME/wifibox/updates'
|
||||||
M.IMAGE_INDEX_FILE = 'wifibox-image.index'
|
M.IMAGE_INDEX_FILE = 'wifibox-image.index'
|
||||||
M.CACHE_PATH = '/tmp/d3d-updater'
|
M.CACHE_PATH = '/tmp/d3d-updater'
|
||||||
|
M.STATE_FILE = 'update-state'
|
||||||
M.WGET_OPTIONS = "-q -t 1 -T 30"
|
M.WGET_OPTIONS = "-q -t 1 -T 30"
|
||||||
--M.WGET_OPTIONS = "-v -t 1 -T 30"
|
--M.WGET_OPTIONS = "-v -t 1 -T 30"
|
||||||
|
|
||||||
M.verbosity = 0
|
local verbosity = 0
|
||||||
|
local log = nil -- wifibox API can use M.setLogger to enable this module to use its logger
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -32,8 +48,26 @@ M.verbosity = 0
|
|||||||
|
|
||||||
-- use level==1 for important messages, 0 for regular messages and -1 for less important messages
|
-- use level==1 for important messages, 0 for regular messages and -1 for less important messages
|
||||||
local function P(lvl, msg) if (-lvl <= M.verbosity) then print(msg) end end
|
local function P(lvl, msg) if (-lvl <= M.verbosity) then print(msg) end end
|
||||||
|
|
||||||
local function E(msg) io.stderr:write(msg .. '\n') end
|
local function E(msg) io.stderr:write(msg .. '\n') end
|
||||||
|
local function D(msg) P(-1, "(DBG) " .. msg) end
|
||||||
|
|
||||||
|
local function getState()
|
||||||
|
local file,msg = io.open(M.CACHE_PATH .. '/' .. M.STATE_FILE, 'r')
|
||||||
|
if not file then return M.STATE.NONE,"" end
|
||||||
|
|
||||||
|
local state = file:read('*a')
|
||||||
|
file:close()
|
||||||
|
local code,msg = string.match(state, '([^|]+)|+(.*)')
|
||||||
|
return code,msg
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setState(code, msg)
|
||||||
|
local s = code .. '|' .. msg
|
||||||
|
if log then log:info("update state: " .. s) else D("update state: " .. s) end
|
||||||
|
local file = io.open(M.CACHE_PATH .. '/' .. M.STATE_FILE, 'w')
|
||||||
|
file:write(s)
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
|
||||||
-- trim whitespace from both ends of string (from http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76)
|
-- trim whitespace from both ends of string (from http://snippets.luacode.org/?p=snippets/trim_whitespace_from_string_76)
|
||||||
local function trim(s)
|
local function trim(s)
|
||||||
@ -68,27 +102,37 @@ local function exists(file)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- from utils.lua
|
-- from utils.lua
|
||||||
|
--argument: either an open file or a filename
|
||||||
local function fileSize(file)
|
local function fileSize(file)
|
||||||
local current = file:seek()
|
local size = nil
|
||||||
local size = file:seek('end')
|
if type(file) == 'file' then
|
||||||
file:seek('set', current)
|
local current = file:seek()
|
||||||
|
size = file:seek('end')
|
||||||
|
file:seek('set', current)
|
||||||
|
elseif type(file) == 'string' then
|
||||||
|
local f = io.open(file)
|
||||||
|
if f then
|
||||||
|
size = f:seek('end')
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return size
|
return size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- returns return value of command
|
-- returns return value of command
|
||||||
local function runCommand(command, dryRun) P(-1, "(DBG) about to run: '" .. command .. "'"); return (not dryRun) and os.execute(command) or 0 end
|
local function runCommand(command, dryRun) D("about to run: '" .. command .. "'"); return (not dryRun) and os.execute(command) or 0 end
|
||||||
|
|
||||||
-- returns return value of wget (or nil if saveDir is nil or empty)
|
-- returns return value of wget (or nil if saveDir is nil or empty)
|
||||||
local function downloadFile(url, saveDir, filename)
|
local function downloadFile(url, saveDir, filename)
|
||||||
if not saveDir or saveDir:len() == 0 then return nil, "saveDir must be non-empty" end
|
if not saveDir or saveDir:len() == 0 then return nil, "saveDir must be non-empty" end
|
||||||
local outArg = (filename:len() > 0) and (' -O' .. filename) or ''
|
local outArg = (filename:len() > 0) and (' -O' .. filename) or ''
|
||||||
if filename:len() > 0 then
|
if filename:len() > 0 then
|
||||||
--return runCommand('wget ' .. M.WGET_OPTIONS .. ' -O ' .. saveDir .. '/' .. filename .. ' ' .. url .. ' 2> /dev/null')
|
return runCommand('wget ' .. M.WGET_OPTIONS .. ' -O ' .. saveDir .. '/' .. filename .. ' ' .. url .. ' 2> /dev/null')
|
||||||
return runCommand('wget ' .. M.WGET_OPTIONS .. ' -O ' .. saveDir .. '/' .. filename .. ' ' .. url)
|
|
||||||
else
|
else
|
||||||
return runCommand('wget ' .. M.WGET_OPTIONS .. ' -P ' .. saveDir .. ' ' .. url .. ' 2> /dev/null')
|
return runCommand('wget ' .. M.WGET_OPTIONS .. ' -P ' .. saveDir .. ' ' .. url .. ' 2> /dev/null')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parseCommandlineArguments(arglist)
|
local function parseCommandlineArguments(arglist)
|
||||||
@ -106,29 +150,27 @@ local function parseCommandlineArguments(arglist)
|
|||||||
elseif argument == '-c' then result.useCache = true
|
elseif argument == '-c' then result.useCache = true
|
||||||
elseif argument == '-C' then result.useCache = false
|
elseif argument == '-C' then result.useCache = false
|
||||||
elseif argument == '-u' then nextIsUrl = true
|
elseif argument == '-u' then nextIsUrl = true
|
||||||
elseif argument == '-m' then result.machineOutput = true
|
|
||||||
elseif argument == '-v' then result.action = 'showCurrentVersion'
|
elseif argument == '-v' then result.action = 'showCurrentVersion'
|
||||||
|
elseif argument == '-s' then result.action = 'showStatus'
|
||||||
elseif argument == '-l' then result.action = 'showAvailableVersions'
|
elseif argument == '-l' then result.action = 'showAvailableVersions'
|
||||||
elseif argument == '-i' then result.action = 'showVersionInfo'; nextIsVersion = true
|
elseif argument == '-i' then result.action = 'showVersionInfo'; nextIsVersion = true
|
||||||
elseif argument == '-d' then result.action = 'imageDownload'; nextIsVersion = true
|
elseif argument == '-d' then result.action = 'imageDownload'; nextIsVersion = true
|
||||||
elseif argument == '-r' then result.action = 'imageRemove'
|
|
||||||
elseif argument == '-f' then result.action = 'imageInstall'; nextIsVersion = true
|
elseif argument == '-f' then result.action = 'imageInstall'; nextIsVersion = true
|
||||||
else return nil,"Unrecognized argument '" .. argument .. "'"
|
elseif argument == '-r' then result.action = 'clear'
|
||||||
|
else return nil,"unrecognized argument '" .. argument .. "'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if result.machineOutput then result.verbosity = -1 end
|
if result.version then
|
||||||
|
|
||||||
if result.version then
|
|
||||||
result.version = M.parseVersion(result.version)
|
result.version = M.parseVersion(result.version)
|
||||||
if not result.version then
|
if not result.version then
|
||||||
return nil,"error parsing specified version"
|
return nil,"error parsing specified version"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if nextIsVersion then return nil, "Missing required version argument" end
|
if nextIsVersion then return nil, "missing required version argument" end
|
||||||
if nextIsUrl then return nil, "Missing required URL argument" end
|
if nextIsUrl then return nil, "missing required URL argument" end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
@ -140,6 +182,28 @@ end
|
|||||||
-- MODULE FUNCTIONS --
|
-- MODULE FUNCTIONS --
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
function M.setLogger(logger)
|
||||||
|
log = logger
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.getStatus(baseUrl, useCache)
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
local verTable = M.getAvailableVersions(baseUrl, useCache)
|
||||||
|
local newest = verTable[#verTable]
|
||||||
|
result.currentVersion = M.getCurrentVersion()
|
||||||
|
result.newestVersion = newest.version
|
||||||
|
result.stateCode, result.stateText = getState()
|
||||||
|
result.stateCode = tonumber(result.stateCode)
|
||||||
|
|
||||||
|
if result.stateCode == M.STATE.DOWNLOADING then
|
||||||
|
result.progress = fileSize(M.CACHE_PATH .. '/' .. newest.sysupgradeFilename)
|
||||||
|
result.imageSize = newest.sysupgradeFileSize
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
function M.parseVersion(versionText)
|
function M.parseVersion(versionText)
|
||||||
if not versionText or versionText:len() == 0 then return nil end
|
if not versionText or versionText:len() == 0 then return nil end
|
||||||
local major,minor,patch = versionText:match("^%s*(%d+)%.(%d+)%.(%d+)%s*$")
|
local major,minor,patch = versionText:match("^%s*(%d+)%.(%d+)%.(%d+)%s*$")
|
||||||
@ -181,12 +245,12 @@ end
|
|||||||
|
|
||||||
-- returns a table with major, minor and patch as keys
|
-- returns a table with major, minor and patch as keys
|
||||||
function M.getCurrentVersion()
|
function M.getCurrentVersion()
|
||||||
local vt,msg = getCurrentVersionText()
|
local vt,msg = M.getCurrentVersionText()
|
||||||
return vt and M.parseVersion(vt) or nil,msg
|
return vt and M.parseVersion(vt) or nil,msg
|
||||||
end
|
end
|
||||||
|
|
||||||
-- requires url of image index file; returns an indexed (and sorted) table containing version tables
|
-- requires url of image index file; returns an indexed (and sorted) table containing version tables
|
||||||
function M.getAvailableVersions(baseUrl, useCache)
|
function M.getAvailableVersions(baseUrl, useCache, version)
|
||||||
local indexFilename = M.CACHE_PATH .. '/' .. M.IMAGE_INDEX_FILE
|
local indexFilename = M.CACHE_PATH .. '/' .. M.IMAGE_INDEX_FILE
|
||||||
|
|
||||||
if not useCache or not exists(indexFilename) then
|
if not useCache or not exists(indexFilename) then
|
||||||
@ -228,8 +292,8 @@ function M.getAvailableVersions(baseUrl, useCache)
|
|||||||
elseif k == 'FileSize' then
|
elseif k == 'FileSize' then
|
||||||
local sSize,fSize = v:match('^(.-);(.*)$')
|
local sSize,fSize = v:match('^(.-);(.*)$')
|
||||||
sSize,fSize = trim(sSize), trim(fSize)
|
sSize,fSize = trim(sSize), trim(fSize)
|
||||||
if sSize then entry.sysupgradeFileSize = sSize end
|
if sSize then entry.sysupgradeFileSize = tonumber(sSize) end
|
||||||
if fSize then entry.factoryFileSize = fSize end
|
if fSize then entry.factoryFileSize = tonumber(fSize) end
|
||||||
elseif k == 'MD5' then
|
elseif k == 'MD5' then
|
||||||
local sSum,fSum = v:match('^(.-);(.*)$')
|
local sSum,fSum = v:match('^(.-);(.*)$')
|
||||||
sSum,fSum = trim(sSum), trim(fSum)
|
sSum,fSum = trim(sSum), trim(fSum)
|
||||||
@ -256,9 +320,16 @@ end
|
|||||||
function M.downloadImageFile(baseUrl, ver, forceDownload, devType, isFactory)
|
function M.downloadImageFile(baseUrl, ver, forceDownload, devType, isFactory)
|
||||||
local filename = M.constructImageFilename(ver, devType, isFactory)
|
local filename = M.constructImageFilename(ver, devType, isFactory)
|
||||||
local doDownload = (type(forceDownload) == 'boolean') and forceDownload or (not exists(M.CACHE_PATH .. '/' .. filename))
|
local doDownload = (type(forceDownload) == 'boolean') and forceDownload or (not exists(M.CACHE_PATH .. '/' .. filename))
|
||||||
--TODO: if file exists but is of different length, set doDownload to true
|
|
||||||
--TODO: if file exists but does not match md5sum, set doDownload to true
|
--TODO: call M.checkValidImage, set doDownload to true if not valid
|
||||||
return doDownload and downloadFile(baseUrl .. '/images/' .. filename, M.CACHE_PATH, filename) or 0
|
|
||||||
|
local rv = 0
|
||||||
|
if doDownload then
|
||||||
|
setState(M.STATE.DOWNLOADING, "Downloading image (" .. filename .. ")")
|
||||||
|
rv = downloadFile(baseUrl .. '/images/' .. filename, M.CACHE_PATH, filename) or 0
|
||||||
|
end
|
||||||
|
setState(M.STATE.IMAGE_READY, "Image downloaded, ready to install (image name: " .. filename .. ")")
|
||||||
|
return rv
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this function will not return
|
-- this function will not return
|
||||||
@ -266,10 +337,24 @@ function M.flashImageVersion(version, noRetain, devType, isFactory)
|
|||||||
local imgName = M.constructImageFilename(version, devType, isFactory)
|
local imgName = M.constructImageFilename(version, devType, isFactory)
|
||||||
local cmd = noRetain and 'sysupgrade -n ' or 'sysupgrade '
|
local cmd = noRetain and 'sysupgrade -n ' or 'sysupgrade '
|
||||||
cmd = cmd .. M.CACHE_PATH .. '/' .. imgName
|
cmd = cmd .. M.CACHE_PATH .. '/' .. imgName
|
||||||
P(1, "running command: '" .. cmd .. "'")
|
setState(M.STATE, "Installing new image (" .. imgName .. ")") -- yes this is rather pointless
|
||||||
return runCommand(cmd, true) -- if everything goes to plan, this will not return
|
local rv = runCommand(cmd, true) -- if everything goes to plan, this will not return
|
||||||
|
|
||||||
|
if rv == 0 then setState(M.STATE.INSTALLED, "Image installed")
|
||||||
|
else setState(M.STATE.INSTALL_FAILED, "Image installation failed (sysupgrade returned " .. rv .. ")")
|
||||||
|
end
|
||||||
|
|
||||||
|
return rv
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.clear()
|
||||||
|
P(0, "Removing " .. M.CACHE_PATH .. "/doodle3d-wifibox-*.bin")
|
||||||
|
setState(M.STATE.NONE, "")
|
||||||
|
return os.execute('rm -f ' .. M.CACHE_PATH .. '/doodle3d-wifibox-*.bin')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------
|
----------
|
||||||
@ -295,20 +380,19 @@ local function main()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if argTable.action == 'showHelp' then
|
if argTable.action == 'showHelp' then
|
||||||
print("\t-h\t\tShow this help message")
|
P(1, "\t-h\t\tShow this help message")
|
||||||
print("\t-q\t\tBe more quiet")
|
P(1, "\t-q\t\tquiet mode")
|
||||||
print("\t-c\t\tUse cache as much as possible")
|
P(1, "\t-V\t\tverbose mode")
|
||||||
print("\t-C\t\tDo not use the cache")
|
P(1, "\t-c\t\tUse cache as much as possible")
|
||||||
print("\t-q\t\tBe more quiet")
|
P(1, "\t-C\t\tDo not use the cache")
|
||||||
print("\t-V\t\tBe more verbose")
|
P(1, "\t-u <base_url>\tUse specified base URL (default: " .. M.DEFAULT_BASE_URL .. ")")
|
||||||
print("\t-u <base_url>\tUse specified base URL (default: " .. M.DEFAULT_BASE_URL .. ")")
|
P(1, "\t-v\t\tShow current image version")
|
||||||
print("\t-m\t\tOnly print machine-readable output (implies -q)")
|
P(1, "\t-s\t\tShow current update status")
|
||||||
print("\t-v\t\tShow current image version")
|
P(1, "\t-l\t\tShow list of available image versions (and which one has been downloaded, if any)")
|
||||||
print("\t-l\t\tShow list of available image versions (and which one has been downloaded, if any)")
|
P(1, "\t-i <version>\tShow information (changelog) about the requested image version")
|
||||||
print("\t-i <version>\tShow information (changelog) about the requested image version")
|
P(1, "\t-d <version>\tDownload requested image version")
|
||||||
print("\t-d <version>\tDownload requested image version")
|
P(1, "\t-f <version>\tFlash to requested image version (by means of sysupgrade)")
|
||||||
print("\t-r\t\tRemove downloaded image")
|
P(1, "\t-r\t\tClear downloaded images and reset state")
|
||||||
print("\t-f <version>\tFlash to requested image version (by means of sysupgrade)")
|
|
||||||
os.exit(10)
|
os.exit(10)
|
||||||
|
|
||||||
elseif argTable.action == 'showCurrentVersion' then
|
elseif argTable.action == 'showCurrentVersion' then
|
||||||
@ -318,6 +402,23 @@ local function main()
|
|||||||
if not v then E("error parsing version '" .. vText .. "'"); os.exit(2) end
|
if not v then E("error parsing version '" .. vText .. "'"); os.exit(2) end
|
||||||
P(1, "version: " .. M.formatVersion(v))
|
P(1, "version: " .. M.formatVersion(v))
|
||||||
|
|
||||||
|
elseif argTable.action == 'showStatus' then
|
||||||
|
local status = M.getStatus(argTable.baseUrl, useCache)
|
||||||
|
P(0, "Current update status:")
|
||||||
|
P(1, " currentVersion:\t" .. (M.formatVersion(status.currentVersion) or '?'))
|
||||||
|
P(1, " newestVersion:\t" .. (M.formatVersion(status.newestVersion) or '?'))
|
||||||
|
|
||||||
|
if status.stateText and status.stateText:len() > 0 then
|
||||||
|
P(1, " state:\t\t" .. M.STATE_NAMES[status.stateCode] .. " (" .. status.stateText .. ")")
|
||||||
|
else
|
||||||
|
P(1, " state:\t\t" .. M.STATE_NAMES[status.stateCode])
|
||||||
|
end
|
||||||
|
|
||||||
|
if status.stateCode == M.STATE.DOWNLOADING then
|
||||||
|
local percent = (status.imageSize > 0) and (math.ceil(status.progress / status.imageSize * 1000) / 10) or 0
|
||||||
|
P(1, " download progress:\t" .. status.progress .. "/" .. status.imageSize .. " (" .. percent .. "%)")
|
||||||
|
end
|
||||||
|
|
||||||
elseif argTable.action == 'showAvailableVersions' then
|
elseif argTable.action == 'showAvailableVersions' then
|
||||||
local verTable,msg = M.getAvailableVersions(argTable.baseUrl, useCache)
|
local verTable,msg = M.getAvailableVersions(argTable.baseUrl, useCache)
|
||||||
if not verTable then
|
if not verTable then
|
||||||
@ -339,14 +440,18 @@ local function main()
|
|||||||
|
|
||||||
if vEnt then
|
if vEnt then
|
||||||
P(0, "Information on version:")
|
P(0, "Information on version:")
|
||||||
P(1, "version: " .. M.formatVersion(vEnt.version))
|
P(1, " version:\t\t" .. M.formatVersion(vEnt.version))
|
||||||
P(1, "sysupgradeFilename: " .. (vEnt.sysupgradeFilename or '<nil>'))
|
P(1, " sysupgradeFilename:\t" .. (vEnt.sysupgradeFilename or '-'))
|
||||||
P(1, "factoryFilename: " .. (vEnt.factoryFilename or '<nil>'))
|
P(1, " sysupgradeFileSize:\t" .. (vEnt.sysupgradeFileSize or '-'))
|
||||||
P(1, "sysupgradeFileSize: " .. (vEnt.sysupgradeFileSize or '<nil>'))
|
P(1, " sysupgradeMD5:\t" .. (vEnt.sysupgradeMD5 or '-'))
|
||||||
P(1, "factoryFileSize: " .. (vEnt.factoryFileSize or '<nil>'))
|
P(1, " factoryFilename:\t" .. (vEnt.factoryFilename or '-'))
|
||||||
P(1, "sysupgradeMD5: " .. (vEnt.sysupgradeMD5 or '<nil>'))
|
P(1, " factoryFileSize:\t" .. (vEnt.factoryFileSize or '-'))
|
||||||
P(1, "factoryMD5: " .. (vEnt.factoryMD5 or '<nil>'))
|
P(1, " factoryMD5:\t\t" .. (vEnt.factoryMD5 or '-'))
|
||||||
P(1, "changelog: " .. (vEnt.changelog or '<nil>'))
|
if vEnt.changelog then
|
||||||
|
P(1, "\n--- Changelog ---\n" .. vEnt.changelog .. '---')
|
||||||
|
else
|
||||||
|
P(1, " changelog:\t\t-")
|
||||||
|
end
|
||||||
else
|
else
|
||||||
P(1, "not found")
|
P(1, "not found")
|
||||||
end
|
end
|
||||||
@ -357,13 +462,19 @@ local function main()
|
|||||||
if rv ~= 0 then E("could not download file (" .. rv .. ")")
|
if rv ~= 0 then E("could not download file (" .. rv .. ")")
|
||||||
else P(1, "success")
|
else P(1, "success")
|
||||||
end
|
end
|
||||||
elseif argTable.action == 'imageRemove' then
|
elseif argTable.action == 'clear' then
|
||||||
P(0, "Removing " .. M.CACHE_PATH .. "/doodle3d-wifibox-*.bin")
|
local rv = M.clear()
|
||||||
--TODO: actually remove
|
if rv ~= 0 then
|
||||||
|
P(1, "error (" .. rv .. ")")
|
||||||
|
else
|
||||||
|
P(1, "success")
|
||||||
|
end
|
||||||
elseif argTable.action == 'imageInstall' then
|
elseif argTable.action == 'imageInstall' then
|
||||||
local rv = M.flashImageVersion(argTable.version)
|
local rv = M.flashImageVersion(argTable.version)
|
||||||
E("error: flash function returned, the device should have been flashed and rebooted instead")
|
E("error: flash function returned, the device should have been flashed and rebooted instead")
|
||||||
os.exit(3)
|
os.exit(3)
|
||||||
|
else
|
||||||
|
P(0, "usage: d3d-updater [-hqVcCvslr] [-u base_url] [-i version] [-d version] [-f version]")
|
||||||
end
|
end
|
||||||
|
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user