summaryrefslogtreecommitdiffstats
path: root/rpmci/dynrepo.py
blob: 8db1a8d58757699b0f03f72032148261f6bff959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/python

# dynrepo.py:
# Monitor set of RPMs in a directory.
#
# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
# Copyright (C) 2010 Red Hat, Inc.
# Written by Colin Walters <walters@verbum.org>

import os
import sys
import logging
import subprocess

import glib
import gio
import rpm
import rpmUtils
import rpmUtils.miscutils

from . import async_subprocess

class Repo(object):
    def __init__(self, dirpath):
        self._dir = dirpath
        self._dir_gfile = gio.File(path=dirpath)
        self._monitor = self._dir_gfile.monitor(gio.FILE_MONITOR_NONE)
        self._monitor.connect('changed', self._on_dir_changed)
        self._rpms = {}

    def get_rpms(self):
        return self._rpms

    def get_rpms_for_name(self, name, arch):
        result = []
        for filename,(n,a,e,v,r) in self._rpms.iteritems():
            if n == name and (arch is None or a == arch):
                result.append((filename, n, a, e, v, r))
        return result

    def get_latest_srpm_for_name(self, name):
        rpms = self.get_rpms_for_name(name, 'src')
        cmpevr=rpmUtils.miscutils.compareEVR
        if rpms:
            rpms.sort(lambda a,b: cmpevr(a[3:6], b[3:6]))
            return rpms[-1]
        return None
 
    def add_srpm(self, srpm_path):
        basename = os.path.basename(srpm_path)
        os.link(srpm_path, os.path.join(self._dir, basename))

    def _delete_old_rpms_in_dir(self, dirpath):
        proc = subprocess.Popen(['repomanage', '-o', '.'], stdout=subprocess.PIPE,
                                stderr=sys.stderr,
                                cwd=dirpath)
        output = proc.communicate()[0]
        for line in output.split('\n'):
             if line.endswith('.rpm') and os.path.exists(line):
               os.unlink(line)

    def update_repo_sync(self):
        self._delete_old_rpms_in_dir(self._dir)
        subprocess.check_call(['createrepo', '.'], cwd=self._dir)

    def _headers_from_packages(self, rpmlist):
        result = {}
        ts = rpm.TransactionSet()
        ts.setVSFlags(~(rpm._RPMVSF_NOPAYLOAD))
        for pkg in rpmlist:
            pkg_path = os.path.join(self._dir, pkg)
            try:
               header = rpmUtils.miscutils.hdrFromPackage(ts, pkg_path)
            except rpmUtils.RpmUtilsError, e:
                logging.exception(e)
                continue
            (n,a,e,v,r) = rpmUtils.miscutils.pkgTupleFromHeader(header)
            del header
            result[pkg] = (n,a,e,v,r)
        return result

    def _on_dir_changed(self, mon, gfile, other, event):
        self._reload()

    def _reload(self):
        dir_contents = os.listdir(self._dir)
        messages = set()
        rpmlist = set()
        for filename in dir_contents:
            if filename.endswith('.tmp'):
                continue
            if not filename.endswith('.rpm'):
                continue
            rpmlist.add(filename)
        
        deleted = []
        for rpm in self._rpms:
            if rpm not in rpmlist:
                deleted.add(rpm)
        for rpm in deleted:
            del self._rpms[rpm]
        new = []
        for rpm in self._rpms:
            if rpm not in rpmlist:
                new.append(rpm)
        for rpm,data in self._headers_from_packages(new).iteritems():
            self._rpms[rpm] = data