~ubuntu-core-dev/update-manager/main

1 by Michael Vogt
* initial revision (after accidently killing it)
1
# aptsource.py.in - parse sources.list
2
#  
3
#  Copyright (c) 2004 Canonical
4
#                2004 Michiel Sikkes
5
#  
6
#  Author: Michiel Sikkes <michiel@eyesopened.nl>
7
#          Michael Vogt <mvo@debian.org>
8
# 
9
#  This program is free software; you can redistribute it and/or 
10
#  modify it under the terms of the GNU General Public License as 
11
#  published by the Free Software Foundation; either version 2 of the
12
#  License, or (at your option) any later version.
13
# 
14
#  This program is distributed in the hope that it will be useful,
15
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
#  GNU General Public License for more details.
18
# 
19
#  You should have received a copy of the GNU General Public License
20
#  along with this program; if not, write to the Free Software
21
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
#  USA
23
 
24
import string
25
import gettext
26
import re
27
import apt_pkg
28
import glob
29
30
from DistInfo import DistInfo
31
32
# actual source.list entries
33
class SourceEntry:
34
35
  def __init__(self, line,file):
36
    self.invalid = False
37
    self.disabled = False
38
    self.type = ""
39
    self.uri = ""
40
    self.dist = ""
41
    self.comps = []
42
    self.comment = ""
43
    self.line = line
44
    self.file = file
45
    self.parse(line)
46
47
  # works mostely like split but takes [] into account
48
  def mysplit(self, line):
49
    line = string.strip(line)
50
    pieces = []
51
    tmp = ""
52
    # we are inside a [..] block
53
    p_found = False
54
    space_found = False
55
    for i in range(len(line)):
56
      if line[i] == "[":
57
        p_found=True
58
        tmp += line[i]
59
      elif line[i] == "]":
60
        p_found=False
61
        tmp += line[i]
62
      elif space_found and not line[i].isspace(): # we skip one or more space
63
        space_found = False
64
        pieces.append(tmp)
65
        tmp = line[i]
66
      elif line[i].isspace() and not p_found:     # found a whitespace
67
        space_found = True
68
      else:
69
        tmp += line[i]
70
    # append last piece
71
    if len(tmp) > 0:
72
      pieces.append(tmp)
73
    return pieces
74
75
76
  # parse a given source line and split it into the fields we need
77
  def parse(self,line):
78
    line  = string.strip(self.line)
79
    #print line
80
    # check if the source is enabled/disabled
81
    if line == "" or line == "#": # empty line
82
      self.invalid = True
83
      return
84
    if line[0] == "#":
85
      self.disabled = True
86
      pieces = string.split(line[1:])
87
      # if it looks not like a disabled deb line return 
88
      if not (pieces[0] == "deb" or pieces[0] == "deb-src"):
89
        self.invalid = True
90
        return
91
      else:
92
        line = line[1:]
93
    # check for another "#" in the line (this is treated as a comment)
94
    i = line.find("#")
95
    if i > 0:
96
      self.comment = line[i+1:]
97
      line = line[:i]
98
    # source is ok, split it and see what we have
99
    pieces = self.mysplit(line)
100
    # Type, deb or deb-src
101
    self.type = string.strip(pieces[0])
102
    # URI
103
    self.uri = string.strip(pieces[1])
104
    # distro and components (optional)
105
    # Directory or distro
106
    self.dist = string.strip(pieces[2])
107
    if len(pieces) > 3:
108
      # List of components
109
      self.comps = pieces[3:]
110
    else:
111
      self.comps = []
112
113
    #print self.__dict__
114
115
116
  # set enabled/disabled
117
  def set_enabled(self, new_value):
118
    self.disabled = not new_value
119
    # enable, remove all "#" from the start of the line
120
    if new_value == True:
121
      i=0
122
      self.line = string.lstrip(self.line)
123
      while self.line[i] == "#":
124
        i += 1
125
      self.line = self.line[i:]
126
    else:
127
      # disabled, add a "#" 
128
      if string.strip(self.line)[0] != "#":
129
        self.line = "#" + self.line
130
131
  def str(self):
