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 RELEASE_NOTES_FILE = "ReleaseNotes.md"
|
||||
local RSYNC_TIMEOUT = 2
|
||||
local MAX_VIABLE_IMAGE_SIZE = 3500000
|
||||
|
||||
local deviceType = 'tl-mr3020' -- or 'tl-wr703'
|
||||
local lock = nil
|
||||
@ -80,6 +81,14 @@ local function detectRootPrivileges()
|
||||
return tonumber(userId) == 0 and true or false
|
||||
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 f = io.open('Makefile', 'r')
|
||||
local line = f and f:read('*line')
|
||||
@ -133,7 +142,9 @@ local function runAction(actMsg, errMsg, ev, func)
|
||||
io.stdout:write("* " .. actMsg .. "...")
|
||||
local rv,err = func()
|
||||
if not rv then
|
||||
print("Error: " .. errMsg .. " (" .. err .. ")")
|
||||
if err then print("Error: " .. errMsg .. " (" .. err .. ")")
|
||||
else print("Error: " .. errMsg)
|
||||
end
|
||||
quit(ev)
|
||||
else
|
||||
print("ok")
|
||||
@ -178,7 +189,7 @@ local function prepare()
|
||||
local isOpenWrtRoot = detectOpenWrtRoot()
|
||||
if isOpenWrtRoot then
|
||||
paths.wrt = pl.path.currentdir()
|
||||
print("found (" .. paths.wrt .. ")")
|
||||
print("found " .. paths.wrt)
|
||||
else
|
||||
print("unrecognized directory, try changing directories or using -wrt-root")
|
||||
return nil
|
||||
@ -199,6 +210,7 @@ local function prepare()
|
||||
|
||||
-- if empty, try to choose something sensible
|
||||
if not paths.cache or paths.cache == '' then
|
||||
--paths.cache = pl.app.appfile('')
|
||||
paths.cache = '/tmp/d3d-release-dir'
|
||||
end
|
||||
io.stdout:write("* Attempting to use " .. paths.cache .. " as cache dir... ")
|
||||
@ -268,6 +280,7 @@ end
|
||||
|
||||
local function generateIndex(newVersion, versionTable, isStable)
|
||||
local indexFilename = isStable and um.IMAGE_STABLE_INDEX_FILE or um.IMAGE_BETA_INDEX_FILE
|
||||
versionTable[#versionTable+1] = newVersion
|
||||
local sortedVers = pl.List(versionTable)
|
||||
sortedVers:sort(function(a, b)
|
||||
return um.compareVersions(a.version, b.version, a.timestamp, b.timestamp) < 0
|
||||
@ -303,14 +316,20 @@ local function copyImages(newVersion)
|
||||
return true
|
||||
end
|
||||
|
||||
local function copyReleaseNotes()
|
||||
local releaseNotesPath = pl.path.join(imageCachePath(), RELEASE_NOTES_FILE)
|
||||
if pl.path.isfile(releaseNotesPath) then
|
||||
local rv = pl.file.copy(releaseNotesPath, pl.path.join(paths.cache, RELEASE_NOTES_FILE..'.'..BACKUP_FILE_SUFFIX))
|
||||
local function copyReleaseNotes(newVersion)
|
||||
local srcReleaseNotesPath = pl.path.join(paths.firmware, RELEASE_NOTES_FILE)
|
||||
local tgtReleaseNotesPath = pl.path.join(imageCachePath(), RELEASE_NOTES_FILE)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
return true
|
||||
@ -333,6 +352,26 @@ local function uploadFiles()
|
||||
return rv and true or nil,("rsync failed, exit status: " .. ev)
|
||||
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()
|
||||
print("\nDoodle3D release script")
|
||||
if detectRootPrivileges() then
|
||||
@ -359,19 +398,13 @@ local function main()
|
||||
quit(3)
|
||||
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()
|
||||
if not stables then
|
||||
print("Error: could not get version information (" .. betas .. ")")
|
||||
quit(1)
|
||||
end
|
||||
|
||||
if um.findVersion(newVersion.version, nil, stables) or um.findVersion(newVersion.version, nil, betas) then
|
||||
print("Error: firmware version " .. um.formatVersion(newVersion.version) .. " already exists")
|
||||
quit(3)
|
||||
end
|
||||
--TODO: if requested, fetch images and packages (i.e., mirror whole directory)
|
||||
|
||||
|
||||
-- pl.pretty.dump(newVersion)
|
||||
@ -379,23 +412,41 @@ local function main()
|
||||
-- print("===========================");
|
||||
-- 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)
|
||||
end)
|
||||
|
||||
runAction("Copying image files", "could not generate index", 4, function()
|
||||
runAction("Copying image files", "could not generate index", 5, function()
|
||||
return copyImages(newVersion)
|
||||
end)
|
||||
|
||||
runAction("Copying release notes", "failed", 4, copyReleaseNotes)
|
||||
|
||||
io.stdout:write("* Building package feed directory...")
|
||||
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) ")
|
||||
@ -404,7 +455,7 @@ local function main()
|
||||
quit(5)
|
||||
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.")
|
||||
quit()
|
||||
|
@ -19,7 +19,7 @@
|
||||
-- - _description_: A descriptive text usable by API clients
|
||||
-- - _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
|
||||
-- - _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.
|
||||
--
|
||||
-- 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_deltamaker = 0,
|
||||
default_kossel = 0,
|
||||
default_minifactory = 150,
|
||||
default_minifactory = 150,
|
||||
subSection = 'printer_type',
|
||||
type = 'int',
|
||||
description = '',
|
||||
@ -335,7 +335,7 @@ M.doodle3d_tour_enabled = {
|
||||
description = 'Show tour to new users'
|
||||
}
|
||||
|
||||
M.doodle3d_betas = {
|
||||
M.doodle3d_includeBetas = {
|
||||
default = false,
|
||||
type = 'bool',
|
||||
description = 'Update to beta releases',
|
||||
|
@ -49,7 +49,7 @@ end
|
||||
function M.status(request, response)
|
||||
updater.setLogger(log)
|
||||
updater.setUseCache(false)
|
||||
local includeBetas = settings.get('doodle3d.betas')
|
||||
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||
local success,status,msg = updater.getStatus(includeBetas)
|
||||
|
||||
response:addData('current_version', updater.formatVersion(status.currentVersion))
|
||||
@ -93,9 +93,9 @@ function M.download_POST(request, response)
|
||||
updater.setState(updater.STATE.DOWNLOADING,"")
|
||||
|
||||
local vEnt, rv, msg
|
||||
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||
|
||||
if not argVersion then
|
||||
local includeBetas = settings.get('doodle3d.betas')
|
||||
local success,status,msg = updater.getStatus(includeBetas)
|
||||
if not success then
|
||||
updater.setState(updater.STATE.DOWNLOAD_FAILED, msg)
|
||||
@ -126,7 +126,7 @@ function M.download_POST(request, response)
|
||||
end
|
||||
end
|
||||
|
||||
vEnt,msg = updater.findVersion(argVersion)
|
||||
vEnt,msg = updater.findVersion(argVersion, includeBetas)
|
||||
if vEnt == nil then
|
||||
updater.setState(updater.STATE.DOWNLOAD_FAILED, "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 rv,msg = netconf.enableAccessPoint(ssid)
|
||||
local includeBetas = settings.get('doodle3d.includeBetas')
|
||||
|
||||
if not argVersion then
|
||||
local includeBetas = settings.get('doodle3d.betas')
|
||||
local success,status,msg = updater.getStatus(includeBetas)
|
||||
if not success then
|
||||
updater.setState(updater.STATE.INSTALL_FAILED, msg)
|
||||
@ -176,7 +176,7 @@ function M.install_POST(request, response)
|
||||
end
|
||||
end
|
||||
|
||||
vEnt,msg = updater.findVersion(argVersion)
|
||||
vEnt,msg = updater.findVersion(argVersion, includeBetas)
|
||||
if vEnt == nil then
|
||||
updater.setState(updater.STATE.INSTALL_FAILED, "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 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 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
|
||||
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 ?string Descriptive message on error.
|
||||
function M.clear()
|
||||
@ -817,8 +817,16 @@ function M.clear()
|
||||
|
||||
D("Removing " .. cachePath .. "/doodle3d-wifibox-*.bin")
|
||||
M.setState(M.STATE.NONE, "")
|
||||
local success = true
|
||||
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
|
||||
|
||||
--- Set updater state.
|
||||
@ -882,7 +890,7 @@ local function main()
|
||||
P(1, "\t-q\t\tquiet mode")
|
||||
P(1, "\t-V\t\tverbose mode")
|
||||
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-b\t\tInclude beta releases")
|
||||
P(1, "\t-v\t\tShow current image version")
|
||||
|
Loading…
Reference in New Issue
Block a user