From ce0e95607d04e95b0d07a11aacbaaa4dae26bfd7 Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Mon, 13 Dec 2010 14:14:06 +0000
Subject: ap: initial implementation

ap is a helper script to parse APKBUILD and calculate build time
dependencies.
---
 Makefile   |   9 +++-
 ap.in      | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 aports.lua | 105 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100755 ap.in
 create mode 100755 aports.lua

diff --git a/Makefile b/Makefile
index 1f8e11c..52d824d 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,11 @@ sysconfdir	?= /etc
 datadir		?= $(prefix)/share/$(PACKAGE)
 abuildrepo	?= ~/.cache/apks
 
+LUA_VERSION	= 5.1
+LUA_SHAREDIR	?= $(prefix)/share/lua/$(LUA_VERSION)/
+
 SCRIPTS		:= abuild devbuild buildrepo abuild-keygen \
-		abuild-sign newapkbuild abump
+		abuild-sign newapkbuild abump ap
 USR_BIN_FILES	:= $(SCRIPTS) abuild-tar
 SAMPLES		:= sample.APKBUILD sample.initd sample.confd \
 		sample.pre-install sample.post-install
@@ -65,7 +68,7 @@ help:
 	@echo "usage: make install [ DESTDIR=<path> ]"
 	@echo "       make dist"
 
-install: $(USR_BIN_FILES) $(SAMPLES) abuild.conf functions.sh
+install: $(USR_BIN_FILES) $(SAMPLES) abuild.conf functions.sh aports.lua
 	mkdir -p $(DESTDIR)/$(prefix)/bin $(DESTDIR)/$(sysconfdir) \
 		$(DESTDIR)/$(datadir)
 	for i in $(USR_BIN_FILES); do\
@@ -76,6 +79,8 @@ install: $(USR_BIN_FILES) $(SAMPLES) abuild.conf functions.sh
 	fi
 	cp $(SAMPLES) $(DESTDIR)/$(prefix)/share/abuild
 	cp functions.sh $(DESTDIR)/$(datadir)/
+	mkdir -p $(DESTDIR)$(LUA_SHAREDIR)
+	cp aports.lua $(DESTDIR)$(LUA_SHAREDIR)/
 
 dist:	$(P).tar.bz2
 
