Merge branch 'master' of ssh://git.ipfire.org/pub/git/ipfire.org
[people/shoehn/ipfire.org.git] / www / webapp / backend / releases.py
CommitLineData
940227cb
MT
1#!/usr/bin/python
2
3c4f2edc 3import hashlib
940227cb 4import logging
3c4f2edc
MT
5import os
6import re
940227cb
MT
7import urlparse
8
9from databases import Databases
10from misc import Singleton
11from settings import Settings
12
13class 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,
60024cc8 62 "arm" : 40,
940227cb
MT
63 "xen" : 50,
64 }
65
66 try:
67 return priorities[self.type]
68 except KeyError:
69 return 999
70
71 @property
72 def rem(self):
73 _ = lambda x: x
74
75 remarks = {
76 "iso" : _("Use this image to burn a CD and install IPFire from it."),
77 "torrent" : _("Download the CD image from the torrent network."),
78 "flash" : _("An image that is meant to run on embedded devices."),
79 "alix" : _("Flash image where a serial console is enabled by default."),
80 "usbfdd" : _("Install IPFire from a floppy-formated USB key."),
81 "usbhdd" : _("If the floppy image doesn't work, use this image instead."),
82 "xen" : _("A ready-to-run image for Xen."),
83 }
84
85 try:
86 return remarks[self.type]
87 except KeyError:
88 return _("Unknown image type")
89
90 @property
91 def sha1(self):
92 return self.__data.get("sha1")
93
94 @property
95 def filename(self):
96 return self.__data.get("filename")
97
c9698a0b
MT
98 @property
99 def basename(self):
100 return os.path.basename(self.filename)
101
60024cc8
MT
102 @property
103 def size(self):
104 return self.__data.get("filesize")
105
106 @property
107 def arch(self):
108 known_arches = ("i586", "arm")
109
110 for arch in known_arches:
111 if arch in self.basename:
112 return arch
113
114 return "N/A"
115
940227cb
MT
116
117class Release(object):
118 @property
119 def db(self):
120 return Releases().db
121
122 def __init__(self, id):
123 self.id = id
124
125 # get all data from database
126 self.__data = \
127 self.db.get("SELECT * FROM releases WHERE id = %s", self.id)
128 assert self.__data
129
130 self.__files = []
131
132 def __repr__(self):
133 return "<%s %s>" % (self.__class__.__name__, self.name)
134
135 @property
136 def files(self):
137 if not self.__files:
138 files = self.db.query("SELECT id FROM files WHERE releases = %s \
60024cc8 139 AND loadable = 'Y' AND NOT filetype = 'torrent'", self.id)
940227cb
MT
140
141 self.__files = [File(self, f.id) for f in files]
142 self.__files.sort(lambda a, b: cmp(a.prio, b.prio))
143
144 return self.__files
145
146 @property
147 def name(self):
148 return self.__data.get("name")
149
150 @property
151 def stable(self):
152 return self.__data.get("stable")
153
154 @property
155 def published(self):
156 return self.__data.get("published")
157
158 @property
159 def date(self):
160 return self.__data.get("date")
161
3c4f2edc
MT
162 @property
163 def path(self):
164 return self.__data.get("path")
165
940227cb
MT
166 @property
167 def torrent_hash(self):
168 h = self.__data.get("torrent_hash")
169 if h:
170 return h.lower()
171
172 def get_file(self, type):
173 for file in self.files:
174 if file.type == type:
175 return file
176
3c4f2edc
MT
177 def __file_hash(self, filename):
178 sha1 = hashlib.sha1()
179
180 with open(filename) as f:
b5f4eef0
MT
181 buf_size = 1024
182 buf = f.read(buf_size)
183 while buf:
184 sha1.update(buf)
185 buf = f.read(buf_size)
3c4f2edc
MT
186
187 return sha1.hexdigest()
188
189 def __guess_filetype(self, filename):
190 if filename.endswith(".iso"):
191 return "iso"
192
193 if filename.endswith(".torrent"):
194 return "torrent"
195
196 if "xen" in filename:
197 return "xen"
198
199 if "sources" in filename:
200 return "source"
201
202 if "usb-fdd" in filename:
203 return "usbfdd"
204
205 if "usb-hdd" in filename:
206 return "usbhdd"
207
60024cc8
MT
208 if "arm" in filename:
209 return "arm"
210
3c4f2edc
MT
211 if "scon" in filename:
212 return "alix"
213
214 if filename.endswith(".img.gz"):
215 return "flash"
216
217 return "unknown"
218
219 def scan_files(self, basepath="/srv/mirror0"):
220 if not self.path:
221 return
222
223 path = os.path.join(basepath, self.path)
224
921d98cc
MT
225 if not os.path.exists(path):
226 return
227
3c4f2edc
MT
228 files = [f.filename for f in self.files]
229
230 # Make files that do not exists not loadable.
231 for filename in files:
232 _filename = os.path.join(basepath, filename)
233 if not os.path.exists(_filename):
234 self.db.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename)
235
236 for filename in os.listdir(path):
237 filename = os.path.join(path, filename)
238
239 if os.path.isdir(filename):
240 continue
241
242 _filename = re.match(".*(releases/.*)", filename).group(1)
243 if _filename in files:
244 continue
245
246 if filename.endswith(".md5"):
247 continue
248
249 filehash = self.__file_hash(filename)
250 filesize = os.path.getsize(filename)
251 filetype = self.__guess_filetype(filename)
252
253 self.db.execute("""INSERT INTO files(releases, filename, filesize, filetype, sha1)
254 VALUES(%s, %s, %s, %s, %s)""", self.id, _filename, filesize, filetype, filehash)
255
940227cb
MT
256
257class Releases(object):
258 __metaclass__ = Singleton
259
260 @property
261 def db(self):
262 return Databases().webapp
263
264 def list(self):
265 return [Release(r.id) for r in self.db.query("SELECT id FROM releases ORDER BY date DESC")]
266
267 def get_by_id(self, id):
268 id = int(id)
269 if id in [r.id for r in self.db.query("SELECT id FROM releases")]:
270 return Release(id)
271
272 def get_latest(self, stable=1):
273 query = "SELECT id FROM releases WHERE published='Y' AND"
274 if stable:
275 query += " stable='Y'"
276 else:
277 query += " stable='N'"
278
279 query += " ORDER BY date DESC LIMIT 1"
280
281 release = self.db.get(query)
282 if release:
283 return Release(release.id)
284
285 def get_stable(self):
286 releases = self.db.query("""SELECT id FROM releases
287 WHERE published='Y' AND stable='Y'
288 ORDER BY date DESC""")
289
290 return [Release(r.id) for r in releases]
291
292 def get_unstable(self):
293 releases = self.db.query("""SELECT id FROM releases
294 WHERE published='Y' AND stable='N'
295 ORDER BY date DESC""")
296
297 return [Release(r.id) for r in releases]
298
299 def get_all(self):
300 releases = self.db.query("""SELECT id FROM releases
301 WHERE published='Y' ORDER BY date DESC""")
302
303 return [Release(r.id) for r in releases]
304
305
306if __name__ == "__main__":
307 r = Releases()
308
309 for release in r.get_all():
310 print release.name
311
312 print r.get_latest()