#!/usr/local/bin/python
# $Id: buildport.py,v 1.5 2005/01/21 16:38:57 john Exp $
#
# JW.
#
# Given a port's magic string, install any dependencies which are already
# built either on an ftp server or in /usr/ports/packages.
# For all remaining packages which are not already installed, extract their
# port directory and invoke make install on the given port.
# Magic: category/name[/version][,-subpackage]{,flavour}*
# Taken from the second column in ports/INDEX.
import csv, re, sys, os
make_path = [
'/bin', '/sbin', '/usr/bin', '/usr/sbin', '/usr/local/bin',
'/usr/local/sbin'
]
http_proxy = os.environ.get('http_proxy')
ftp_proxy = os.environ.get('ftp_proxy')
ftpsite = 'ftp://xxxxxxxxxxxxxxxxxx/3.6CD1/3.6/packages/i386'
ftpdb = map(lambda entry: entry.split()[-1].strip(), \
file('/var/db/packages_3.6_i386').readlines())
portsdb = '/var/db/ports_3.6'
portsdb_cache = {}
packages_cache = {}
portsbuilt = '/usr/ports/packages/i386/all'
installed = os.listdir('/var/db/pkg')
portstar = '/home/john/openbsd/ports.tar.gz'
portsdir = '/usr/ports'
mopts = os.readlink('/etc/malloc.conf').lower()
def pkg_add(location):
os.spawnl(os.P_WAIT, "/usr/bin/sudo", "sudo", "/usr/sbin/pkg_add", location)
def make(dir, env=[], target='install'):
env.append("SUDO=sudo")
env.append("MALLOC_OPTIONS=" + mopts)
env.append("PATH=" + ':'.join(make_path))
if http_proxy:
env.append("http_proxy=" + http_proxy)
if ftp_proxy:
env.append("ftp_proxy=" + ftp_proxy)
args = [ 'env', '-i' ] + env + [ '/usr/bin/make', target ]
os.chdir(os.path.join(portsdir, dir))
#print os.getcwd(), '|'.join(args)
os.spawnv(os.P_WAIT, "/usr/bin/env", args)
def tar_extract(paths):
if not paths:
return
os.chdir(os.path.split(portsdir)[0])
args = [ 'tar', 'xzf', portstar ] + paths
os.spawnv(os.P_WAIT, "/bin/tar", args)
def Package(pkgident):
global packages_cache
if pkgident not in packages_cache:
packages_cache[pkgident] = _Package(pkgident)
return packages_cache[pkgident]
class _Package:
def __init__(self, pkgident):
self.pkgident = pkgident
self.pkg = findpkg(pkgident)
self.depends = depends(pkgident)
self.pkgdir, self.subpackage, self.flavors = decodepkgident(pkgident)
self.pkgtgz = self.pkg[0] + '.tgz'
self.isonftp = self.pkgtgz in ftpdb
self.isbuilt = os.path.exists(os.path.join(portsbuilt, self.pkgtgz))
self.isinstalled = self.pkg[0] in installed
def __repr__(self):
s = '<Package \"%s\"' % self.pkgident
if self.subpackage:
s += ' subpackage=%s' % self.subpackage
if self.flavors:
s += ' flavors=%s' % self.flavors
if self.depends:
s += ' depends=%d' % len(self.depends)
s += '>'
return s
def _createlistthrurecursion(self, fn, init, cond=True):
l = []
if cond:
l.append(init)
for d in self.depends:
_dirs = getattr(d, fn)()
for _d in _dirs:
if _d not in l:
l.append(_d)
return l
def gettgzs(self):
return self._createlistthrurecursion('gettgzs', self.pkgtgz)
def getdirs(self):
return self._createlistthrurecursion('getdirs', self.pkgdir)
def getbuilt(self):
return self._createlistthrurecursion('getbuilt', self.pkgtgz, self.isbuilt)
def getftp(self):
return self._createlistthrurecursion('getftp', self.pkgtgz, self.isonftp)
def getinstalled(self):
return self._createlistthrurecursion('getinstalled', self.pkgtgz, self.isinstalled)
def _finddepends(self):
inst = []
installed = self.getinstalled()
onftp = self.getftp()
built = self.getbuilt()
deps = self.gettgzs()
for i in installed:
if i in onftp:
onftp.remove(i)
if i in built:
built.remove(i)
for i in built:
if i in onftp:
onftp.remove(i)
for i in installed:
inst.append(( 'none', i ))
inst.append(( 'port', i ))
deps.remove(i)
for i in built:
inst.append(( 'built', i ))
inst.append(( 'port', i ))
deps.remove(i)
for i in onftp:
inst.append(( 'ftp', i ))
inst.append(( 'port', i ))
deps.remove(i)
for i in deps:
inst.append(( 'port', i ))
# Put ports first.
inst.reverse()
return inst
def preinstall(self):
recipe = self._finddepends()
for method, location in recipe:
globals()['install_' + method](location)
extract = []
for dir in extract_ports:
if not os.path.exists(os.path.join(portsdir, dir)):
print "Will extract `%s' from ports.tar.gz." % dir
extract.append('ports/' + dir)
tar_extract(extract)
def environment(self):
env = []
if self.subpackage:
env.append('SUBPACKAGE=%s' % self.subpackage)
if self.flavors:
env.append('FLAVOR=%s' % ' '.join(self.flavors))
return env
def build(self):
make(self.pkgdir, self.environment())
def install_none(pkg):
print "Package `%s' is already installed." % pkg
extract_ports = [ 'infrastructure' ]
def install_port(pkg):
global extract_ports
for p in packages_cache.itervalues():
if p.pkgtgz == pkg:
print "Package `%s' will be compiled from `%s'." % (pkg, p.pkgdir)
extract_ports.append(p.pkgdir)
return
raise StandardError("Couldn't find port for `%s'" % pkg)
def install_built(pkg):
print "Installing `%s' from /usr/ports/packages." % pkg
pkg_add(os.path.join(portsbuilt, pkg))
def install_ftp(pkg):
print "Installing `%s' from ftp site." % pkg
pkg_add(os.path.join(ftpsite, pkg))
def findpkg(pkgident):
global portsdb_cache
if pkgident in portsdb_cache:
return portsdb_cache[pkgident]
for pkg in csv.reader(file(portsdb), delimiter='|'):
if pkg[1] == pkgident:
portsdb_cache[pkgident] = pkg
return pkg
for pkg in csv.reader(file(portsdb), delimiter='|'):
if pkg[1].find(pkgident + ',') == 0:
portsdb_cache[pkgident] = pkg
return pkg
return None
def depends(pkgident):
depends = None
pkg = findpkg(pkgident)
if not pkg:
raise StandardError("Couldn't find package `%s'" % pkgident)
depends = []
for dlist in pkg[7:10]:
for dep in dlist.split():
p = Package(dep.split(':')[-1])
if p not in depends:
depends.append(p)
return depends
def decodepkgident(pkgident):
# category/name[/version][,-subpackage]{,flavour}*
options = pkgident.split(',')
pkgdir = options[0]
del(options[0])
subpackage = ''
if options and options[0][0] == '-':
subpackage = options[0]
del(options[0])
flavors = options
return ( pkgdir, subpackage, flavors )
def main():
target = 'install'
try:
me, pkgident, target = sys.argv
except:
try:
me, pkgident = sys.argv
except:
print >> sys.stderr, "Usage: %s PKGIDENT [TARGET]" % sys.argv[0]
sys.exit(1)
p = Package(pkgident)
if target == 'clean':
for pkg in packages_cache.itervalues():
if os.path.exists(os.path.join(portsdir, pkg.pkgdir)):
make(pkg.pkgdir, pkg.environment(), target='clean')
elif target == 'install':
p.preinstall()
p.build()
if __name__ == '__main__':
main()