Blame dnf/yum/misc.py

Packit Service 21c75c
# misc.py
Packit Service 21c75c
# Copyright (C) 2012-2016 Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
# This copyrighted material is made available to anyone wishing to use,
Packit Service 21c75c
# modify, copy, or redistribute it subject to the terms and conditions of
Packit Service 21c75c
# the GNU General Public License v.2, or (at your option) any later version.
Packit Service 21c75c
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit Service 21c75c
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit Service 21c75c
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit Service 21c75c
# Public License for more details.  You should have received a copy of the
Packit Service 21c75c
# GNU General Public License along with this program; if not, write to the
Packit Service 21c75c
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 21c75c
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit Service 21c75c
# source code or documentation are not subject to the GNU General Public
Packit Service 21c75c
# License and may only be used or replicated with the express permission of
Packit Service 21c75c
# Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
Packit Service 21c75c
"""
Packit Service 21c75c
Assorted utility functions for yum.
Packit Service 21c75c
"""
Packit Service 21c75c
Packit Service 21c75c
from __future__ import print_function, absolute_import
Packit Service 21c75c
from __future__ import unicode_literals
Packit Service 21c75c
from dnf.exceptions import MiscError
Packit Service 21c75c
from dnf.pycomp import base64_decodebytes, basestring, unicode
Packit Service 21c75c
from stat import *
Packit Service 21c75c
import libdnf.utils
Packit Service 21c75c
import dnf.const
Packit Service 21c75c
import dnf.crypto
Packit Service 21c75c
import dnf.exceptions
Packit Service 21c75c
import dnf.i18n
Packit Service 21c75c
import errno
Packit Service 21c75c
import glob
Packit Service 21c75c
import hashlib
Packit Service 21c75c
import io
Packit Service 21c75c
import os
Packit Service 21c75c
import os.path
Packit Service 21c75c
import pwd
Packit Service 21c75c
import re
Packit Service 21c75c
import shutil
Packit Service 21c75c
import tempfile
Packit Service 21c75c
Packit Service 21c75c
_available_checksums = set(['md5', 'sha1', 'sha256', 'sha384', 'sha512'])
Packit Service 21c75c
_default_checksums = ['sha256']
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
_re_compiled_glob_match = None
Packit Service 21c75c
def re_glob(s):
Packit Service 21c75c
    """ Tests if a string is a shell wildcard. """
Packit Service 21c75c
    global _re_compiled_glob_match
Packit Service 21c75c
    if _re_compiled_glob_match is None:
Packit Service 21c75c
        _re_compiled_glob_match = re.compile(r'[*?]|\[.+\]').search
Packit Service 21c75c
    return _re_compiled_glob_match(s)
Packit Service 21c75c
Packit Service 21c75c
_re_compiled_full_match = None
Packit Service 21c75c
def re_full_search_needed(s):
Packit Service 21c75c
    """ Tests if a string needs a full nevra match, instead of just name. """
Packit Service 21c75c
    global _re_compiled_full_match
Packit Service 21c75c
    if _re_compiled_full_match is None:
Packit Service 21c75c
        # A glob, or a "." or "-" separator, followed by something (the ".")
Packit Service 21c75c
        one = re.compile(r'.*([-.*?]|\[.+\]).').match
Packit Service 21c75c
        # Any epoch, for envra
Packit Service 21c75c
        two = re.compile('[0-9]+:').match
Packit Service 21c75c
        _re_compiled_full_match = (one, two)
Packit Service 21c75c
    for rec in _re_compiled_full_match:
Packit Service 21c75c
        if rec(s):
Packit Service 21c75c
            return True
Packit Service 21c75c
    return False
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class Checksums(object):
Packit Service 21c75c
    """ Generate checksum(s), on given pieces of data. Producing the
Packit Service 21c75c
        Length and the result(s) when complete. """
Packit Service 21c75c
Packit Service 21c75c
    def __init__(self, checksums=None, ignore_missing=False, ignore_none=False):
Packit Service 21c75c
        if checksums is None:
Packit Service 21c75c
            checksums = _default_checksums
Packit Service 21c75c
        self._sumalgos = []
Packit Service 21c75c
        self._sumtypes = []
Packit Service 21c75c
        self._len = 0
Packit Service 21c75c
Packit Service 21c75c
        done = set()
Packit Service 21c75c
        for sumtype in checksums:
Packit Service 21c75c
            if sumtype == 'sha':
