Commit a1d46857 authored by Seblu's avatar Seblu
Browse files

Initial commit

parents
Loading
Loading
Loading
Loading

aurbot

0 → 100755
+242 −0
Original line number Diff line number Diff line
#!/usr/bin/env python
# Copyright Sébastien Luttringer <seblu@seblu.net>
# Started 30/10/2011

import os
import time
import json
import glob
import shutil
import argparse
import tempfile
import tarfile
import urllib.request
import configparser
import subprocess
import AUR

class Repositories(dict):
	'''
	Repository class abstract all stuff around repositories
	'''

	def init(self, repo):
		'''
		Init a repository
		'''
		print('Initialize %s' % repo)
		# create repository path
		if self[repo]['path'] is not None:
			os.makedirs(self[repo]['path'], exist_ok=True)
		# create chroot
		if self[repo]['chroot'] is not None:
			root = os.path.join(self[repo]['chroot'], 'root')
			if not os.path.exists(root):
				os.makedirs(self[repo]['chroot'], exist_ok=True)
				cmds = ['mkarchroot', '-n', root, 'base', 'base-devel', 'sudo']
				if self[repo]['arch'] == 'i686':
					cmds.insert(0, 'linux32')
				elif self[repo]['arch'] == 'x86_64':
					cmds.insert(0, 'linux64')
				if os.geteuid() != 0:
					cmds.insert(0, 'sudo')
				subprocess.check_call(cmds, close_fds=True)

	def load(self, conf_path, db_path):
		'''
		Load repositories configuration
		'''
		try:
			# read config
			cp = configparser.RawConfigParser()
			cp.read(conf_path)
			for sec in cp.sections():
				self[sec] = {
					'dbname': '%s.db.tar.gz' % sec,
					'arch': None,
					'path': None,
					'chroot': None,
					'build_command': None}
				self[sec].update(cp.items(sec))
				self[sec]['packages'] = cp.get(sec, 'packages', fallback='').split()
				# checks
				if self[sec]['arch'] not in ('x86_64', 'i686'):
					raise Exception('Invalid arch')
				if self[sec]['path'] is None:
					raise Exception('Invalid repository path')
		except Exception as e:
			print('Unable to load package database: %s' % e)
	
	def tobuild(self):
		'''
		 of packages to build
		'''
		for repo in self:
			for pkg in self[repo]['packages']:
				yield (repo, pkg)
	
	def add(self, repo, files=[]):
		'''
		Add pkg to repo
		'''
		dbpath = os.path.join(self[repo]['path'], self[repo]['dbname'])
		for f in files:
			dstpath = os.path.join(self[repo]['path'], os.path.basename(f))
			shutil.copy(f, dstpath)
			subprocess.check_call(['repo-add', dbpath, dstpath], close_fds=True)

class AURPackages(dict):
	'''
	Packages class handle package informations
	'''

	aur_url = 'https://aur.archlinux.org'
	aur_min_update_interval = 60

	def load(self, path):
		'''
		Load packages informations from a file
		'''
		if not os.path.exists(path):
			return
		try:
			self.update(json.load(open(path, "r")))
		except Exception as e:
			print('Unable to load package database: %s' % e)

	def save(self, path):
		'''
		Save packages informations to a file
		'''
		json.dump(self, open(path, 'w'))

	def register(self, pkg, update=False):
		if pkg not in self or update:
			self.aur_update(pkg)

	def aur_update(self, pkg):
		'''
		update information about a package
		'''
		if (pkg in self and
		    'aurbuilder_update' in self[pkg] and
		    self[pkg]['aurbuilder_update'] + self.aur_min_update_interval > time.time()):
			return
		info = AUR.aur_query('info', pkg)
		if info is not None:
			self[pkg] = info
			self[pkg]['aurbuilder_update'] = time.time()
		else:
			print('No package %s' % pkg)

	def extract(self, pkg, path):
		'''
		Extract aur source tarball inside a directory path
		'''
		# feed package db
		self.register(pkg, update=args.update)
		# get tarball
		fo = urllib.request.urlopen('%s/%s' % (self.aur_url, self[pkg]['URLPath']))
		# extract tarball
		tarball = tarfile.open(mode='r|*', fileobj=fo)
		tarball.extractall(path)

################
#Parser commands
################

def c_init(args):
	'''
	Init command
	'''
	for repo in args.repos:
		args.repos.init(repo)

def c_update(args):
	'''
	Update command
	'''
	args.aurpkg.update()

def c_build(args):
	'''
	Build command
	'''
	# /dev/null fd
	devnull = open('/dev/null', 'w')
	
	# start building
	for repo, pkg in repositories.tobuild():
		print('Building %s in %s' % (repo, pkg))
		# creating temp directory to extract tarball
		tempd = tempfile.TemporaryDirectory()
		# extract package inside tempdir
		aurpkg.extract(pkg, tempd.name)
		# compile
		try:
			builddir = os.path.join(tempd.name, pkg)
			os.chdir(builddir)
	#			subprocess.check_call(['makechrootpkg',
	#					       '-c', '-r', repositories[reponame]['chroot']])
			subprocess.check_call(['makepkg','-c'], close_fds=True, stdout=devnull, stderr=devnull)
			files = glob.glob(os.path.join(builddir, '*.pkg.tar.xz'))
			if len(files) == 0:
				raise Exception('Unable to find binary packages')
		except Exception as e:
			# FIXME: mark package as invalid to build
			print('build failure: %s' % e)
		finally:
			os.chdir(cwd)
		# add to repository
		try:
			repositories.add(repo, files)
		except Exception as e:
			print('repository modification failure: %s' % e)
		pass

# we start here
parser = argparse.ArgumentParser()
parser.add_argument('-r', '--repo-conf', default='repositories.conf', help='repository definitions')
parser.add_argument('-R', '--repo-db', default='repositories.json', help='repositories databases')
parser.add_argument('-p', '--aurpkg-db', default='packages.json', help='AUR packages database')
parser.add_argument('-q', '--quiet', action='store_true', default=False,
	help='Quiet mode')

sp = parser.add_subparsers()
p_init = sp.add_parser('init')
p_init.set_defaults(func=c_init)
p_update = sp.add_parser('update')
p_update.set_defaults(func=c_update)
p_build = sp.add_parser('build')
p_build.set_defaults(func=c_build)
#p_update.add_argument('-u', '--update', action='store_true', default=False,
#	help='Connect AUR to update packages db')

# parse args
args = parser.parse_args()

# path must be absolute!
args.repo_conf = os.path.abspath(args.repo_conf)
args.repo_db = os.path.abspath(args.repo_db)
args.aurpkg_db = os.path.abspath(args.aurpkg_db)

# store current directory
cwd = os.getcwd()

# load repo mananger
repos = Repositories()
repos.load(args.repo_conf, args.repo_db)

# load package manager
aurpkg = AURPackages()
aurpkg.load(args.aurpkg_db)

# add aurpkg and repos to args
args.aurpkg = aurpkg
args.repos = repos

# run command function
args.func(args)

# save aur packages db
aurpkg.save(args.aurpkg_db)

repositories.conf

0 → 100644
+20 −0
Original line number Diff line number Diff line
[seblu-aur-i686]
arch = i686
path=repo/i686
chroot=chroots/i686
packages =  atftp
 lantencytop
 rar
 rootcheck

[seblu-aur-x86_64]
dbname = seblu-aur.db.tar.gz
arch = x86_64
path=repo/amd64
chroot=chroots/amd64
build_command = makepkg -c
packages = 
 atftp
 latencytop
 rar
 rootcheck