132
    return self.line
133
134
135
def uniq(s):
136
  """ simple (and not efficient) way to return uniq list """
137
  u = []
138
  for x in s:
139
    if x not in u:
140
      u.append(x)
141
  return u 
142
  
143
144
# the SourceList file as a class
145
class SourcesList:
146
  def __init__(self):
147
    self.list = []      # of Type SourceEntries
148
    # read sources.list
149
    dir = apt_pkg.Config.FindDir("Dir::Etc")
150
    file = apt_pkg.Config.Find("Dir::Etc::sourcelist")
151
    self.load(dir+file)
152
    # read sources.list.d
153
    partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts")
154
    for file in glob.glob("%s/*.list" % partsdir):
155
      self.load(file)
156
157
  def is_mirror(self, add_uri, orig_uri):
158
    """check if the given add_url is idential or a mirror of orig_uri
159
       e.g. add_uri = archive.ubuntu.com
160
            orig_uri = de.archive.ubuntu.com
161
            -> True
162
    """
163
    # remove traling spaces and "/"
164
    add_uri = add_uri.rstrip("/ ")
165
    orig_uri = orig_uri.rstrip("/ ")
166
    # uri is identical
167
    if add_uri == orig_uri:
168
      #print "Identical"
169
      return True
170
    # add uri is a master site and orig_uri has the from "XX.mastersite"
171
    # (e.g. de.archive.ubuntu.com)
172
    try:
173
      add_srv = add_uri.split("//")[1]
174
      orig_srv = orig_uri.split("//")[1]
175
      #print "%s == %s " % (add_srv, orig_srv)
176
    except IndexError: # ok, somethings wrong here
177
      #print "IndexError"
178
      return False
179
    if add_srv == orig_srv[3:]:
180
      #print "Mirror"
181
      return True
182
    return False
183
184
  def add(self, type, uri, dist, comps, comment="", pos=-1):
185
    # if there is a repo with the same (type, uri, dist) just add the
186
    # components
187
    for i in self.list:
188
      if i.type == type and self.is_mirror(uri,i.uri) and i.dist == dist:
189
        comps = uniq(i.comps + comps)
190
        # set to the old position and preserve comment
191
        comment = i.comment
192
        pos = self.list.index(i)
193
        self.list.remove(i)
194
    line = "%s %s %s" % (type,uri,dist)
195
    for c in comps:
196
      line = line + " " + c;
197
    if comment != "":
198
      line = "%s #%s\n" %(line,comment)
199
    line = line + "\n"
200
    self.list.insert(pos, SourceEntry(line))
201
202
  def remove(self, source_entry):
203
    self.list.remove(source_entry)
204
205
  def load(self,file):
206
    f = open(file, "r")
207
    lines = f.readlines()
208
    for line in lines:
209
      source = SourceEntry(line,file)
210
      self.list.append(source)
211
    f.close()
212
213
  def save(self,file):
214
    files = {}
215
    for source in self.list:
216
      if not files.has_key(source.file):
217
        files[source.file]=open(source.file,"w")
218
      files[source.file].write(source.str())
219
    for f in files:
220
      files[f].close()
221
222
223
# templates for the add dialog
224
class SourceEntryTemplate(SourceEntry):
225
  def __init__(self,a_type,uri,dist,description,comps):
226
    self.comps = []
227
    self.comps_descriptions = []
228
    self.type = a_type
229
    self.uri = uri
230
    self.dist = dist
231
    self.description = description
232
    self.comps = comps
233
234
class SourceCompTemplate:
235
  def __init__(self, name, description, on_by_default):
236
    self.name = name
237
    self.description = description
238
    self.on_by_default = on_by_default
239
240
class SourceEntryTemplates:
2 by Michael Vogt
* switched to python dist-utils (DIE auto* DIE)
241
  def __init__(self,datadir):
1 by Michael Vogt
* initial revision (after accidently killing it)
242
    _ = gettext.gettext
243
    self.templates = []
244
2 by Michael Vogt
* switched to python dist-utils (DIE auto* DIE)
245
    dinfo = DistInfo (base_dir=datadir+"channels/")
