# -*- encoding: utf-8 -*-
# PKGBUILDer v4.3.2
# An AUR helper (and library) in Python 3.
# Copyright © 2011-2023, Chris Warrick.
# See /LICENSE for licensing information.
"""
PKGBUILDer Data Storage.
:Copyright: © 2011-2023, Chris Warrick.
:License: BSD (see /LICENSE).
"""
from . import _, __version__
import pkgbuilder
import pkgbuilder.ui
import sys
import os
import logging
import subprocess
import pycman
import pkg_resources
import configparser
__all__ = ('PBDS',)
[docs]class PBDS(object):
"""PKGBUILDer Data Storage."""
# For fancy-schmancy messages stolen from makepkg.
colors = {
'all_off': '\x1b[1;0m',
'bold': '\x1b[1;1m',
'blue': '\x1b[1;1m\x1b[1;34m',
'green': '\x1b[1;1m\x1b[1;32m',
'red': '\x1b[1;1m\x1b[1;31m',
'yellow': '\x1b[1;1m\x1b[1;33m'
}
pacman = False
fetch = False
validation = True
depcheck = True
pkginst = True
clean = False
pgpcheck = True
confirm = True
deepclone = False
depcheck = True
vcsupgrade = False
colors_status = True
# TRANSLATORS: see makepkg.
inttext = _('Aborted by user! Exiting...')
# TRANSLATORS: see pacman.
wrapperinttext = _('Interrupt signal received\n')
edit_pkgbuild = False
# STUFF NOT TO BE CHANGED BY HUMAN BEINGS. EVER.
mp1 = '=='
mp2 = ' '
debug = False
console = None
_pyc = None
hassudo = os.path.exists('/usr/bin/sudo')
uid = os.geteuid()
# Creating the configuration/log stuff...
confhome = os.getenv('XDG_CONFIG_HOME')
if confhome is None:
confhome = os.path.expanduser('~/.config/')
kwdir = os.path.join(confhome, 'kwpolska')
confdir = os.path.join(kwdir, 'pkgbuilder')
confpath = os.path.join(confdir, 'pkgbuilder.ini')
if not os.path.exists(confhome):
os.mkdir(confhome)
if not os.path.exists(kwdir):
os.mkdir(kwdir)
if not os.path.exists(confdir):
os.mkdir(confdir)
if not os.path.exists(confpath):
with open(confpath, 'wb') as fh:
fh.write(pkg_resources.resource_string(
'pkgbuilder', 'data/pkgbuilder.ini.skel'))
# Configuration file support
config = configparser.ConfigParser()
config.read_string(pkg_resources.resource_string(
'pkgbuilder', 'data/pkgbuilder.ini.skel').decode('utf-8'))
config.read([confpath], encoding='utf-8')
if os.getenv('PACMAN') is None:
paccommand = config.get('extras', 'paccommand', fallback='pacman')
else:
paccommand = os.getenv('PACMAN')
# Language changing
language = config.get('PKGBUILDer', 'language')
if language != 'auto':
pkgbuilder.T = pkgbuilder.gettext.translation(
'pkgbuilder', '/usr/share/locale', languages=[language],
fallback='C')
pkgbuilder.G = pkgbuilder.T.gettext
logging.basicConfig(format='%(asctime)-15s [%(levelname)-7s] '
':%(name)-10s: %(message)s',
filename=os.path.join(confdir, 'pkgbuilder.log'),
level=logging.DEBUG)
log = logging.getLogger('pkgbuilder')
log.info('*** PKGBUILDer v' + __version__)
[docs] def get_setting(self, name, config_section, config_option,
positive, negative):
"""Get the value of a setting, based on config file and arguments.
:param str name: name of setting, used for error on conflict
:param bool config_section: configuration file section
:param bool config_option: configuration file option
:param bool positive: positive argument
:param bool negative: negative argument
:return: the value requested by the user, defaults to config
:rtype: bool
"""
config = s = self.config.getboolean(config_section, config_option)
if positive:
s = True
elif negative:
s = False
if positive and negative:
print(
_("warning: conflicting values for setting {0}, "
"using {1}").format(name, config))
s = config
return s
def _pycreload(self):
"""Reload pycman, without UI fanciness."""
self._pyc = pycman.config.init_with_config('/etc/pacman.conf')
[docs] def pycreload(self):
"""Reload pycman."""
msg = _('Initializing pacman access...')
with pkgbuilder.ui.Throbber(msg, printback=False):
self._pyc = pycman.config.init_with_config('/etc/pacman.conf')
sys.stdout.write('\r' + ((len(msg) + 4) * ' ') + '\r')
@property
def pyc(self):
"""Return a pycman handle, initializing one if necessary."""
if not self._pyc:
self.pycreload()
return self._pyc
[docs] def run_command(self, args, prepend=None, asonearg=False):
"""
Run a command.
.. note:: Accepts only one command. ``shell=False``, for safety.
asonearg is for ``su -c`` and most people don’t need nor want
it.
.. note:: since version 2.1.6.2, ``args`` must be a list.
"""
if prepend is None:
prepend = []
if asonearg:
return subprocess.call(prepend + [' '.join(args)])
else:
return subprocess.call(prepend + args)
[docs] def sudo(self, args):
"""
Run as root.
Uses ``sudo`` if present, ``su -c`` otherwise, nothing if already
running as root.
.. note:: Accepts only one command. `shell=False`, for safety.
"""
if self.uid != 0:
if self.hassudo:
return self.run_command(args, prepend=['sudo'])
else:
return self.run_command(args, prepend=['su', '-c'],
asonearg=True)
else:
return self.run_command(args)
[docs] def root_crash(self):
"""Crash if running as root."""
if self.uid == 0:
self.log.error('running as root, crashing')
self.fancy_error(_('Running as root is not allowed as it can '
'cause catastrophic damage to your system!'))
self.fancy_error(_('Please restart PKGBUILDer as a regular user.'))
sys.exit(255)
[docs] def debugmode(self, nochange=False):
"""Print all the logged messages to stderr."""
if not self.debug:
self.console = logging.StreamHandler()
self.console.setLevel(logging.DEBUG)
self.console.setFormatter(logging.Formatter('[%(levelname)-7s] '
':%(name)-10s: %(message)s'))
logging.getLogger('').addHandler(self.console)
self.debug = True
self.mp1 = self.mp2 = 'pb'
elif self.debug and nochange:
pass
else:
logging.getLogger('').removeHandler(self.console)
self.debug = False
self.mp1 = '=='
self.mp2 = ' '
[docs] def colorson(self):
"""Enable colors."""
self.colors = {
'all_off': '\x1b[1;0m',
'bold': '\x1b[1;1m',
'blue': '\x1b[1;1m\x1b[1;34m',
'green': '\x1b[1;1m\x1b[1;32m',
'red': '\x1b[1;1m\x1b[1;31m',
'yellow': '\x1b[1;1m\x1b[1;33m'
}
[docs] def colorsoff(self):
"""Disable colors."""
self.colors = {
'all_off': '',
'bold': '',
'blue': '',
'green': '',
'red': '',
'yellow': ''
}
[docs] def fancy_msg(self, text):
"""Display main messages."""
sys.stderr.write(self.colors['green'] + self.mp1 + '>' +
self.colors['all_off'] +
self.colors['bold'] + ' ' + text +
self.colors['all_off'] + '\n')
self.log.info('({0:<20}) {1}'.format('fancy_msg', text))
[docs] def fancy_msg_prompt(self, text):
"""Display main messages that ask a question."""
sys.stderr.write(self.colors['green'] + self.mp1 + '>' +
self.colors['all_off'] +
self.colors['bold'] + ' ' + text +
self.colors['all_off'])
sys.stderr.flush()
self.log.info('({0:<20}) {1} \n'.format('fancy_msg', text))
return input()
[docs] def fancy_msg2(self, text):
"""Display sub-messages."""
sys.stderr.write(self.colors['blue'] + self.mp2 + '->' +
self.colors['all_off'] +
self.colors['bold'] + ' ' + text +
self.colors['all_off'] + '\n')
self.log.info('({0:<20}) {1}'.format('fancy_msg2', text))
[docs] def fancy_warning(self, text):
"""Display warning messages."""
sys.stderr.write(self.colors['yellow'] + self.mp1 + '> ' +
_('WARNING:') + self.colors['all_off'] +
self.colors['bold'] + ' ' + text +
self.colors['all_off'] + '\n')
self.log.warning('({0:<20}) {1}'.format('fancy_warning', text))
[docs] def fancy_warning2(self, text):
"""Display warning sub-messages."""
sys.stderr.write(self.colors['yellow'] + self.mp2 + '->' +
self.colors['all_off'] + self.colors['bold'] + ' ' +
text + self.colors['all_off'] + '\n')
self.log.warning('({0:<20}) {1}'.format('fancy_warning2', text))
[docs] def fancy_error(self, text):
"""Display error messages."""
sys.stderr.write(self.colors['red'] + self.mp1 + '> ' + _('ERROR:') +
self.colors['all_off'] + self.colors['bold'] + ' ' +
text + self.colors['all_off'] + '\n')
self.log.error('({0:<20}) {1}'.format('fancy_error', text))
[docs] def fancy_error2(self, text):
"""Display error sub-messages."""
sys.stderr.write(self.colors['red'] + self.mp2 + '->' +
self.colors['all_off'] + self.colors['bold'] + ' ' +
text + self.colors['all_off'] + '\n')
self.log.error('({0:<20}) {1}'.format('fancy_error2', text))