Packit Service 21c75c
                sumtype = 'sha1'
Packit Service 21c75c
            if sumtype in done:
Packit Service 21c75c
                continue
Packit Service 21c75c
Packit Service 21c75c
            if sumtype in _available_checksums:
Packit Service 21c75c
                sumalgo = hashlib.new(sumtype)
Packit Service 21c75c
            elif ignore_missing:
Packit Service 21c75c
                continue
Packit Service 21c75c
            else:
Packit Service 21c75c
                raise MiscError('Error Checksumming, bad checksum type %s' %
Packit Service 21c75c
                                sumtype)
Packit Service 21c75c
            done.add(sumtype)
Packit Service 21c75c
            self._sumtypes.append(sumtype)
Packit Service 21c75c
            self._sumalgos.append(sumalgo)
Packit Service 21c75c
        if not done and not ignore_none:
Packit Service 21c75c
            raise MiscError('Error Checksumming, no valid checksum type')
Packit Service 21c75c
Packit Service 21c75c
    def __len__(self):
Packit Service 21c75c
        return self._len
Packit Service 21c75c
Packit Service 21c75c
    # Note that len(x) is assert limited to INT_MAX, which is 2GB on i686.
Packit Service 21c75c
    length = property(fget=lambda self: self._len)
Packit Service 21c75c
Packit Service 21c75c
    def update(self, data):
Packit Service 21c75c
        self._len += len(data)
Packit Service 21c75c
        for sumalgo in self._sumalgos:
Packit Service 21c75c
            data = data.encode('utf-8') if isinstance(data, unicode) else data
Packit Service 21c75c
            sumalgo.update(data)
Packit Service 21c75c
Packit Service 21c75c
    def read(self, fo, size=2**16):
Packit Service 21c75c
        data = fo.read(size)
Packit Service 21c75c
        self.update(data)
Packit Service 21c75c
        return data
Packit Service 21c75c
Packit Service 21c75c
    def hexdigests(self):
Packit Service 21c75c
        ret = {}
Packit Service 21c75c
        for sumtype, sumdata in zip(self._sumtypes, self._sumalgos):
Packit Service 21c75c
            ret[sumtype] = sumdata.hexdigest()
Packit Service 21c75c
        return ret
Packit Service 21c75c
Packit Service 21c75c
    def hexdigest(self, checksum=None):
Packit Service 21c75c
        if checksum is None:
Packit Service 21c75c
            if not self._sumtypes:
Packit Service 21c75c
                return None
Packit Service 21c75c
            checksum = self._sumtypes[0]
Packit Service 21c75c
        if checksum == 'sha':
Packit Service 21c75c
            checksum = 'sha1'
Packit Service 21c75c
        return self.hexdigests()[checksum]
Packit Service 21c75c
Packit Service 21c75c
    def digests(self):
Packit Service 21c75c
        ret = {}
Packit Service 21c75c
        for sumtype, sumdata in zip(self._sumtypes, self._sumalgos):
Packit Service 21c75c
            ret[sumtype] = sumdata.digest()
Packit Service 21c75c
        return ret
Packit Service 21c75c
Packit Service 21c75c
    def digest(self, checksum=None):
Packit Service 21c75c
        if checksum is None:
Packit Service 21c75c
            if not self._sumtypes:
Packit Service 21c75c
                return None
Packit Service 21c75c
            checksum = self._sumtypes[0]
Packit Service 21c75c
        if checksum == 'sha':
Packit Service 21c75c
            checksum = 'sha1'
Packit Service 21c75c
        return self.digests()[checksum]
Packit Service 21c75c
Packit Service 21c75c
def get_default_chksum_type():
Packit Service 21c75c
    return _default_checksums[0]
Packit Service 21c75c
Packit Service 21c75c
def checksum(sumtype, file, CHUNK=2**16, datasize=None):
Packit Service 21c75c
    """takes filename, hand back Checksum of it
Packit Service 21c75c
       sumtype = md5 or sha/sha1/sha256/sha512 (note sha == sha1)
Packit Service 21c75c
       filename = /path/to/file
Packit Service 21c75c
       CHUNK=65536 by default"""
Packit Service 21c75c
Packit Service 21c75c
    # chunking brazenly lifted from Ryan Tomayko
Packit Service 21c75c
Packit Service 21c75c
    if isinstance(file, basestring):
Packit Service 21c75c
        try:
Packit Service 21c75c
            with open(file, 'rb', CHUNK) as fo:
Packit Service 21c75c
                return checksum(sumtype, fo, CHUNK, datasize)
Packit Service 21c75c
        except (IOError, OSError):
Packit Service 21c75c
            raise MiscError('Error opening file for checksum: %s' % file)
Packit Service 21c75c
Packit Service 21c75c
    try:
Packit Service 21c75c
        # assumes file is a file-like-object
Packit Service 21c75c
        data = Checksums([sumtype])
Packit Service 21c75c
        while data.read(file, CHUNK):
Packit Service 21c75c
            if datasize is not None and data.length > datasize:
Packit Service 21c75c
                break
Packit Service 21c75c
Packit Service 21c75c
        # This screws up the length, but that shouldn't matter. We only care
Packit Service 21c75c
        # if this checksum == what we expect.
Packit Service 21c75c
        if datasize is not None and datasize != data.length:
Packit Service 21c75c
            return '!%u!%s' % (datasize, data.hexdigest(sumtype))
Packit Service 21c75c
Packit Service 21c75c
        return data.hexdigest(sumtype)
Packit Service 21c75c
    except (IOError, OSError) as e:
Packit Service 21c75c
        raise MiscError('Error reading file for checksum: %s' % file)
Packit Service 21c75c
Packit Service 21c75c
class GenericHolder(object):
Packit Service 21c75c
    """Generic Holder class used to hold other objects of known types
Packit Service 21c75c
       It exists purely to be able to do object.somestuff, object.someotherstuff
Packit Service 21c75c
       or object[key] and pass object to another function that will
Packit Service 21c75c
       understand it"""
Packit Service 21c75c
Packit Service 21c75c
    def __init__(self, iter=None):
Packit Service 21c75c
        self.__iter = iter
Packit Service 21c75c
Packit Service 21c75c
    def __iter__(self):
Packit Service 21c75c
        if self.__iter is not None:
Packit Service 21c75c
            return iter(self[self.__iter])
Packit Service 21c75c
Packit Service 21c75c
    def __getitem__(self, item):
Packit Service 21c75c
        if hasattr(self, item):
Packit Service 21c75c
            return getattr(self, item)
Packit Service 21c75c
        else:
Packit Service 21c75c
            raise KeyError(item)
Packit Service 21c75c
Packit Service 21c75c
    def all_lists(self):
Packit Service 21c75c
        """Return a dictionary of all lists."""
Packit Service 21c75c
        return {key: list_ for key, list_ in vars(self).items()
Packit Service 21c75c
                if type(list_) is list}
Packit Service 21c75c
Packit Service 21c75c
    def merge_lists(self, other):
Packit Service 21c75c
        """ Concatenate the list attributes from 'other' to ours. """
Packit Service 21c75c
        for (key, val) in other.all_lists().items():
Packit Service 21c75c
            vars(self).setdefault(key, []).extend(val)
Packit Service 21c75c
        return self
Packit Service 21c75c
Packit Service 21c75c
def procgpgkey(rawkey):
Packit Service 21c75c
    '''Convert ASCII-armored GPG key to binary
Packit Service 21c75c
    '''
Packit Service 21c75c
Packit Service 21c75c
    # Normalise newlines
Packit Service 21c75c
    rawkey = re.sub(b'\r\n?', b'\n', rawkey)
Packit Service 21c75c
Packit Service 21c75c
    # Extract block
Packit Service 21c75c
    block = io.BytesIO()
Packit Service 21c75c
    inblock = 0
Packit Service 21c75c
    pastheaders = 0
Packit Service 21c75c
    for line in rawkey.split(b'\n'):
Packit Service 21c75c
        if line.startswith(b'-----BEGIN PGP PUBLIC KEY BLOCK-----'):
Packit Service 21c75c
            inblock = 1
Packit Service 21c75c
        elif inblock and line.strip() == b'':
Packit Service 21c75c
            pastheaders = 1
Packit Service 21c75c
        elif inblock and line.startswith(b'-----END PGP PUBLIC KEY BLOCK-----'):
Packit Service 21c75c
            # Hit the end of the block, get out
Packit Service 21c75c
            break
Packit Service 21c75c
        elif pastheaders and line.startswith(b'='):
Packit Service 21c75c
            # Hit the CRC line, don't include this and stop
Packit Service 21c75c
            break
Packit Service 21c75c
        elif pastheaders:
Packit Service 21c75c
            block.write(line + b'\n')
Packit Service 21c75c
Packit Service 21c75c
    # Decode and return
