summaryrefslogtreecommitdiff
blob: 5769745fe48d2c7641a764c95b156836d035288f (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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
"""Portage Objects"""

# Once tuned, this will hopefully be the interface used in the future for
# packages.g.o

__revision__ = "$Revision: 1.1 $"
# $Source: /var/cvsroot/gentoo/src/packages/p_objects.py,v $
# $Date: 2004/09/17 02:16:17 $

import config

SUBARCHS = ('stable', 'testing', 'all')

class SubArch:
    """Sub Architecture
    We split portage into /<arch>/['stable','testing','all']/
    """

    def __init__(self, arch, sub):
        if sub == 'all':
            self.xml_filename = '%s/archs/%s/portage.xml' % (config.LOCALHOME, 
                arch)
        else:
            self.xml_filename = ('%s/archs/%s/%s/portage.xml' %
            (config.LOCALHOME, arch, sub))
        self.arch = arch
        self.sub = sub
        self.categories = []
        
    def set_categories(self, categories):
        """Set categries of SubArch to categories"""
        self.categories = categories
    
class ArchCollection:
    """Collection of all SubArchitectures"""

    def __init__(self):
        self.collection = {}
        for arch in config.ARCHLIST:
            #print arch
            self.collection[arch] = {}
            for sub in SUBARCHS:
                #print sub
                self.collection[arch][sub] = SubArch(arch, sub)
                
class Category:
    """Collection of packages"""

    def __init__(self, arch, sub, name):
        self.arch = arch
        self.sub = sub
        self.name = name
        self.packages = []

    def set_packages(self, packages):
        """Set packages for this Category"""
        self.packages = packages
    def __str__(self):
        return self.name

class CategoryFactory:
    """get returns a list of categories with specified criteria
    create creates a "deep" (populated) category (singular) from specified
    criteria
    """
    def __init__(self, db):
        # shuts up pylint
        self.db = db
        self.cache = {}
        self.pfactory = PackageFactory(self.db)
        
    def create(self, arch, sub, category):
        """Create a populated category using database db"""
        key = '/'.join((arch, sub, category))
        if self.cache.has_key(key):
            return self.cache[key]
        
        category = Category(arch, sub, category)
        packages = [self.pfactory.create(arch, sub, category.name, package.name) 
            for package in self.pfactory.get(arch, sub, category.name)]
        category.set_packages(packages)
        self.cache[key] = category
        return category
        
    def get(self, arch, sub):
        """Return list of categories from db with specified criteria"""
        key = '/'.join((arch, sub))
        if self.cache.has_key(key):
            return self.cache[key]
        c = self.db.cursor()
        query = ('SELECT DISTINCT category FROM ebuild WHERE 1=1 %s ' 
            % get_extra(arch, sub))
        #print query
        c.execute(query)
        results = [result[0] for result in c.fetchall()]
        categories = [Category(arch, sub, category) for category in results]
        self.cache[key] = categories
        return categories
        
class Package:
    """Collection of ebuilds"""

    def __init__(self, arch, sub, category, name):
        self.arch = arch
        self.sub = sub
        self.category = category
        self.name = name
        self.ebuilds = []
        self.homepages = ''
        self.licenses = ''
        self.description = ''

    def set_ebuilds(self, ebuilds):
        """Populates Package with specified list of ebuilds"""
        self.ebuilds = ebuilds
        if self.ebuilds:
            self.homepages = self.ebuilds[0].homepages
            self.licenses = self.ebuilds[0].licenses
            self.description = self.ebuilds[0].description
            
    def __str__(self):
        return self.name

class PackageFactory:
    """get or create packages and populate the ebuilds automagically"""
    
    def __init__(self, db):
        self.db = db
        self.cache = {}
        self.efactory = EbuildFactory(self.db)
    
    def create(self, arch, sub, category, name):
        """Create fully populated Package"""
        
        key = '/'.join((arch, sub, category, name))
        if self.cache.has_key(key):
            return self.cache[key]
            
        package = Package(arch, sub, category, name)
        ebuilds = [Ebuild(category = ebuild.category, 
            name = ebuild.name,
            version = ebuild.version, 
            when_found = ebuild.when_found,
            description = ebuild.description, 
            arch = ' '.join(ebuild.archs),
            homepage = ' '.join(ebuild.homepages), 
            license = ' '.join(ebuild.licenses),
            changelog = ebuild.changelog)
            for ebuild in self.efactory.get(arch, sub, category, name)]
        package.set_ebuilds(ebuilds)
        self.cache[key] = package
        return package
        
    def get(self, arch, sub, category):
        """Return list of (empty) Packages with specified criteria"""
        key = '/'.join((arch, sub, category))
        if self.cache.has_key(key):
            return self.cache[key]
        
        c = self.db.cursor()
        query = ('SELECT DISTINCT name FROM ebuild WHERE category = "%s" %s'
            % (category, get_extra(arch, sub)))
        #print query
        c.execute(query)
        results = [result[0] for result in c.fetchall()]
        packages = [Package(arch, sub, category, name) for name in results]
        self.cache[key] = packages
        return packages
    
class Ebuild:
    """Classic ebuild
    
    To create a Ebuild object, we expect:
        category
        name
        version
        when_found
        description
        arch (as KEYWORDS in .ebuilds)
        homepage
        license
        changelog (see changelog.py for help in getting this value from portage)
    """

    def __init__(self, **kwargs):
        self.category = kwargs['category']
        self.name = kwargs['name']
        self.version = kwargs['version']
        self.when_found = kwargs['when_found']
        self.description = kwargs['description']
        self.archs = kwargs['arch'].split()
        self.homepages = kwargs['homepage'].split()
        licenses = kwargs['license'].replace('|',' ') 
        # replace |  with space so to split
        self.licenses = licenses.split()
        self.changelog = kwargs['changelog']

class EbuildFactory:
    """Ebuild factory.  We only need the get() method as create would do the
    same thing as Ebuild().  Ebuilds don't need to be populated further down
    """
    def __init__(self, db):
        self.db = db
        self.cache = {}
        
    def get(self, arch, sub, category, name):
        """Given database, db, return list of Ebuilds"""
        c = self.db.cursor()
        query = ('SELECT ebuild.category, ebuild.name, version, when_found, '
            'description, changelog, arch, homepage, license FROM ebuild, '
            'package WHERE ebuild.name = "%s" AND ebuild.category = "%s" AND '
            'ebuild.name = package.name AND ebuild.category = package.category '
            '%s ORDER by when_found DESC' 
            % (name, category, get_extra(arch, sub)))
        #print query
        c.execute(query)
        results = c.fetchall()
        return [Ebuild(category=result[0], name=result[1], version=result[2],
            when_found=result[3], description=result[4], changelog=result[5],
            arch=result[6], homepage=result[7], license=result[8]) for result
            in results]
        
def get_extra(arch, sub):
    """Return extra criteria of a query string according to arch and sub"""
    
    if sub == 'all':
        sub = ''
    if arch == 'all':
        arch = ''
    extra = ''
    if arch:
        stable_extra = ('ebuild.arch REGEXP "^%s| %s" '
            % (arch,arch))
        testing_extra = ('ebuild.arch REGEXP "^~%s| ~%s" '
            % (arch,arch))
        if sub == 'stable':
            extra = ' AND (%s) ' % stable_extra
        elif sub == 'testing':
            extra = ' AND (%s) ' % testing_extra
        else:
            extra = ' AND ((%s) OR (%s)) ' % (stable_extra, testing_extra)
            
    return extra