summaryrefslogtreecommitdiffstats
path: root/bin/buildrepo.lua
diff options
context:
space:
mode:
authorJakub Jirutka <jakub@jirutka.cz>2017-07-25 21:44:50 +0200
committerJakub Jirutka <jakub@jirutka.cz>2017-07-25 21:44:50 +0200
commita66abec72346d0bd50d0dad6c02c2fc8023e277a (patch)
treeda36dddf35be68bbac04ce9a3b161a59e96b4aa4 /bin/buildrepo.lua
parentb8151f36204607d1697701ad6174af2073ffa77c (diff)
downloadlua-aports-a66abec72346d0bd50d0dad6c02c2fc8023e277a.tar.bz2
lua-aports-a66abec72346d0bd50d0dad6c02c2fc8023e277a.tar.xz
move binfiles to bin/ directory
Diffstat (limited to 'bin/buildrepo.lua')
-rwxr-xr-xbin/buildrepo.lua259
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