Packit Service 21c75c
    return base64_decodebytes(block.getvalue())
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def keyInstalled(ts, keyid, timestamp):
Packit Service 21c75c
    '''
Packit Service 21c75c
    Return if the GPG key described by the given keyid and timestamp are
Packit Service 21c75c
    installed in the rpmdb.
Packit Service 21c75c
Packit Service 21c75c
    The keyid and timestamp should both be passed as integers.
Packit Service 21c75c
    The ts is an rpm transaction set object
Packit Service 21c75c
Packit Service 21c75c
    Return values:
Packit Service 21c75c
        - -1      key is not installed
Packit Service 21c75c
        - 0       key with matching ID and timestamp is installed
Packit Service 21c75c
        - 1       key with matching ID is installed but has an older timestamp
Packit Service 21c75c
        - 2       key with matching ID is installed but has a newer timestamp
Packit Service 21c75c
Packit Service 21c75c
    No effort is made to handle duplicates. The first matching keyid is used to
Packit Service 21c75c
    calculate the return result.
Packit Service 21c75c
    '''
Packit Service 21c75c
    # Search
Packit Service 21c75c
    for hdr in ts.dbMatch('name', 'gpg-pubkey'):
Packit Service 21c75c
        if hdr['version'] == keyid:
Packit Service 21c75c
            installedts = int(hdr['release'], 16)
Packit Service 21c75c
            if installedts == timestamp:
Packit Service 21c75c
                return 0
Packit Service 21c75c
            elif installedts < timestamp:
Packit Service 21c75c
                return 1
Packit Service 21c75c
            else:
Packit Service 21c75c
                return 2
Packit Service 21c75c
Packit Service 21c75c
    return -1
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def import_key_to_pubring(rawkey, keyid, gpgdir=None, make_ro_copy=True):
Packit Service 21c75c
    if not os.path.exists(gpgdir):
Packit Service 21c75c
        os.makedirs(gpgdir)
Packit Service 21c75c
Packit Service 21c75c
    with dnf.crypto.pubring_dir(gpgdir), dnf.crypto.Context() as ctx:
Packit Service 21c75c
        # import the key
Packit Service 21c75c
        with open(os.path.join(gpgdir, 'gpg.conf'), 'wb') as fp:
Packit Service 21c75c
            fp.write(b'')
Packit Service 21c75c
        ctx.op_import(rawkey)
Packit Service 21c75c
Packit Service 21c75c
        if make_ro_copy:
Packit Service 21c75c
Packit Service 21c75c
            rodir = gpgdir + '-ro'
Packit Service 21c75c
            if not os.path.exists(rodir):
Packit Service 21c75c
                os.makedirs(rodir, mode=0o755)
Packit Service 21c75c
                for f in glob.glob(gpgdir + '/*'):
Packit Service 21c75c
                    basename = os.path.basename(f)
Packit Service 21c75c
                    ro_f = rodir + '/' + basename
Packit Service 21c75c
                    shutil.copy(f, ro_f)
Packit Service 21c75c
                    os.chmod(ro_f, 0o755)
Packit Service 21c75c
                # yes it is this stupid, why do you ask?
Packit Service 21c75c
                opts = """lock-never
Packit Service 21c75c
    no-auto-check-trustdb
Packit Service 21c75c
    trust-model direct
Packit Service 21c75c
    no-expensive-trust-checks
Packit Service 21c75c
    no-permission-warning
Packit Service 21c75c
    preserve-permissions
Packit Service 21c75c
    """
Packit Service 21c75c
                with open(os.path.join(rodir, 'gpg.conf'), 'w', 0o755) as fp:
Packit Service 21c75c
                    fp.write(opts)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
        return True
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def getCacheDir():
Packit Service 21c75c
    """return a path to a valid and safe cachedir - only used when not running
Packit Service 21c75c
       as root or when --tempcache is set"""
Packit Service 21c75c
Packit Service 21c75c
    uid = os.geteuid()
Packit Service 21c75c
    try:
Packit Service 21c75c
        usertup = pwd.getpwuid(uid)
Packit Service 21c75c
        username = dnf.i18n.ucd(usertup[0])
Packit Service 21c75c
        prefix = '%s-%s-' % (dnf.const.PREFIX, username)
Packit Service 21c75c
    except KeyError:
Packit Service 21c75c
        prefix = '%s-%s-' % (dnf.const.PREFIX, uid)
