class PkginfoParser(Parser): ''' The PKGINFO parser ''' #: Pattern matches 'key = val' PATTERN = compile_pattern('([a-z]+) = ([^\n]+)\n') #: Translations from PKGINFO to local-repo TRANS = {'pkgname': 'name', 'pkgver': 'version', 'pkgdesc': 'desc', 'size': 'isize', 'url': 'url', 'license': 'license', 'arch': 'arch', 'builddate': 'builddate', 'packager': 'packager'} def parse(self): ''' Parses a PKGINFO ''' info = dict(PkginfoParser.PATTERN.findall(self._data)) try: return {t: info[k] for k, t in PkginfoParser.TRANS.items()} except KeyError as e: raise ParserError(_('Missing PKGINFO entry: {0}').format(e))
class DescParser(Parser): ''' The database desc parser ''' #: Pattern matches '%key%\nval' PATTERN = compile_pattern('%([A-Z256]+)%\n([^\n]+)\n') #: List of mandatory fields MANDATORY = ['filename', 'name', 'version'] #: List of fields with informational character OPTIONAL = ['desc', 'csize', 'isize', 'md5sum', 'sha256sum', 'url', 'license', 'arch', 'builddate', 'packager'] #: List of fields of which we just want to know wether they are availble or not BOOL = ['pgpsig'] def parse(self): ''' Parses a desc file ''' info = {k.lower(): v for k, v in DescParser.PATTERN.findall(self._data)} missing = [field for field in DescParser.MANDATORY if field not in info] if missing: raise ParserError(_('Missing fields: {0}').format(', '.join(missing))) for opt in [o for o in DescParser.OPTIONAL if o not in info]: info[opt] = None for opt in DescParser.BOOL: info[opt] = bool(info[opt]) if opt in info else False return info
class PkgbuildParser(Parser): ''' The PKGBUILD parser ''' #: Path to bash BASH = '/bin/bash' #: Path to makepkg.conf MAKEPKG_CONF = '/etc/makepkg.conf' #: Pattern matches 'key=val' PATTERN = compile_pattern('([a-z]+)=([^\n]*)\n') #: Translations from PKGBUILD to local-repo TRANS = {'pkgname': 'name', 'pkgver': 'version', 'depends': list, 'makedepends': list} #: Bash command that prints needed info 'key=val' style ECHO = ' && '.join(('echo "{0}=${{{0}[@]}}"'.format(k) for k in TRANS)) def parse(self): ''' Parses a PKGBUILD - self._data must be the path to a PKGBUILD file''' cmd = 'source {0} && source {1} && {2}'.format(PkgbuildParser.MAKEPKG_CONF, self._data, PkgbuildParser.ECHO) try: data = check_output([PkgbuildParser.BASH, '-c', cmd]).decode('utf8') except: raise ParserError(_('Could not parse PKGBUILD: {0}').format(self._data)) data = dict(PkgbuildParser.PATTERN.findall(data)) info = {} for k, t in PkgbuildParser.TRANS.items(): if k not in data: raise ParserError(_('Could not parse PKGBUILD: {0}').format(self._data)) if t is list: info[k] = data[k].split() elif data[k] != '': info[t] = data[k] else: raise ParserError(_('Missing PKGBUILD entry: {0}').format(k)) return info
from Choice import create_Choice from Course import create_Course from Question import create_Question from Question import find_question_by_key from Quiz import create_Quiz from Quiz import find_quiz_by_key from re import compile as compile_pattern from Student import create_Student from Student import lookup_student from Teacher import create_Teacher group_positive_integer_pattern = r'([1-9][0-9]*)' choice_number_match = compile_pattern( r'^' + group_positive_integer_pattern # course number + '.' + group_positive_integer_pattern # question number + '.' + group_positive_integer_pattern # quiz number + r'([A-Z])' # choice letter + '\Z').match question_number_match = compile_pattern( r'^' + group_positive_integer_pattern # course number + '.' + group_positive_integer_pattern # question number + '.' + group_positive_integer_pattern # quiz number + '\Z').match # # create_choice_and_print # def create_choice_and_print(i, name, number, correct, choice_text): m = choice_number_match(number)
class Pacman: ''' A wrapper for program calls of the pacman package ''' #: Path to su SU = '/bin/su' #: Path to sudo SUDO = '/usr/bin/sudo' #: Path to pacman PACMAN = '/usr/bin/pacman' #: Path to makepkg MAKEPKG = '/usr/bin/makepkg' #: Path to repo-add REPO_ADD = '/usr/bin/repo-add' #: Path to repo-remove REPO_REMOVE = '/usr/bin/repo-remove' #: Path to repo-elephant REPO_ELEPHANT = '/usr/bin/repo-elephant' #: Split pattern, used to remove the version requirement from the package name VERSION_SEP = compile_pattern('<|>|=') @staticmethod def call(cmd): ''' Calls a command ''' if type(cmd) is str: cmd = [cmd] if call(cmd) is not 0: raise PacmanCallError(' '.join(cmd)) @staticmethod def _run_as_root(cmd): ''' Runs a command as root ''' if getuid() is not 0: if access(Pacman.SUDO, X_OK): cmd.insert(0, Pacman.SUDO) else: cmd = [Pacman.SU, '-c', '\'{0}\''.format(' '.join(cmd))] Pacman.call(cmd) @staticmethod def install(pkgs, as_deps=False): ''' Installs packages ''' cmd = [Pacman.PACMAN, '-Sy'] + pkgs if as_deps: cmd.append('--asdeps') Pacman._run_as_root(cmd) @staticmethod def uninstall(pkgs): ''' Unnstalls packages ''' for i, pkg in enumerate(pkgs): pkgs[i] = Pacman.VERSION_SEP.split(pkg)[0] Pacman._run_as_root([Pacman.PACMAN, '-Rs'] + list(set(pkgs))) @staticmethod def check_from_aur(pkgs): ''' Checks whether packages are from AUR ''' res = {} for pkg in pkgs: # Try to find `pkg` in official repositories cmd = [Pacman.PACMAN, '-Ssq', pkg] try: check_output(cmd) res[pkg] = False except CalledProcessError as e: res[pkg] = True return res @staticmethod def check_deps(pkgs): ''' Checks for unresolved dependencies ''' cmd = [Pacman.PACMAN, '-T'] + pkgs try: check_output(cmd) return [] except CalledProcessError as e: if e.returncode is 127: return e.output.decode('utf8').split() raise PacmanCallError(' '.join(cmd)) @staticmethod def make_package(path, force=False): ''' Calls makepkg ''' try: chdir(path) except: raise PacmanError( _('Could not change working directory: {0}').format(path)) cmd = [Pacman.MAKEPKG, '-d'] if force: cmd.append('-f') if Config.get('buildlog', False): cmd += ['-L', '-m'] if Config.get('sign', False): cmd.append('--sign') else: cmd.append('--nosign') Pacman.call(cmd) @staticmethod def _repo_script(script, db, pkgs): ''' Calls one of the repo- scripts ''' cmd = [script, db] + pkgs if Config.get('signdb', False): cmd += ['--verify', '--sign'] Pacman.call(cmd) @staticmethod def repo_add(db, pkgs): ''' Calls repo-add ''' Pacman._repo_script(Pacman.REPO_ADD, db, pkgs) @staticmethod def repo_remove(db, pkgs): ''' Calls repo-remove ''' Pacman._repo_script(Pacman.REPO_REMOVE, db, pkgs) @staticmethod def repo_elephant(): ''' The elephant never forgets ''' if call([Pacman.REPO_ELEPHANT]) is not 0: raise PacmanError(_('Ooh no! Somebody killed the repo elephant'))