#!/opt/lnxall_app/bin/lua -- Created by jiaqiang.ye@lnxall.com -- LNXALL Version List Generator -- 2025/09/01 local cjson = require "cjson" local invoker = require "invoker" local gfmt = string.format local g_VERDIR = "/app/upstart/verlist" local g_VERLOCK = "/tmp/.lock-lnxall-version" local g_VEROUT = "/tmp/.lnxall-version-list.json" local g_syslist = { [1] = "sysmonitor", [2] = "deb4gnet", [3] = "ucinet", [4] = "ntpdrtc", [5] = "broadcast", [6] = "gpio_powerchk", } local g_verlist = {} local function bad_str(s) if type(s) ~= "string" then return true end if string.len(s) == 0 then return true end return false end local function good_str(s) if type(s) == "string" and #s > 0 then return true end return false end local function verlist_add(pkgname, pkgver, pkgdesc) if bad_str(pkgname) or bad_str(pkgver) then return false end local idx, found = 0, nil while true do idx = idx + 1 local verinfo = g_verlist[idx] if verinfo == nil then break end if verinfo.name == pkgname then found = idx break end end if bad_str(pkgdesc) then pkgdesc = nil end if found then local vi = g_verlist[found] vi.version = pkgver vi.description = pkgdesc else g_verlist[#g_verlist + 1] = { ["name"] = pkgname, ["version"] = pkgver, ["description"] = pkgdesc, } end io.stdout:write(gfmt("Package version found, name: %s, version: %s, description: %s\n", pkgname, pkgver, pkgdesc or "")) io.stdout:flush() return found or #g_verlist end local function glob_verlist() local vlist = invoker.glob(gfmt("%s/*.json", g_VERDIR)) if type(vlist) ~= "table" then io.stderr:write(gfmt("No JSON file found in '%s'\n", g_VERDIR)) io.stderr:flush() return false end for _, vj in ipairs(vlist) do local okay, jver = false, nil local vstr = invoker.readfile(vj, 0x40000) if not bad_str(vstr) then okay, jver = pcall(cjson.decode, vstr) end if okay and type(jver) == "table" then verlist_add(jver.name, jver.version, jver.description) else io.stderr:write(gfmt("Error, failed to decode as JSON: %s\n", vj)) io.stderr:flush() end end end local function opkg_version() for _, pkg in ipairs(g_syslist) do local okay, output = invoker.invoke(invoker.OUTPUT, "opkg", "status", pkg) if okay and type(output) == "string" and #output > 0 then local verstr = nil for line in string.gmatch(output, "[^\r\n]+") do verstr = string.match(line, "^Version:%s+([^%s]+)%s*$") if good_str(verstr) then break end end if good_str(verstr) then verlist_add(pkg, verstr, nil) end else io.stderr:write(gfmt("Warning, package seems to be uninstalled: %s\n", pkg)) io.stderr:flush() end end end local function lnxver_main(arg1) if good_str(arg1) then g_VEROUT = arg1 end local lockfd = invoker.waitlock(g_VERLOCK) if not lockfd then io.stderr:write(gfmt("Error, failed to lock file: %s\n", g_VERLOCK)) io.stderr:flush() end glob_verlist() opkg_version() local vnum = #g_verlist if vnum == 0 then io.stderr:write("Error, no package version found.\n") io.stderr:flush() return false end local vhdl = io.open(g_VEROUT, "wb") if vhdl then local vbuf = cjson.encode(g_verlist) if vbuf:sub(1, 1) ~= "{" then vbuf = gfmt('{"verlist":%s}', vbuf) end vhdl:write(vbuf) vhdl:close(); vhdl = nil io.stdout:write(gfmt("Version file written to: %s\n", g_VEROUT)) io.stdout:flush() return true end io.stderr:write(gfmt("Error, failed to open file for writing: %s\n", g_VEROUT)) io.stderr:flush() return false end os.exit(lnxver_main(arg[1]) and 0 or 1)