Add a number of sanity checks to release script.

Tidying up.
Several changes and fixes to beta updating code.
This commit is contained in:
Wouter R 2014-02-24 15:22:08 +01:00
parent 264511f809
commit 524ef027f5
4 changed files with 93 additions and 34 deletions

View File

@ -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()

View File

@ -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',

View File

@ -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 .. ")")

View File

@ -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")