1 by Michael Vogt
* initial revision (after accidently killing it)
246
247
    for suite in dinfo.suites:
248
      comps = []
249
      for comp in suite.components:
250
        comps.append(SourceCompTemplate(comp.name, _(comp.description),
251
                                        comp.enabled))
252
      self.templates.append (SourceEntryTemplate(suite.repository_type,
253
                                                 suite.base_uri,
254
                                                 suite.name,
255
                                                 suite.description,
256
                                                 comps))
257
258
# matcher class to make a source entry look nice
259
# lots of predefined matchers to make it i18n/gettext friendly
260
class SourceEntryMatcher:
261
  class MatchType:
262
    def __init__(self, a_type,a_descr):
263
      self.type = a_type
264
      self.description = a_descr
265
  
266
  class MatchDist:
267
    def __init__(self,a_uri,a_dist, a_descr,l_comps, l_comps_descr):
268
      self.uri = a_uri
269
      self.dist = a_dist
270
      self.description = a_descr
271
      self.comps = l_comps
272
      self.comps_descriptions = l_comps_descr
273
274
  def __init__(self):
275
    _ = gettext.gettext
276
    self.type_list = []
277
    self.type_list.append(self.MatchType("^deb$",_("Binary")))
278
    self.type_list.append(self.MatchType("^deb-src$",_("Source")))
279
280
    self.dist_list = []
281
282
    ubuntu_comps = ["^main$","^restricted$","^universe$","^multiverse$"]
283
    ubuntu_comps_descr = [_("Officially supported"),
284
                          _("Restricted copyright"),
285
                          _("Community maintained (Universe)"),
286
                          _("Non-free (Multiverse)")]
287
    # CDs
288
    self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.10",
289
                                         ".*",
290
                                        _("CD disk with Ubuntu 5.10 \"Breezy Badger\""),
291
                                         ubuntu_comps, ubuntu_comps_descr))
292
    self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*5.04",
293
                                         ".*",
294
                                        _("CD disk with Ubuntu 5.04 \"Hoary Hedgehog\""),
295
                                         ubuntu_comps, ubuntu_comps_descr))
296
    self.dist_list.append(self.MatchDist("cdrom:\[Ubuntu.*4.10",
297
                                         ".*",
298
                                        _("CD disk with Ubuntu 4.10 \"Warty Warthog\""),
299
                                         ubuntu_comps, ubuntu_comps_descr))
300
    # URIs
301
    # Warty
302
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
303
                                         "^warty$",
304
                                         "Ubuntu 4.10 \"Warty Warthog\"",
305
                                         ubuntu_comps, ubuntu_comps_descr))
306
    self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
307
                                         "^warty-security$",
308
                                         _("Ubuntu 4.10 Security Updates"),
309
                                         ubuntu_comps, ubuntu_comps_descr))
310
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
311
                                         "^warty-security$",
312
                                         _("Ubuntu 4.10 Security Updates"),
313
                                         ubuntu_comps, ubuntu_comps_descr))
314
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
315
                                         "^warty-updates$",
316
                                         _("Ubuntu 4.10 Updates"),
317
                                         ubuntu_comps, ubuntu_comps_descr))
318
    # Hoary
319
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
320
                                         "^hoary-security$",
321
                                         _("Ubuntu 5.04 Security Updates"),
322
                                         ubuntu_comps, ubuntu_comps_descr))
323
    self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
324
                                         "^hoary-security$",
325
                                         _("Ubuntu 5.04 Security Updates"),
326
                                         ubuntu_comps, ubuntu_comps_descr))
327
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
328
                                         "^hoary$",
329
                                         "Ubuntu 5.04 \"Hoary Hedgehog\"",
330
                                         ubuntu_comps, ubuntu_comps_descr))
331
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
332
                                         "^hoary-updates$",
333
                                         _("Ubuntu 5.04 Updates"),
334
                                         ubuntu_comps, ubuntu_comps_descr))
335
    # Breezy
336
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
337
                                         "^breezy-security$",
338
                                         _("Ubuntu 5.10 Security Updates"),