diff --git a/ap.in b/ap.in
new file mode 100755
index 0000000..64b7cf9
--- /dev/null
+++ b/ap.in
@@ -0,0 +1,147 @@
+#!/usr/bin/lua
+
+require("aports")
+
+-- subcommands -----------------------
+subcmd = {}
+subcmd.revdep = {
+	desc = "Print reverse dependencies",
+	usage = "PKG...",
+	run = function(opts)
+		local i
+		local apkdb, rev = aports.init_apkdb(repodirs)
+		for i = 2, #opts do
+			local pkg = opts[i]
+			local _,p
+			for _,p in ipairs(rev[pkg] or {}) do
+				print(p.pkgname) 
+			end
+		end
+	end
+}
+
+subcmd.list = {
+	desc = "Print all packages built from aports tree",
+	usage = "",
+	run = function()
+		local apkdb = aports.init_apkdb(repodirs)
+		local k,v
+		for k,v in pairs(apkdb) do
+			print(k)
+		end
+	end
+}
+
+subcmd.recursdeps = {
+	desc = "Recursively print all make dependencies for given packages",
+	usage = "PKG...",
+	run = function (opts)
+		local i
+		local visited = {}
+		local apkdb, rev = aports.init_apkdb(repodirs)
+		function recurs(pn)
+			if pn == nil or visited[pn] or apkdb[pn] == nil then
+				return
+			end
+			visited[pn] = true
+			local i,d, p
+			for i,p in ipairs(apkdb[pn]) do
+				local _, d
+				for _, d in ipairs(p.depends) do
+					recurs(d)
+				end
+				for _, d in ipairs(p.makedepends) do
+					recurs(d)
+				end
+			end
+			print(pn)
+		end
+		for i = 2, #opts do
+			recurs(opts[i])
+		end
+	end
+}
+
+subcmd.builddirs = {
+	desc = "Print the build dirs for given packages in build order",
+	usage = "PKG...",
+	run = function(opts)
+		local i, _
+		local visited = {}
+		local dir_visited = {}
+		local apkdb, rev = aports.init_apkdb(repodirs)
+		local to_print = {}
+		function recursdir(pn)
+			if pn == nil or visited[pn] or apkdb[pn] == nil then
+				return
+			end
+			visited[pn] = true
+			local i, p
+			for i,p in pairs(apkdb[pn]) do
+				if not dir_visited[p.dir] then
+					dir_visited[p.dir] = true
+					local _, d
+					for _, d in pairs(p.depends) do
+						recursdir(d)
+					end
+					for _, d in pairs(p.makedepends) do
+						recursdir(d)
+					end
+					if to_print[pn] then
+						print(p.dir)
+					end
+				end
+			end
+		end
+		for i = 2, #opts do
+			to_print[opts[i]] = true
+		end
+		for i = 2, #opts do
+			recursdir(opts[i])
+		end
+	end
+}
+
+
+function print_usage()
+	io.write("usage: ap SUBCOMMAND [options]\n\nSubcommands are:\n")
+	local k,v
+	for k in pairs(subcmd) do
+		print("  "..k)
+	end
+end
+
+-- those should be read from some config file
+repodirs = {} 
+
+
+-- parse args
+i = 1
+opts = {}
+help = false
+while i <= #arg do
+	if arg[i] == "-d" then
+		i = i + 1
+		repodirs[#repodirs + 1] = arg[i]
+	elseif arg[i] == "-h" then
+		help = true
+	else
+		opts[#opts + 1] = arg[i]
+	end
+	i = i + 1
+end
+
+cmd = opts[1]
+
+if cmd == nil then
+	print_usage()
+	-- usage
+	return
+end
+
+if subcmd[cmd] and type(subcmd[cmd].run) == "function" then
+	subcmd[cmd].run(opts)
+else
+	io.stderr:write(cmd..": invalid subcommand\n")
+end
+
diff --git a/aports.lua b/aports.lua
new file mode 100755
index 0000000..44691c8
--- /dev/null
+++ b/aports.lua
@@ -0,0 +1,105 @@
+module(..., package.seeall)
+
+function split(str)
+	local t = {}
+	local e
+	if (str == nil) then
+		return nil
+	end
+	for e in string.gmatch(str, "%S+") do
+		t[#t + 1] = string.gsub(e, ":.*", "")
+	end
+	return t
+end
+
+function split_apkbuild(line)
+	local r = {}
+	local dir,pkgname, pkgver, pkgrel, arch, depends, makedepends, subpackages, source = string.match(line, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)")
+	r.dir = dir
+	r.pkgname = pkgname
+	r.pkgver = pkgver
+	r.pkgrel = pkgrel
+	r.depends = split(depends)
+	r.makedepends = split(makedepends)
+	r.subpackages = split(subpackages)
+	r.source = split(source)
+	return r
+end
+
+-- parse the APKBUILDs and return an iterator
+function parse_apkbuilds(dirs)
+	local i,v, p
+	local str=""
+	if dirs == nil then
+		return nil
+	end
+	--expand repos
+	for i,v in ipairs(dirs) do
+		str = str..v.."/*/APKBUILD "
+	end	
+		
+	local p = io.popen([[ 
+		for i in ]]..str..[[; do
+			pkgname=
+			pkgver=
+			pkgrel=
+			arch=
+			depends=
+			makedepends=
+			subpackages=
+			source=
+			dir="${i%/APKBUILD}"
+			cd "$dir"
+			. ./APKBUILD
+			echo $dir\|$pkgname\|$pkgver\|$pkgrel\|$arch\|$depends\|$makedepends\|$subpackages\|$source
+		done
+	]])
+	return function()
+		local line = p:read("*line")
+		if line == nil then
+			p:close()
+			return nil
+		end
+		return split_apkbuild(line) 
+	end
+end
+
+
+function target_packages(pkgdb, pkgname)
+	local i,v
+	local t = {}
+	for i,v in ipairs(pkgdb[pkgname]) do
+		table.insert(t, pkgname.."-"..v.pkgver.."-r"..v.pkgrel..".apk")
+	end
+	return t
+end
+
+function init_apkdb(repodirs)
+	local pkgdb = {}
+	local revdeps = {}
+	local a
+	for a in parse_apkbuilds(repodirs) do
+	--	io.write(a.pkgname.." "..a.pkgver.."\t"..a.dir.."\n")
+		if pkgdb[a.pkgname] == nil then
+			pkgdb[a.pkgname] = {}
+		end
+		table.insert(pkgdb[a.pkgname], a)
+		-- add subpackages to package db
+		local k,v
+		for k,v in pairs(a.subpackages) do
+			if pkgdb[v] == nil then
+				pkgdb[v] = {}
+			end
+			table.insert(pkgdb[v], a)
+		end
+		-- add to reverse dependencies
+		for k,v in pairs(a.makedepends) do
+			if revdeps[v] == nil then
+				revdeps[v] = {}
+			end
+			table.insert(revdeps[v], a)
+		end
+	end
+	return pkgdb, revdeps
+end
+
-- 
cgit v1.2.3-70-g09d2