mirror of
https://github.com/lilydjwg/archrepo2.git
synced 2025-03-10 12:02:43 +00:00
175 lines
4.6 KiB
Python
Executable file
175 lines
4.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import configparser
|
|
import subprocess
|
|
import logging
|
|
import shutil
|
|
import tarfile
|
|
|
|
from myutils import enable_pretty_logging
|
|
enable_pretty_logging(logging.DEBUG)
|
|
|
|
class Command:
|
|
def __init__(self, ctx, args):
|
|
self.args = args
|
|
self.ctx = ctx
|
|
self.run()
|
|
|
|
class WaitCommand(Command):
|
|
cmd = 'wait'
|
|
def run(self):
|
|
t = self.ctx['wait_time'] + 2
|
|
logging.info('waiting for %d seconds...', t)
|
|
time.sleep(t)
|
|
|
|
class RacingWaitCommand(Command):
|
|
cmd = 'racing-wait'
|
|
def run(self):
|
|
t = self.ctx['wait_time'] + 0.3
|
|
logging.info('Racing-waiting for %s seconds...', t)
|
|
time.sleep(t)
|
|
|
|
class BaseDirCommand(Command):
|
|
cmd = 'base_dir'
|
|
def run(self):
|
|
base_dir = self.args[0]
|
|
logging.info('base_dir set to %s.', base_dir)
|
|
self.ctx['base_dir'] = base_dir
|
|
|
|
class AddCommand(Command):
|
|
cmd = 'add'
|
|
def run(self):
|
|
arch, file = self.args
|
|
srcfile = os.path.join(self.ctx['base_dir'], file)
|
|
dstfile = os.path.join(self.ctx['repo_dir'], arch, file)
|
|
logging.info('adding file %s', file)
|
|
shutil.copyfile(srcfile, dstfile)
|
|
|
|
class RemoveCommand(Command):
|
|
cmd = 'remove'
|
|
def run(self):
|
|
arch, file = self.args
|
|
file = arch + '/' + file
|
|
dstfile = os.path.join(self.ctx['repo_dir'], file)
|
|
os.unlink(dstfile)
|
|
logging.info('removing file %s', file)
|
|
|
|
class CheckYCommand(Command):
|
|
cmd = 'checky'
|
|
def run(self):
|
|
f = os.path.join(self.ctx['repo_dir'], self.args[0])
|
|
r = os.path.isfile(f)
|
|
if not r:
|
|
logging.error('checky assertion failed: %s is not a file.', f)
|
|
|
|
class CheckNCommand(Command):
|
|
cmd = 'checkn'
|
|
def run(self):
|
|
f = os.path.join(self.ctx['repo_dir'], self.args[0])
|
|
r = os.path.exists(f)
|
|
if r:
|
|
logging.error('checkn assertion failed: %s exists.', f)
|
|
|
|
class CheckPCommand(Command):
|
|
cmd = 'checkp'
|
|
def run(self):
|
|
arch, what = self.args
|
|
dbfile = os.path.join(self.ctx['repo_dir'], arch, self.ctx['repo_name'] + '.db')
|
|
db = tarfile.open(dbfile)
|
|
name, ver = what.split('=', 1)
|
|
if ver == 'null':
|
|
pkg = [x for x in db.getnames() if '/' not in x and x.startswith(name+'-') and x[len(name)+1:].count('-') != 1]
|
|
if pkg:
|
|
logging.error('checkp assertion failed: package %s still exists in database: %r', name, pkg)
|
|
else:
|
|
try:
|
|
db.getmember('%s-%s' % (name, ver))
|
|
except KeyError:
|
|
logging.error('checkp assertion failed: package %s does not exist in database.', what)
|
|
db.close()
|
|
|
|
def build_command_map(cmdcls=Command, cmdmap={}):
|
|
for cls in cmdcls.__subclasses__():
|
|
cmdmap[cls.cmd] = cls
|
|
build_command_map(cls)
|
|
return cmdmap
|
|
|
|
def build_action_ctx(conf):
|
|
ctx = {}
|
|
ctx['repo_dir'] = conf.get('path')
|
|
ctx['repo_name'] = conf.get('name')
|
|
ctx['wait_time'] = conf.getint('wait-time', 10)
|
|
ctx['base_dir'] = ''
|
|
return ctx
|
|
|
|
def run_action_file(conf, actlines):
|
|
cmdmap = build_command_map()
|
|
ctx = build_action_ctx(conf)
|
|
for l in actlines:
|
|
l = l.rstrip()
|
|
if not l or l.startswith('#'):
|
|
continue
|
|
cmd, *args = l.split()
|
|
cmd = cmd.rstrip(':')
|
|
try:
|
|
cmdmap[cmd](ctx, args)
|
|
except KeyboardInterrupt:
|
|
logging.info('Interrupted.')
|
|
break
|
|
except:
|
|
logging.error('error running action: %s', l, exc_info=True)
|
|
logging.info('done running action file.')
|
|
|
|
class Server:
|
|
def __init__(self, conffile):
|
|
self.conffile = conffile
|
|
|
|
def start(self):
|
|
logging.info('starting server...')
|
|
self.p = subprocess.Popen(['archreposrv', self.conffile])
|
|
|
|
def stop(self):
|
|
logging.info('quitting server...')
|
|
p = self.p
|
|
p.send_signal(2)
|
|
ret = p.wait()
|
|
if ret == 0:
|
|
logging.info('server exited normally.')
|
|
else:
|
|
logging.error('server exited with error code %d.' % ret)
|
|
|
|
def main(conffile, actfile):
|
|
config = configparser.ConfigParser()
|
|
config.read(conffile)
|
|
|
|
dest_dir = config['repository'].get('path')
|
|
if os.path.isdir(dest_dir):
|
|
ans = input('Repository directory for testing exists. Removing? [y/N] ')
|
|
if ans not in 'Yy':
|
|
logging.warn('user cancelled.')
|
|
sys.exit(1)
|
|
else:
|
|
logging.info('removing already existing testing repo...')
|
|
shutil.rmtree(dest_dir)
|
|
os.mkdir(dest_dir)
|
|
for d in ('any', 'i686', 'x86_64'):
|
|
p = os.path.join(dest_dir, d)
|
|
os.mkdir(p)
|
|
|
|
server = Server(conffile)
|
|
server.start()
|
|
|
|
with open(actfile) as acts:
|
|
run_action_file(config['repository'], acts)
|
|
|
|
server.stop()
|
|
logging.info('removing testing repo...')
|
|
shutil.rmtree(dest_dir)
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) != 3:
|
|
sys.exit('usage: %s repo_config test_action' % os.path.split(sys.argv[0])[-1])
|
|
main(sys.argv[1], sys.argv[2])
|