339
                                         ubuntu_comps, ubuntu_comps_descr))
340
    self.dist_list.append(self.MatchDist(".*security.ubuntu.com/ubuntu",
341
                                         "^breezy-security$",
342
                                         _("Ubuntu 5.10 Security Updates"),
343
                                         ubuntu_comps, ubuntu_comps_descr))
344
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
345
                                         "^breezy$",
346
                                         "Ubuntu 5.10 \"Breezy Badger\"",
347
                                         ubuntu_comps, ubuntu_comps_descr))
348
    self.dist_list.append(self.MatchDist(".*archive.ubuntu.com/ubuntu",
349
                                         "^breezy-updates$",
350
                                         _("Ubuntu 5.10 Updates"),
351
                                         ubuntu_comps, ubuntu_comps_descr))
352
353
354
    # DEBIAN
355
    debian_comps =  ["^main$","^contrib$","^non-free$","^non-US$"]
356
    debian_comps_descr = [_("Officially supported"),
357
                          _("Contributed software"),
358
                          _("Non-free software"),
359
                          _("US export restricted software")
360
                          ]
361
362
    # dists by name
363
    self.dist_list.append(self.MatchDist(".*debian.org/debian",
364
                                         "^sarge$",
365
                                         _("Debian 3.1 \"Sarge\""),
366
                                         debian_comps, debian_comps_descr))
367
    self.dist_list.append(self.MatchDist(".*debian.org/debian",
368
                                         "^woody$",
369
                                         _("Debian 3.0 \"Woody\""),
370
                                         debian_comps, debian_comps_descr))
371
    # securtiy
372
    self.dist_list.append(self.MatchDist(".*security.debian.org",
373
                                         "^stable.*$",
374
                                         _("Debian Stable Security Updates"),
375
                                         debian_comps, debian_comps_descr))
376
    # dists by status
377
    self.dist_list.append(self.MatchDist(".*debian.org/debian",
378
                                         "^stable$",
379
                                         _("Debian Stable"),
380
                                         debian_comps, debian_comps_descr))
381
    self.dist_list.append(self.MatchDist(".*debian.org/debian",
382
                                         "^testing$",
383
                                         _("Debian Testing"),
384
                                         debian_comps, debian_comps_descr))
385
    self.dist_list.append(self.MatchDist(".*debian.org/debian",
386
                                         "^unstable$",
387
                                         _("Debian Unstable \"Sid\""),
388
                                         debian_comps, debian_comps_descr))
389
390
    # non-us
391
    self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
392
                                         "^stable.*$",
393
                                         _("Debian Non-US (Stable)"),
394
                                         debian_comps, debian_comps_descr))
395
    self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
396
                                         "^testing.*$",
397
                                         _("Debian Non-US (Testing)"),
398
                                         debian_comps, debian_comps_descr))
399
    self.dist_list.append(self.MatchDist(".*debian.org/debian-non-US",
400
                                         "^unstable.*$",
401
                                         _("Debian Non-US (Unstable)"),
402
                                         debian_comps, debian_comps_descr))
403
404
405
406
  
407
  def match(self,source):
408
    _ = gettext.gettext
409
    # some sane defaults first
410
    type_description = source.type
411
    dist_description = source.uri + " " + source.dist
412
    comp_description = ""
413
    for c in source.comps:
414
      comp_description = comp_description + " " + c 
415
    
416
    for t in self.type_list:
417
      if re.match(t.type, source.type):
418
        type_description = _(t.description)
419
        break
420
421
    for d in self.dist_list:
422
      #print "'%s'" %source.uri
423
      if re.match(d.uri, source.uri) and re.match(d.dist,source.dist):
424
        dist_description = d.description
425
        comp_description = ""
426
        for c in source.comps:
427
          found = False
428
          for i in range(len(d.comps)):
429
            if re.match(d.comps[i], c):
430
              comp_description = comp_description+"\n"+d.comps_descriptions[i]
431
              found = True
432
          if found == False:
433
            comp_description = comp_description+" "+c
434
        break
435
      
436
      
437
    return (type_description,dist_description,comp_description)