mirror of
https://github.com/Doodle3D/doodle3d-firmware.git
synced 2024-12-22 11:03:48 +01:00
Add a number of sanity checks to release script.
Tidying up. Several changes and fixes to beta updating code.
This commit is contained in:
parent
264511f809
commit
524ef027f5
@ -32,6 +32,7 @@ local IMAGE_BASENAME = 'doodle3d-wifibox'
|
|||||||
local BACKUP_FILE_SUFFIX = 'bkp'
|
local BACKUP_FILE_SUFFIX = 'bkp'
|
||||||
local RELEASE_NOTES_FILE = "ReleaseNotes.md"
|
local RELEASE_NOTES_FILE = "ReleaseNotes.md"
|
||||||
local RSYNC_TIMEOUT = 2
|
local RSYNC_TIMEOUT = 2
|
||||||
|
local MAX_VIABLE_IMAGE_SIZE = 3500000
|
||||||
|
|
||||||
local deviceType = 'tl-mr3020' -- or 'tl-wr703'
|
local deviceType = 'tl-mr3020' -- or 'tl-wr703'
|
||||||
local lock = nil
|
local lock = nil
|
||||||
@ -80,6 +81,14 @@ local function detectRootPrivileges()
|
|||||||
return tonumber(userId) == 0 and true or false
|
return tonumber(userId) == 0 and true or false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function findInFile(needle, file)
|
||||||
|
local f = io.open(file, 'r')
|
||||||
|
if not f then return nil,"could not open file" end
|
||||||
|
|
||||||
|
local t = f:read('*all')
|
||||||
|
return not not t:find(needle, 1, true)
|
||||||
|
end
|
||||||
|
|
||||||
local function detectOpenWrtRoot()
|
local function detectOpenWrtRoot()
|
||||||
local f = io.open('Makefile', 'r')
|
local f = io.open('Makefile', 'r')
|
||||||
local line = f and f:read('*line')
|
local line = f and f:read('*line')
|
||||||
@ -133,7 +142,9 @@ local function runAction(actMsg, errMsg, ev, func)
|
|||||||
io.stdout:write("* " .. actMsg .. "...")
|
io.stdout:write("* " .. actMsg .. "...")
|
||||||
local rv,err = func()
|
local rv,err = func()
|
||||||
if not rv then
|
if not rv then
|
||||||
print("Error: " .. errMsg .. " (" .. err .. ")")
|
if err then print("Error: " .. errMsg .. " (" .. err .. ")")
|
||||||
|
else print("Error: " .. errMsg)
|
||||||
|
end
|
||||||
quit(ev)
|
quit(ev)
|
||||||
else
|
else
|
||||||
print("ok")
|
print("ok")
|
||||||
@ -178,7 +189,7 @@ local function prepare()
|
|||||||
local isOpenWrtRoot = detectOpenWrtRoot()
|
local isOpenWrtRoot = detectOpenWrtRoot()
|
||||||
if isOpenWrtRoot then
|
if isOpenWrtRoot then
|
||||||
paths.wrt = pl.path.currentdir()
|
paths.wrt = pl.path.currentdir()
|
||||||
print("found (" .. paths.wrt .. ")")
|
print("found " .. paths.wrt)
|
||||||
else
|
else
|
||||||
print("unrecognized directory, try changing directories or using -wrt-root")
|
print("unrecognized directory, try changing directories or using -wrt-root")
|
||||||
return nil
|
return nil
|
||||||
@ -199,6 +210,7 @@ local function prepare()
|
|||||||
|
|
||||||
-- if empty, try to choose something sensible
|
-- if empty, try to choose something sensible
|
||||||
if not paths.cache or paths.cache == '' then
|
if not paths.cache or paths.cache == '' then
|
||||||
|
--paths.cache = pl.app.appfile('')
|
||||||
paths.cache = '/tmp/d3d-release-dir'
|
paths.cache = '/tmp/d3d-release-dir'
|
||||||
end
|
end
|
||||||
io.stdout:write("* Attempting to use " .. paths.cache .. " as cache dir... ")
|
io.stdout:write("* Attempting to use " .. paths.cache .. " as cache dir... ")
|
||||||
@ -268,6 +280,7 @@ end
|
|||||||
|
|
||||||
local function generateIndex(newVersion, versionTable, isStable)
|
local function generateIndex(newVersion, versionTable, isStable)
|
||||||
local indexFilename = isStable and um.IMAGE_STABLE_INDEX_FILE or um.IMAGE_BETA_INDEX_FILE
|
local indexFilename = isStable and um.IMAGE_STABLE_INDEX_FILE or um.IMAGE_BETA_INDEX_FILE
|
||||||
|
versionTable[#versionTable+1] = newVersion
|
||||||
local sortedVers = pl.List(versionTable)
|
local sortedVers = pl.List(versionTable)
|
||||||
sortedVers:sort(function(a, b)
|
sortedVers:sort(function(a, b)
|
||||||
return um.compareVersions(a.version, b.version, a.timestamp, b.timestamp) < 0
|
return um.compareVersions(a.version, b.version, a.timestamp, b.timestamp) < 0
|
||||||
@ -303,14 +316,20 @@ local function copyImages(newVersion)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function copyReleaseNotes()
|
local function copyReleaseNotes(newVersion)
|
||||||
local releaseNotesPath = pl.path.join(imageCachePath(), RELEASE_NOTES_FILE)
|
local srcReleaseNotesPath = pl.path.join(paths.firmware, RELEASE_NOTES_FILE)
|
||||||
if pl.path.isfile(releaseNotesPath) then
|
local tgtReleaseNotesPath = pl.path.join(imageCachePath(), RELEASE_NOTES_FILE)
|
||||||
local rv = pl.file.copy(releaseNotesPath, pl.path.join(paths.cache, RELEASE_NOTES_FILE..'.'..BACKUP_FILE_SUFFIX))
|
|
||||||
|
if not findInFile(um.formatVersion(newVersion.version), srcReleaseNotesPath) then
|
||||||
|
return nil,"version not mentioned in release notes file"
|
||||||
|
end
|
||||||
|
|
||||||
|
if pl.path.isfile(tgtReleaseNotesPath) then
|
||||||
|
local rv = pl.file.copy(tgtReleaseNotesPath, tgtReleaseNotesPath..'.'..BACKUP_FILE_SUFFIX)
|
||||||
if not rv then return nil,"could not backup file" end
|
if not rv then return nil,"could not backup file" end
|
||||||
end
|
end
|
||||||
|
|
||||||
local rv = pl.file.copy(pl.path.join(paths.firmware, RELEASE_NOTES_FILE), releaseNotesPath)
|
local rv = pl.file.copy(srcReleaseNotesPath, tgtReleaseNotesPath)
|
||||||
if not rv then return nil,"could not copy file" end
|
if not rv then return nil,"could not copy file" end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -333,6 +352,26 @@ local function uploadFiles()
|
|||||||
return rv and true or nil,("rsync failed, exit status: " .. ev)
|
return rv and true or nil,("rsync failed, exit status: " .. ev)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function checkWrtConfig()
|
||||||
|
local goodConfigPath = pl.path.join(paths.firmware, "extra/openwrt-build/openwrt-diffconfig-extramini")
|
||||||
|
local wrtConfigPath = pl.path.tmpname()
|
||||||
|
--print("diffonfig output file: " .. wrtConfigPath)
|
||||||
|
|
||||||
|
local rv,ev = pl.utils.execute('./scripts/diffconfig.sh > "' .. wrtConfigPath .. '"')
|
||||||
|
if not rv then return nil,"could not run diffconfig script (exit status: " .. ev .. ")" end
|
||||||
|
|
||||||
|
local _,rv,output = pl.utils.executeex('diff "' .. wrtConfigPath .. '" "' .. goodConfigPath .. '"')
|
||||||
|
|
||||||
|
if rv == 0 then
|
||||||
|
return true
|
||||||
|
elseif rv == 1 then
|
||||||
|
print("configurations differ:\n-----------------------\n" .. output .. "\n-----------------------")
|
||||||
|
--ask for confirmation?
|
||||||
|
else
|
||||||
|
return nil,"unexpected exit status from diff (" .. rv .. ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function main()
|
local function main()
|
||||||
print("\nDoodle3D release script")
|
print("\nDoodle3D release script")
|
||||||
if detectRootPrivileges() then
|
if detectRootPrivileges() then
|
||||||
@ -359,19 +398,13 @@ local function main()
|
|||||||
quit(3)
|
quit(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
local isStable = (newVersion.version.suffix == nil)
|
|
||||||
print("\nRolling release for firmware version " .. um.formatVersion(newVersion.version) .. " (type: " .. (isStable and "stable" or "beta") .. ").")
|
|
||||||
|
|
||||||
local stables,betas = fetchVersionInfo()
|
local stables,betas = fetchVersionInfo()
|
||||||
if not stables then
|
if not stables then
|
||||||
print("Error: could not get version information (" .. betas .. ")")
|
print("Error: could not get version information (" .. betas .. ")")
|
||||||
quit(1)
|
quit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
if um.findVersion(newVersion.version, nil, stables) or um.findVersion(newVersion.version, nil, betas) then
|
--TODO: if requested, fetch images and packages (i.e., mirror whole directory)
|
||||||
print("Error: firmware version " .. um.formatVersion(newVersion.version) .. " already exists")
|
|
||||||
quit(3)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- pl.pretty.dump(newVersion)
|
-- pl.pretty.dump(newVersion)
|
||||||
@ -379,23 +412,41 @@ local function main()
|
|||||||
-- print("===========================");
|
-- print("===========================");
|
||||||
-- print("betas: "); pl.pretty.dump(betas)
|
-- print("betas: "); pl.pretty.dump(betas)
|
||||||
|
|
||||||
--TODO: if requested, fetch images and packages (i.e., mirror whole directory)
|
|
||||||
--TODO: run sanity checks
|
|
||||||
|
|
||||||
|
print("\nRunning sanity checks")
|
||||||
|
|
||||||
runAction("Generating new index file", "could not generate index", 4, function()
|
runAction("Checking whether version is unique",
|
||||||
|
"firmware version " .. um.formatVersion(newVersion.version) .. " already exists", 3, function()
|
||||||
|
return not (um.findVersion(newVersion.version, nil, stables) or um.findVersion(newVersion.version, nil, betas)) and true or nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
runAction("Checking OpenWrt config", "failed", 3, checkWrtConfig)
|
||||||
|
|
||||||
|
--TODO: check git repos (`git log -n 1 --pretty=format:%ct` gives commit date of last commit (not author date))
|
||||||
|
|
||||||
|
local isStable = (newVersion.version.suffix == nil)
|
||||||
|
print("\nRolling release for firmware version " .. um.formatVersion(newVersion.version) .. " (type: " .. (isStable and "stable" or "beta") .. ").")
|
||||||
|
|
||||||
|
if newVersion.sysupgradeFileSize > MAX_VIABLE_IMAGE_SIZE then
|
||||||
|
print("Error: sysupgrade image file is too large, it will not run well (max. size: " .. MAX_VIABLE_IMAGE_SIZE .. " bytes)")
|
||||||
|
quit(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
runAction("Copying release notes", "failed", 5, function()
|
||||||
|
return copyReleaseNotes(newVersion)
|
||||||
|
end)
|
||||||
|
|
||||||
|
runAction("Generating new index file", "could not generate index", 5, function()
|
||||||
return generateIndex(newVersion, isStable and stables or betas, isStable)
|
return generateIndex(newVersion, isStable and stables or betas, isStable)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
runAction("Copying image files", "could not generate index", 4, function()
|
runAction("Copying image files", "could not generate index", 5, function()
|
||||||
return copyImages(newVersion)
|
return copyImages(newVersion)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
runAction("Copying release notes", "failed", 4, copyReleaseNotes)
|
|
||||||
|
|
||||||
io.stdout:write("* Building package feed directory...")
|
io.stdout:write("* Building package feed directory...")
|
||||||
print("skipped - not implemented")
|
print("skipped - not implemented")
|
||||||
-- runAction("Building package feed directory", "failed", 4, buildFeedDir)
|
-- runAction("Building package feed directory", "failed", 5, buildFeedDir)
|
||||||
|
|
||||||
|
|
||||||
local answer = getYesNo("? Local updates directory will be synced to remote server, proceed? (y/n) ")
|
local answer = getYesNo("? Local updates directory will be synced to remote server, proceed? (y/n) ")
|
||||||
@ -404,7 +455,7 @@ local function main()
|
|||||||
quit(5)
|
quit(5)
|
||||||
end
|
end
|
||||||
|
|
||||||
runAction("About to sync files to server", "could not upload files", 5, uploadFiles)
|
runAction("About to sync files to server", "could not upload files", 6, uploadFiles)
|
||||||
|
|
||||||
print("Done.")
|
print("Done.")
|
||||||
quit()
|
quit()
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
-- - _description_: A descriptive text usable by API clients
|
-- - _description_: A descriptive text usable by API clients
|
||||||
-- - _min_, _max_, _regex_: optional constraints (min and max constrain value for numbers, or length for strings)
|
-- - _min_, _max_, _regex_: optional constraints (min and max constrain value for numbers, or length for strings)
|
||||||
-- - _isValid_: an optional function which should return true for valid values and false for invalid ones
|
-- - _isValid_: an optional function which should return true for valid values and false for invalid ones
|
||||||
-- - _subSection: optional: setting name of which current value is used as the uci section where this setting should be loaded from. Otherwise it's retrieved from the generic section. Setting subsection also means it will first try to get a default from subconf_defaults, if that doesn't exsist it will use the regular default
|
-- - _subSection: optional: setting name of which current value is used as the uci section where this setting should be loaded from. Otherwise it's retrieved from the generic section. Setting subsection also means it will first try to get a default from subconf_defaults, if that doesn't exsist it will use the regular default
|
||||||
-- The configuration keys themselves document themselves rather well, hence they are not included in the generated documentation.
|
-- The configuration keys themselves document themselves rather well, hence they are not included in the generated documentation.
|
||||||
--
|
--
|
||||||
-- NOTE: the all-caps definitions should be changed into configuration keys, or moved to a better location.
|
-- NOTE: the all-caps definitions should be changed into configuration keys, or moved to a better location.
|
||||||
@ -106,7 +106,7 @@ M.printer_dimensions_x = {
|
|||||||
default_delta_rostockmax = 0,
|
default_delta_rostockmax = 0,
|
||||||
default_deltamaker = 0,
|
default_deltamaker = 0,
|
||||||
default_kossel = 0,
|
default_kossel = 0,
|
||||||
default_minifactory = 150,
|
default_minifactory = 150,
|
||||||
subSection = 'printer_type',
|
subSection = 'printer_type',
|
||||||
type = 'int',
|
type = 'int',
|
||||||
description = '',
|
description = '',
|
||||||
@ -335,7 +335,7 @@ M.doodle3d_tour_enabled = {
|
|||||||
description = 'Show tour to new users'
|
description = 'Show tour to new users'
|
||||||
}
|
}
|
||||||
|
|
||||||
M.doodle3d_betas = {
|
M.doodle3d_includeBetas = {
|
||||||
default = false,
|
default = false,
|
||||||
type = 'bool',
|
type = 'bool',
|
||||||
description = 'Update to beta releases',
|
description = 'Update to beta releases',
|
||||||
|
@ -49,7 +49,7 @@ end
|
|||||||
function M.status(request, response)
|
function M.status(request, response)
|
||||||
updater.setLogger(log)
|
updater.setLogger(log)
|
||||||
updater.setUseCache(false)
|
updater.setUseCache(false)
|
||||||
local includeBetas = settings.get('doodle3d.betas')
|
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||||
local success,status,msg = updater.getStatus(includeBetas)
|
local success,status,msg = updater.getStatus(includeBetas)
|
||||||
|
|
||||||
response:addData('current_version', updater.formatVersion(status.currentVersion))
|
response:addData('current_version', updater.formatVersion(status.currentVersion))
|
||||||
@ -93,9 +93,9 @@ function M.download_POST(request, response)
|
|||||||
updater.setState(updater.STATE.DOWNLOADING,"")
|
updater.setState(updater.STATE.DOWNLOADING,"")
|
||||||
|
|
||||||
local vEnt, rv, msg
|
local vEnt, rv, msg
|
||||||
|
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||||
|
|
||||||
if not argVersion then
|
if not argVersion then
|
||||||
local includeBetas = settings.get('doodle3d.betas')
|
|
||||||
local success,status,msg = updater.getStatus(includeBetas)
|
local success,status,msg = updater.getStatus(includeBetas)
|
||||||
if not success then
|
if not success then
|
||||||
updater.setState(updater.STATE.DOWNLOAD_FAILED, msg)
|
updater.setState(updater.STATE.DOWNLOAD_FAILED, msg)
|
||||||
@ -126,7 +126,7 @@ function M.download_POST(request, response)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
vEnt,msg = updater.findVersion(argVersion)
|
vEnt,msg = updater.findVersion(argVersion, includeBetas)
|
||||||
if vEnt == nil then
|
if vEnt == nil then
|
||||||
updater.setState(updater.STATE.DOWNLOAD_FAILED, "error searching version index (" .. msg .. ")")
|
updater.setState(updater.STATE.DOWNLOAD_FAILED, "error searching version index (" .. msg .. ")")
|
||||||
response:setFail("error searching version index (" .. msg .. ")")
|
response:setFail("error searching version index (" .. msg .. ")")
|
||||||
@ -163,9 +163,9 @@ function M.install_POST(request, response)
|
|||||||
|
|
||||||
--local ssid = wifi.getSubstitutedSsid(settings.get('network.ap.ssid'))
|
--local ssid = wifi.getSubstitutedSsid(settings.get('network.ap.ssid'))
|
||||||
--local rv,msg = netconf.enableAccessPoint(ssid)
|
--local rv,msg = netconf.enableAccessPoint(ssid)
|
||||||
|
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||||
|
|
||||||
if not argVersion then
|
if not argVersion then
|
||||||
local includeBetas = settings.get('doodle3d.betas')
|
|
||||||
local success,status,msg = updater.getStatus(includeBetas)
|
local success,status,msg = updater.getStatus(includeBetas)
|
||||||
if not success then
|
if not success then
|
||||||
updater.setState(updater.STATE.INSTALL_FAILED, msg)
|
updater.setState(updater.STATE.INSTALL_FAILED, msg)
|
||||||
@ -176,7 +176,7 @@ function M.install_POST(request, response)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
vEnt,msg = updater.findVersion(argVersion)
|
vEnt,msg = updater.findVersion(argVersion, includeBetas)
|
||||||
if vEnt == nil then
|
if vEnt == nil then
|
||||||
updater.setState(updater.STATE.INSTALL_FAILED, "error searching version index (" .. msg .. ")")
|
updater.setState(updater.STATE.INSTALL_FAILED, "error searching version index (" .. msg .. ")")
|
||||||
response:setFail("error searching version index (" .. msg .. ")")
|
response:setFail("error searching version index (" .. msg .. ")")
|
||||||
|
@ -67,7 +67,7 @@ M.WGET_OPTIONS = "-q -t 1 -T 30"
|
|||||||
|
|
||||||
local verbosity = 0 -- set by parseCommandlineArguments() or @{setVerbosity}
|
local verbosity = 0 -- set by parseCommandlineArguments() or @{setVerbosity}
|
||||||
local log = nil -- wifibox API can use M.setLogger to enable this module to use its logger
|
local log = nil -- wifibox API can use M.setLogger to enable this module to use its logger
|
||||||
local useCache = true -- default, can be overwritten using @{setUseCache}
|
local useCache = false -- default, can be overwritten using @{setUseCache}
|
||||||
local cachePath = M.DEFAULT_CACHE_PATH -- default, can be change using @{setCachePath}
|
local cachePath = M.DEFAULT_CACHE_PATH -- default, can be change using @{setCachePath}
|
||||||
local baseUrl = M.DEFAULT_BASE_URL -- default, can be overwritten by M.setBaseUrl()
|
local baseUrl = M.DEFAULT_BASE_URL -- default, can be overwritten by M.setBaseUrl()
|
||||||
|
|
||||||
@ -808,7 +808,7 @@ function M.flashImageVersion(versionEntry, noRetain, devType, isFactory)
|
|||||||
return (rv == 0) and true or nil,rv
|
return (rv == 0) and true or nil,rv
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Clears '*.bin' in the @{cachePath} directory.
|
--- Clears '*.bin' and both index files in the @{cachePath} directory.
|
||||||
-- @treturn bool|nil True on success, or nil on error.
|
-- @treturn bool|nil True on success, or nil on error.
|
||||||
-- @treturn ?string Descriptive message on error.
|
-- @treturn ?string Descriptive message on error.
|
||||||
function M.clear()
|
function M.clear()
|
||||||
@ -817,8 +817,16 @@ function M.clear()
|
|||||||
|
|
||||||
D("Removing " .. cachePath .. "/doodle3d-wifibox-*.bin")
|
D("Removing " .. cachePath .. "/doodle3d-wifibox-*.bin")
|
||||||
M.setState(M.STATE.NONE, "")
|
M.setState(M.STATE.NONE, "")
|
||||||
|
local success = true
|
||||||
local rv = M.compatexecute('rm -f ' .. cachePath .. '/doodle3d-wifibox-*.bin')
|
local rv = M.compatexecute('rm -f ' .. cachePath .. '/doodle3d-wifibox-*.bin')
|
||||||
return rv and true or nil,"could not remove image files"
|
success = success and (rv == 0)
|
||||||
|
local rv = M.compatexecute('rm -f ' .. cachePath .. '/' .. M.IMAGE_STABLE_INDEX_FILE)
|
||||||
|
success = success and (rv == 0)
|
||||||
|
local rv = M.compatexecute('rm -f ' .. cachePath .. '/' .. M.IMAGE_BETA_INDEX_FILE)
|
||||||
|
success = success and (rv == 0)
|
||||||
|
|
||||||
|
--return success,"could not delete all files"
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set updater state.
|
--- Set updater state.
|
||||||
@ -882,7 +890,7 @@ local function main()
|
|||||||
P(1, "\t-q\t\tquiet mode")
|
P(1, "\t-q\t\tquiet mode")
|
||||||
P(1, "\t-V\t\tverbose mode")
|
P(1, "\t-V\t\tverbose mode")
|
||||||
P(1, "\t-c\t\tUse cache as much as possible")
|
P(1, "\t-c\t\tUse cache as much as possible")
|
||||||
P(1, "\t-C\t\tDo not use the cache")
|
P(1, "\t-C\t\tDo not use the cache (default)")
|
||||||
P(1, "\t-u <base_url>\tUse specified base URL (default: " .. M.DEFAULT_BASE_URL .. ")")
|
P(1, "\t-u <base_url>\tUse specified base URL (default: " .. M.DEFAULT_BASE_URL .. ")")
|
||||||
P(1, "\t-b\t\tInclude beta releases")
|
P(1, "\t-b\t\tInclude beta releases")
|
||||||
P(1, "\t-v\t\tShow current image version")
|
P(1, "\t-v\t\tShow current image version")
|
||||||
|
Loading…
Reference in New Issue
Block a user