diff options
author | Jakub Jirutka <jakub@jirutka.cz> | 2017-07-25 21:44:50 +0200 |
---|---|---|
committer | Jakub Jirutka <jakub@jirutka.cz> | 2017-07-25 21:44:50 +0200 |
commit | a66abec72346d0bd50d0dad6c02c2fc8023e277a (patch) | |
tree | da36dddf35be68bbac04ce9a3b161a59e96b4aa4 /bin/buildrepo.lua | |
parent | b8151f36204607d1697701ad6174af2073ffa77c (diff) | |
download | lua-aports-a66abec72346d0bd50d0dad6c02c2fc8023e277a.tar.bz2 lua-aports-a66abec72346d0bd50d0dad6c02c2fc8023e277a.tar.xz |
move binfiles to bin/ directory
Diffstat (limited to 'bin/buildrepo.lua')
-rwxr-xr-x | bin/buildrepo.lua | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/bin/buildrepo.lua b/bin/buildrepo.lua new file mode 100755 index 0000000..7f6b886 --- /dev/null +++ b/bin/buildrepo.lua @@ -0,0 +1,259 @@ +#!/usr/bin/lua5.2 + +local abuild = require("aports.abuild") +local apkrepo = require("aports.apkrepo") +local lfs = require("lfs") +local optarg = require("optarg") + +local pluginsdir = "/etc/buildrepo/plugins.d" + +local function warn(formatstr, ...) + io.stderr:write(("WARNING: %s\n"):format(formatstr:format(...))) + io.stderr:flush() +end + +local function err(formatstr, ...) + io.stderr:write(("ERROR: %s\n"):format(formatstr:format(...))) + io.stderr:flush() +end + +local function info(formatstr, ...) + io.stdout:write(("%s\n"):format(formatstr:format(...))) + io.stdout:flush() +end + +local function skip_aport(aport) + local dirattr = lfs.attributes(aport.dir.."/src/") + local fileattr = lfs.attributes(aport.dir.."/APKBUILD") + if not dirattr or not fileattr then + return false + end + if os.difftime(fileattr.modification, dirattr.modification) > 0 then + return false + end + warn("%s: Skipped due to previous build failure", aport.pkgname) + return true +end + +local function run_plugins(dirpath, func, ...) + local a = lfs.attributes(dirpath) + if not a or a.mode ~= "directory" then + return + end + local flist = {} + for f in lfs.dir(dirpath) do + if string.match(f, ".lua$") then + table.insert(flist, f) + end + end + table.sort(flist) + for i = 1, #flist do + local m = dofile(dirpath.."/"..flist[i]) + if type(m[func]) == "function" then + m[func](...) + end + end +end + +local function plugins_prebuild(...) + return run_plugins(pluginsdir, "prebuild", ...) +end + +local function plugins_postbuild(...) + return run_plugins(pluginsdir, "postbuild", ...) +end + +local function plugins_prerepo(...) + return run_plugins(pluginsdir, "prerepo", ...) +end + +local function plugins_postrepo(...) + return run_plugins(pluginsdir, "postrepo", ...) +end + +local function logfile_path(logdirbase, repo, aport) + if not logdirbase then + return nil + end + local dir = ("%s/%s/%s"):format(logdirbase, repo, aport.pkgname) + if not lfs.attributes(dir) then + local path = "" + for n in string.gmatch(dir, "[^/]+") do + path = path.."/"..n + lfs.mkdir(path) + end + end + return ("%s/%s-%s-r%s.log"):format(dir, aport.pkgname, aport.pkgver, aport.pkgrel) +end + + +local function build_aport(aport, repodest, logfile) + local success, errmsg = lfs.chdir(aport.dir) + if not success then + err("%s", errmsg) + return nil + end + local logredirect = "" + if logfile ~= nil then + logredirect = ("> '%s' 2>&1"):format(logfile) + end + local cmd = ("REPODEST='%s' abuild -r -m %s"):format(repodest, logredirect) + success = os.execute(cmd) + if not success then + err("%s: Failed to build", aport.pkgname) + end + return success +end + +local function log_progress(progress, repo, aport) + info("%d/%d %d/%d %s/%s %s-r%s", + progress.tried, progress.total, + progress.repo_built, progress.repo_total, + repo, aport.pkgname, aport.pkgver, aport.pkgrel) +end +----------------------------------------------------------------- +local opthelp = [[ + -a, --aports=DIR Set the aports base dir to DIR instead of $HOME/aports + -d, --destdir=DIR Set destination repository base to DIR instead of + $HOME/packages + -h, --help Show this help and exit + -l, --logdir=DIR Create build logs in DIR/REPO/pkgname/ instead of stdout + -k, --keep-going Keep going, even if packages fails + -n, --dry-run Dry run. Don't acutally build or delete, just print + -p, --purge Purge obsolete packages from REPODIR after build + -r, --deps-repo=REPO Dependencies are found in REPO + -s, --skip-failed Skip those who previously failed (src dir exists) +]] + +local function usage(exitcode) + io.stdout:write(( + "Usage: %s [-hknps] [-a DIR] [-d DIR] [-l DIR] [-r REPO] REPO...\n".. + "Options:\n%s\n"):format(_G.arg[0], opthelp)) + os.exit(exitcode) +end + +local opts, args = optarg.from_opthelp(opthelp) +if not opts or #args == 0 then + usage(1) +end + +if opts.h then + usage(0) +end + +local homedir = os.getenv("HOME") +local aportsdir = opts.a or ("%s/aports"):format(homedir) +local repodest = opts.d or abuild.repodest or ("%s/packages"):format(homedir) +local logdirbase = opts.l + +if opts.n then + build_aport = function() return true end +end + +local stats = {} +for _, repo in pairs(args) do + local db = require('aports.db').new(aportsdir, repo, repodest) + local pkgs = {} + local unsorted = {} + stats[repo] = {} + local start_time = os.clock() + + if not db then + err("%s/%s: Failed to open apkbuilds", aportsdir, repo) + os.exit(1) + end + + -- count total aports + local relevant_aports = 0 + local total_aports = 0 + for aport in db:each_aport() do + total_aports = total_aports + 1 + if aport:relevant() then + relevant_aports = relevant_aports + 1 + end + end + stats[repo].relevant_aports = relevant_aports + stats[repo].total_aports = total_aports + + -- run prerepo hooks + plugins_prerepo(repo, aportsdir, repodest, abuild.arch, stats[repo]) + + -- find out what needs to be built + for aport in db:each_need_build() do + table.insert(pkgs, aport.pkgname) + if unsorted[aport.pkgname] then + warn("more than one aport provides %s", aport.pkgname) + end + unsorted[aport.pkgname] = true + end + + -- build packages + local built = 0 + local tried = 0 + for aport in db:each_in_build_order(pkgs) do + local logfile = logfile_path(logdirbase, repo, aport) + tried = tried + 1 + local progress = { + tried = tried, + total = #pkgs, + repo_built = stats[repo].relevant_aports - #pkgs + built, + repo_total = stats[repo].relevant_aports, + } + if not db:known_deps_exists(aport) then + warn("%s: Skipped due to missing dependencies", aport.pkgname) + elseif not (opts.s and skip_aport(aport)) then + log_progress(progress, repo, aport) + plugins_prebuild(aport, progress, repodest, abuild.arch, logfile) + local success = build_aport(aport, repodest, logfile) + plugins_postbuild(aport, success, repodest, abuild.arch, logfile) + if success then + built = built + 1 + end + if not success and not opts.k then + os.exit(1) + end + end + end + + -- purge old packages + local deleted = 0 + if opts.p then + local keep = {} + for aport, name in db:each() do + keep[aport:get_apk_file_name(name)] = true + end + local apkrepodir = ("%s/%s/%s"):format(repodest, repo, abuild.arch) + for file in lfs.dir(apkrepodir) do + if file:match("%.apk$") and not keep[file] then + info("Deleting %s", file) + if not opts.n then + os.remove(("%s/%s"):format(apkrepodir, file)) + deleted = deleted + 1 + end + end + end + end + + -- generate new apkindex + if not opts.n and (built > 0 or deleted > 0) then + info("Updating apk index") + apkrepo.update_index(("%s/%s"):format(repodest, repo), + abuild.arch, db:git_describe()) + end + stats[repo].built = built + stats[repo].tried = tried + stats[repo].deleted = deleted + stats[repo].time = os.clock() - start_time + + -- run portrepo hooks + plugins_postrepo(repo, aportsdir, repodest, abuild.arch, stats[repo]) +end + +for repo, stat in pairs(stats) do + info("%s built:\t%d", repo, stat.built) + info("%s tried:\t%d", repo, stat.tried) + info("%s deleted:\t%d", repo, stat.deleted) + info("%s total built:\t%d", repo, stat.relevant_aports - stat.tried + stat.built) + info("%s total relevant aports:\t%d", repo, stat.relevant_aports) + info("%s total aports:\t%d", repo, stat.total_aports) +end |