Packit Service 21c75c
Packit Service 21c75c
    # check for /var/tmp/prefix-* -
Packit Service 21c75c
    dirpath = '%s/%s*' % (dnf.const.TMPDIR, prefix)
Packit Service 21c75c
    cachedirs = sorted(glob.glob(dirpath))
Packit Service 21c75c
    for thisdir in cachedirs:
Packit Service 21c75c
        stats = os.lstat(thisdir)
Packit Service 21c75c
        if S_ISDIR(stats[0]) and S_IMODE(stats[0]) == 448 and stats[4] == uid:
Packit Service 21c75c
            return thisdir
Packit Service 21c75c
Packit Service 21c75c
    # make the dir (tempfile.mkdtemp())
Packit Service 21c75c
    cachedir = tempfile.mkdtemp(prefix=prefix, dir=dnf.const.TMPDIR)
Packit Service 21c75c
    return cachedir
Packit Service 21c75c
Packit Service 21c75c
def seq_max_split(seq, max_entries):
Packit Service 21c75c
    """ Given a seq, split into a list of lists of length max_entries each. """
Packit Service 21c75c
    ret = []
Packit Service 21c75c
    num = len(seq)
Packit Service 21c75c
    seq = list(seq) # Trying to use a set/etc. here is bad
Packit Service 21c75c
    beg = 0
Packit Service 21c75c
    while num > max_entries:
Packit Service 21c75c
        end = beg + max_entries
Packit Service 21c75c
        ret.append(seq[beg:end])
Packit Service 21c75c
        beg += max_entries
Packit Service 21c75c
        num -= max_entries
Packit Service 21c75c
    ret.append(seq[beg:])
Packit Service 21c75c
    return ret
Packit Service 21c75c
Packit Service 21c75c
def unlink_f(filename):
Packit Service 21c75c
    """ Call os.unlink, but don't die if the file isn't there. This is the main
Packit Service 21c75c
        difference between "rm -f" and plain "rm". """
Packit Service 21c75c
    try:
Packit Service 21c75c
        os.unlink(filename)
Packit Service 21c75c
    except OSError as e:
Packit Service 21c75c
        if e.errno != errno.ENOENT:
Packit Service 21c75c
            raise
Packit Service 21c75c
Packit Service 21c75c
def stat_f(filename, ignore_EACCES=False):
Packit Service 21c75c
    """ Call os.stat(), but don't die if the file isn't there. Returns None. """
Packit Service 21c75c
    try:
Packit Service 21c75c
        return os.stat(filename)
Packit Service 21c75c
    except OSError as e:
Packit Service 21c75c
        if e.errno in (errno.ENOENT, errno.ENOTDIR):
Packit Service 21c75c
            return None
Packit Service 21c75c
        if ignore_EACCES and e.errno == errno.EACCES:
Packit Service 21c75c
            return None
Packit Service 21c75c
        raise
Packit Service 21c75c
Packit Service 21c75c
def _getloginuid():
Packit Service 21c75c
    """ Get the audit-uid/login-uid, if available. os.getuid() is returned
Packit Service 21c75c
        instead if there was a problem. Note that no caching is done here. """
Packit Service 21c75c
    #  We might normally call audit.audit_getloginuid(), except that requires
Packit Service 21c75c
    # importing all of the audit module. And it doesn't work anyway: BZ 518721
Packit Service 21c75c
    try:
Packit Service 21c75c
        with open("/proc/self/loginuid") as fo:
Packit Service 21c75c
            data = fo.read()
Packit Service 21c75c
            return int(data)
Packit Service 21c75c
    except (IOError, ValueError):
Packit Service 21c75c
        return os.getuid()
Packit Service 21c75c
Packit Service 21c75c
_cached_getloginuid = None
Packit Service 21c75c
def getloginuid():
Packit Service 21c75c
    """ Get the audit-uid/login-uid, if available. os.getuid() is returned
Packit Service 21c75c
        instead if there was a problem. The value is cached, so you don't
Packit Service 21c75c
        have to save it. """
Packit Service 21c75c
    global _cached_getloginuid
Packit Service 21c75c
    if _cached_getloginuid is None:
Packit Service 21c75c
        _cached_getloginuid = _getloginuid()
Packit Service 21c75c
    return _cached_getloginuid
