--- LuaDist manifest specific functions including checks -- Peter Drahos, Peter Kapec, LuaDist Project, 2008 module ("dist.manifest", package.seeall) local fetch = require "dist.fetch" local persist = require "dist.persist" local sys = require "dist.sys" local config = require "dist.config" --- Make dist.manifest inside given directory. -- @param directory string: Directory to make manifest in. -- @return ok, err: True when successful, nil and error message on failure. function makeManifest(directory) assert(type(directory)=="string", "makeManifest argument 'directory' not a string.") local dir = string.gsub(directory,"file://","") local t for _,file in pairs(sys.dir(dir) or {}) do -- Search for any package local name, version, arch, type = file:match("([^\-]+)\-([^\-]+)\-*([^\-]*)\-*([^\-]*)\.dist$") -- Maybe its a package dir .. lets try loading dist.info local dist = persist.load(dir .. "/" .. file .. "/dist.info") if dist then name, version, arch, type = dist.name, dist.version, dist.arch, dist.type end -- Check if its a package if name and version then if not arch or arch == "" then arch = "Universal" end if not type or type == "" then type = "source" end if not t then t = {} end if not t[name] then t[name] = {} end if not t[name][version] then t[name][version] = {} end if not t[name][version][arch] then t[name][version][arch] = {} end t[name][version][arch][type]=file end end if not t then return nil, "No files to make manifest for." end return t end --- Collect all installed packages info. -- @param depl string: Deployment directory to collect modules in. -- @return table, err: List of collected info tables. Returns nil and error on failure. function collectPackages(depl) assert(not depl or type(depl)=="string") depl = depl or config.root local share = depl .. "/" .. config.share local packages = {} for _,name in pairs(sys.dir(share) or {}) do if sys.exists(share .. "/" .. name .. "/dist.info") then local info, err = getInfo(share .. "/" .. name .. "/dist.info") if not info then return nil, err end table.insert(packages, info) end end return packages end --- Get or generate repository contents from repo url. -- @param url string: URL to load the dist.manifest from. In case file:// is used generate the manifest. -- @return ok, err: Returns true on success and nil and error message on failure. function getRepository(url) assert(type(url)=="string", "getRepository argument 'url' is not a string.") local manifest = fetch.get(url.."/dist.manifest") if manifest then local repo, err = persist.loadText(manifest) if repo then -- Check the contents if not type(repo)=="table" then return nil, "Manifest does not contain module table in repository " .. url .. "." end for package, versions in pairs(repo) do if not type(package)=="string" or not type(versions)=="table" then return nil, "Manifest does not contain valid module table in repository " .. url .. "." end for version, archs in pairs(versions) do if not type(version)=="string" or not type(archs)== "table" then return nil, "Manifest module " .. package .. " in repository " .. url .. " does not contain valid version table." end for arch, types in pairs(archs) do if not type(arch)=="string" or not type(types)=="table" then return nil, "Manifest module " .. package .. "-" .. version .. " in repository " .. url .. " does not contain valid architecture table" end for typ, file in pairs(types) do if not type(typ)=="string" or not type(file)=="string" then return nil, "Manifest module " .. package .. "-" .. version .. "-" .. arch .. " in repository " .. url .. " does not contain valid type package." end end end end end return repo end return nil, "Manifest could not be loaded for repository " .. url .. "." elseif url:match("^file://") then return makeManifest(url) end return nil, "Manifest for " .. url .. " does not exist." end --- Load and check info from dist.info. -- @param path string: Path to dist.info. -- @return info, err: Table containing loaded info or nil and error message. function getInfo(path) assert(type(path)=="string", "getInfo argument 'path' is not a string.") local info, err = persist.load(path) if not info then return nil, "Failed loading dist.info: " .. path .. "\n\t" .. err end info.arch = info.arch or "Universal" info.type = info.type or "source" -- Check the info entries if not type(info.name)=="string" then return nil, "Info does not contain valid name. " .. path end if not type(info.version)=="string" then return nil, "Info does not contain valid version. " .. path end if not type(info.arch)=="string" then return nil, "Info does not contain valid architecture. File:" .. path end if not type(info.type)=="string" then return nil, "Info does not contain valid type. File:" .. path end if info.short and not type(info.short)=="string" then return nil, "Info does not contain valid short description. File:" .. path end if info.full and not type(info.full)=="string" then return nil, "Info does not contain valid full description. File:" .. path end if info.author and not type(info.author)=="string" then return nil, "Info does not contain valid author. File:" .. path end if info.maintainer and not type(info.maintainer)=="string" then return nil, "Info does not contain valid maintainer. File:" .. path end if info.homepage and not type(info.homepage)=="string" then return nil, "Info does not contain valid homepage. File:" .. path end if info.license and not type(info.license)=="string" then return nil, "Info does not contain valid license. File:" .. path end if info.dependencies and not type(info.dependencies)=="table" then return nil, "Info does not contain valid dependencies. File:" .. path end if info.dependencies and info.dependencies.external and not type(info.dependencies.external)=="table" then return nil, "Info does not contain valid external dependencies. File:" .. path end if info.files and not type(info.files)=="table" then return nil, "Info does not contain valid files entry. File:" .. path end return info end