manager: Fix crash is release directory does not exist, yet.
[people/shoehn/ipfire.org.git] / www / webapp / backend / releases.py
1 #!/usr/bin/python
2
3 import hashlib
4 import logging
5 import os
6 import re
7 import urlparse
8
9 from databases import Databases
10 from misc import Singleton
11 from settings import Settings
12
13 class File(object):
14         def __init__(self, release, id):
15                 self.release = release
16
17                 # get all data from database
18                 self.__data = self.db.get("SELECT * FROM files WHERE id = %s", id)
19
20         @property
21         def db(self):
22                 return self.release.db
23
24         @property
25         def type(self):
26                 return self.__data.get("filetype")
27
28         @property
29         def url(self):
30                 baseurl = Settings().get("download_url")
31
32                 return urlparse.urljoin(baseurl, self.filename)
33
34         @property
35         def desc(self):
36                 _ = lambda x: x
37
38                 descriptions = {
39                         "iso"           : _("Installable CD image"),
40                         "torrent"       : _("Torrent file"),
41                         "flash"         : _("Flash image"),
42                         "alix"          : _("Alix image"),
43                         "usbfdd"        : _("USB FDD Image"),
44                         "usbhdd"        : _("USB HDD Image"),
45                         "xen"           : _("Pregenerated Xen image"),
46                 }
47
48                 try:
49                         return descriptions[self.type]
50                 except KeyError:
51                         return _("Unknown image type")
52
53         @property
54         def prio(self):
55                 priorities = {
56                         "iso"           : 10,
57                         "torrent"       : 20,
58                         "flash"         : 40,
59                         "alix"          : 41,
60                         "usbfdd"        : 31,
61                         "usbhdd"        : 30,
62                         "xen"           : 50,
63                 }
64                 
65                 try:
66                         return priorities[self.type]
67                 except KeyError:
68                         return 999
69
70         @property
71         def rem(self):
72                 _ = lambda x: x
73         
74                 remarks = {
75                         "iso"           : _("Use this image to burn a CD and install IPFire from it."),
76                         "torrent"       : _("Download the CD image from the torrent network."),
77                         "flash"         : _("An image that is meant to run on embedded devices."),
78                         "alix"          : _("Flash image where a serial console is enabled by default."),
79                         "usbfdd"        : _("Install IPFire from a floppy-formated USB key."),
80                         "usbhdd"        : _("If the floppy image doesn't work, use this image instead."),
81                         "xen"           : _("A ready-to-run image for Xen."),
82                 }
83
84                 try:
85                         return remarks[self.type]
86                 except KeyError:
87                         return _("Unknown image type")
88
89         @property
90         def sha1(self):
91                 return self.__data.get("sha1")
92
93         @property
94         def filename(self):
95                 return self.__data.get("filename")
96
97         @property
98         def basename(self):
99                 return os.path.basename(self.filename)
100
101
102 class Release(object):
103         @property
104         def db(self):
105                 return Releases().db
106
107         def __init__(self, id):
108                 self.id = id
109
110                 # get all data from database
111                 self.__data = \
112                         self.db.get("SELECT * FROM releases WHERE id = %s", self.id)
113                 assert self.__data
114
115                 self.__files = []
116
117         def __repr__(self):
118                 return "<%s %s>" % (self.__class__.__name__, self.name)
119
120         @property
121         def files(self):
122                 if not self.__files:
123                         files = self.db.query("SELECT id FROM files WHERE releases = %s \
124                                         AND loadable = 'Y'", self.id)
125
126                         self.__files = [File(self, f.id) for f in files]
127                         self.__files.sort(lambda a, b: cmp(a.prio, b.prio))
128
129                 return self.__files
130
131         @property
132         def name(self):
133                 return self.__data.get("name")
134
135         @property
136         def stable(self):
137                 return self.__data.get("stable")
138
139         @property
140         def published(self):
141                 return self.__data.get("published")
142
143         @property
144         def date(self):
145                 return self.__data.get("date")
146
147         @property
148         def path(self):
149                 return self.__data.get("path")
150
151         @property
152         def torrent_hash(self):
153                 h = self.__data.get("torrent_hash")
154                 if h:
155                         return h.lower()
156
157         def get_file(self, type):
158                 for file in self.files:
159                         if file.type == type:
160                                 return file
161
162         def __file_hash(self, filename):
163                 sha1 = hashlib.sha1()
164
165                 with open(filename) as f:
166                         sha1.update(f.read())
167
168                 return sha1.hexdigest()
169
170         def __guess_filetype(self, filename):
171                 if filename.endswith(".iso"):
172                         return "iso"
173
174                 if filename.endswith(".torrent"):
175                         return "torrent"
176
177                 if "xen" in filename:
178                         return "xen"
179
180                 if "sources" in filename:
181                         return "source"
182
183                 if "usb-fdd" in filename:
184                         return "usbfdd"
185
186                 if "usb-hdd" in filename:
187                         return "usbhdd"
188
189                 if "scon" in filename:
190                         return "alix"
191
192                 if filename.endswith(".img.gz"):
193                         return "flash"
194
195                 return "unknown"
196
197         def scan_files(self, basepath="/srv/mirror0"):
198                 if not self.path:
199                         return
200
201                 path = os.path.join(basepath, self.path)
202
203                 if not os.path.exists(path):
204                         return
205
206                 files = [f.filename for f in self.files]
207
208                 # Make files that do not exists not loadable.
209                 for filename in files:
210                         _filename = os.path.join(basepath, filename)
211                         if not os.path.exists(_filename):
212                                 self.db.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename)
213
214                 for filename in os.listdir(path):
215                         filename = os.path.join(path, filename)
216
217                         if os.path.isdir(filename):
218                                 continue
219
220                         _filename = re.match(".*(releases/.*)", filename).group(1)
221                         if _filename in files:
222                                 continue
223
224                         if filename.endswith(".md5"):
225                                 continue
226
227                         filehash = self.__file_hash(filename)
228                         filesize = os.path.getsize(filename)
229                         filetype = self.__guess_filetype(filename)
230
231                         self.db.execute("""INSERT INTO files(releases, filename, filesize, filetype, sha1)
232                                 VALUES(%s, %s, %s, %s, %s)""", self.id, _filename, filesize, filetype, filehash)
233
234
235 class Releases(object):
236         __metaclass__ = Singleton
237
238         @property
239         def db(self):
240                 return Databases().webapp
241
242         def list(self):
243                 return [Release(r.id) for r in self.db.query("SELECT id FROM releases ORDER BY date DESC")]
244
245         def get_by_id(self, id):
246                 id = int(id)
247                 if id in [r.id for r in self.db.query("SELECT id FROM releases")]:
248                         return Release(id)
249
250         def get_latest(self, stable=1):
251                 query = "SELECT id FROM releases WHERE published='Y' AND"
252                 if stable:
253                         query += " stable='Y'"
254                 else:
255                         query += " stable='N'"
256
257                 query += " ORDER BY date DESC LIMIT 1"
258
259                 release = self.db.get(query)
260                 if release:
261                         return Release(release.id)
262
263         def get_stable(self):
264                 releases = self.db.query("""SELECT id FROM releases
265                         WHERE published='Y' AND stable='Y'
266                         ORDER BY date DESC""")
267
268                 return [Release(r.id) for r in releases]
269
270         def get_unstable(self):
271                 releases = self.db.query("""SELECT id FROM releases
272                         WHERE published='Y' AND stable='N'
273                         ORDER BY date DESC""")
274
275                 return [Release(r.id) for r in releases]
276
277         def get_all(self):
278                 releases = self.db.query("""SELECT id FROM releases
279                         WHERE published='Y' ORDER BY date DESC""")
280
281                 return [Release(r.id) for r in releases]
282
283
284 if __name__ == "__main__":
285         r = Releases()
286
287         for release in r.get_all():
288                 print release.name
289
290         print r.get_latest()