Packit Service 21c75c
Packit Service 21c75c
Packit Service 8e7813
def decompress(filename, dest=None, check_timestamps=False):
Packit Service 8e7813
    """take a filename and decompress it into the same relative location.
Packit Service 8e7813
       When the compression type is not recognized (or file is not compressed),
Packit Service 8e7813
       the content of the file is copied to the destination"""
Packit Service 8e7813
Packit Service 8e7813
    if dest:
Packit Service 8e7813
        out = dest
Packit Service 8e7813
    else:
Packit Service 8e7813
        out = None
Packit Service 8e7813
        dot_pos = filename.rfind('.')
Packit Service 8e7813
        if dot_pos > 0:
Packit Service 8e7813
            ext = filename[dot_pos:]
Packit Service 8e7813
            if ext in ('.zck', '.xz', '.bz2', '.gz', '.lzma', '.zst'):
Packit Service 8e7813
                out = filename[:dot_pos]
Packit Service 8e7813
        if out is None:
Packit Service 8e7813
            raise dnf.exceptions.MiscError("Could not determine destination filename")
Packit Service 8e7813
Packit Service 8e7813
    if check_timestamps:
Packit Service 8e7813
        fi = stat_f(filename)
Packit Service 8e7813
        fo = stat_f(out)
Packit Service 8e7813
        if fi and fo and fo.st_mtime == fi.st_mtime:
Packit Service 8e7813
            return out
Packit Service 21c75c
Packit Service 8e7813
    try:
Packit Service 8e7813
        # libdnf.utils.decompress either decompress file to the destination or
Packit Service 8e7813
        # copy the content if the compression type is not recognized
Packit Service 8e7813
        libdnf.utils.decompress(filename, out, 0o644)
Packit Service 8e7813
    except RuntimeError as e:
Packit Service 8e7813
        raise dnf.exceptions.MiscError(str(e))
Packit Service 21c75c
Packit Service 8e7813
    if check_timestamps and fi:
Packit Service 8e7813
        os.utime(out, (fi.st_mtime, fi.st_mtime))
Packit Service 21c75c
Packit Service 21c75c
    return out
Packit Service 21c75c
Packit Service 21c75c
def calculate_repo_gen_dest(filename, generated_name):
Packit Service 21c75c
    dest = os.path.dirname(filename)
Packit Service 21c75c
    dest += '/gen'
Packit Service 21c75c
    if not os.path.exists(dest):
Packit Service 21c75c
        os.makedirs(dest, mode=0o755)
Packit Service 21c75c
    return dest + '/' + generated_name
Packit Service 21c75c
Packit Service 8e7813
Packit Service 8e7813
def repo_gen_decompress(filename, generated_name):
Packit Service 21c75c
    """ This is a wrapper around decompress, where we work out a cached
Packit Service 21c75c
        generated name, and use check_timestamps. filename _must_ be from
Packit Service 21c75c
        a repo. and generated_name is the type of the file. """
Packit Service 21c75c
Packit Service 21c75c
    dest = calculate_repo_gen_dest(filename, generated_name)
Packit Service 8e7813
    return decompress(filename, dest=dest, check_timestamps=True)
Packit Service 21c75c
Packit Service 21c75c
def read_in_items_from_dot_dir(thisglob, line_as_list=True):
Packit Service 21c75c
    """ Takes a glob of a dir (like /etc/foo.d/\\*.foo) returns a list of all
Packit Service 21c75c
       the lines in all the files matching that glob, ignores comments and blank
Packit Service 21c75c
       lines, optional paramater 'line_as_list tells whether to treat each line
Packit Service 21c75c
       as a space or comma-separated list, defaults to True.
Packit Service 21c75c
    """
Packit Service 21c75c
    results = []
Packit Service 21c75c
    for fname in glob.glob(thisglob):
Packit Service 21c75c
        with open(fname) as f:
Packit Service 21c75c
            for line in f:
Packit Service 21c75c
                if re.match(r'\s*(#|$)', line):
Packit Service 21c75c
                    continue
Packit Service 21c75c
                line = line.rstrip() # no more trailing \n's
Packit Service 21c75c
                line = line.lstrip() # be nice
Packit Service 21c75c
                if not line:
Packit Service 21c75c
                    continue
Packit Service 21c75c
                if line_as_list:
Packit Service 21c75c
                    line = line.replace('\n', ' ')
Packit Service 21c75c
                    line = line.replace(',', ' ')
Packit Service 21c75c
                    results.extend(line.split())
Packit Service 21c75c
                    continue
Packit Service 21c75c
                results.append(line)
Packit Service 21c75c
    return results