~ubuntu-core-dev/ubuntu/xenial/ubuntu-release-upgrader/xenial

« back to all changes in this revision

Viewing changes to AutoUpgradeTester/install_universe

  • Committer: Michael Terry
  • Date: 2012-06-06 21:23:35 UTC
  • mto: This revision was merged to the branch mainline in revision 2509.
  • Revision ID: michael.terry@canonical.com-20120606212335-dt5xyu2v3ct5hcey
first pass at converting update-manager source into ubuntu-release-upgrader

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
"""
3
 
Install all packages with a desktop file in app-install-data
4
 
"""
5
 
 
6
 
 
7
 
from __future__ import print_function
8
 
 
9
 
import apt
10
 
import apt_pkg
11
 
import re
12
 
import os
13
 
import sys
14
 
 
15
 
# global install blacklist
16
 
pkg_blacklist = None
17
 
 
18
 
# whitelist regexp to include only certain packages (useful for e.g.
19
 
# installing only all python packages)
20
 
pkg_whitelist = ""
21
 
 
22
 
class InstallProgress(apt.progress.base.InstallProgress):
23
 
   " Out install progress that can automatically remove broken pkgs "
24
 
   def error(self, pkg, errormsg):
25
 
      # on failure: 
26
 
      # - add failing package to "install_failures.txt"  [done]
27
 
      # - remove package from best.txt [done]
28
 
      # FIXME: - remove all rdepends from best.txt
29
 
      # - remove the failed install attempts [done]
30
 
      #   * explode if a package can not be removed and let the user cleanup
31
 
      open("install_failures.txt","a").write("%s _:_ %s" % (pkg, errormsg))
32
 
      bad = set()
33
 
      bad.add(os.path.basename(pkg).split("_")[0])
34
 
      # FIXME: just run apt-cache rdepends $pkg here?
35
 
      #        or use apt.Package.candidateDependencies ?
36
 
      #        or calculate the set again? <- BEST!
37
 
      for name in bad:
38
 
         new_best = open("best.txt").read().replace(name+"\n","")
39
 
         open("best.txt","w").write(new_best)
40
 
         open("install_blacklist.cfg","a").write("# auto added by install_all.py\n%s\n" % name)
41
 
 
42
 
def do_install(cache):
43
 
   # go and install
44
 
   res = False
45
 
   current = 0
46
 
   maxRetries = 5
47
 
   while current < maxRetries:
48
 
      print("Retry: ", current)
49
 
      try:
50
 
         res = cache.commit(apt.progress.text.AcquireProgress(),
51
 
                            InstallProgress())
52
 
         break
53
 
      except IOError as e:
54
 
         # fetch failed, will be retried
55
 
         current += 1
56
 
         print("Retrying to fetch: ", current, e)
57
 
         continue
58
 
      except SystemError as e:
59
 
         print("Error installing packages! ")
60
 
         print(e)
61
 
         print("Install result: ", res)
62
 
         break
63
 
   # check for failed packages and remove them
64
 
   if os.path.exists("install_failures.txt"):
65
 
      with open("install_failures.txt") as install_failures:
66
 
         failures = set([os.path.basename(s.split("_:_")[0]).split("_")[0]
67
 
                         for s in install_failures])
68
 
      print("failed: ", failures)
69
 
      assert(os.system("dpkg -r %s" % " ".join(failures)) == 0)
70
 
      assert(os.system("dpkg --configure -a") == 0)
71
 
      # remove pos.txt and best.txt to force recalculation
72
 
      os.unlink("pos.txt")
73
 
      os.unlink("best.txt")
74
 
   return res
75
 
 
76
 
def blacklisted(name):
77
 
   global pkg_blacklist
78
 
   if pkg_blacklist is None and os.path.exists("install_blacklist.cfg"):
79
 
      pkg_blacklist = set()
80
 
      with open("install_blacklist.cfg") as blacklist_file:
81
 
         for line in blacklist_file:
82
 
            name = line.strip()
83
 
            if name and not name.startswith("#"):
84
 
               pkg_blacklist.add(name)
85
 
      print("blacklist: ", pkg_blacklist)
86
 
   if pkg_blacklist:
87
 
      for b in pkg_blacklist:
88
 
           if re.match(b, name):
89
 
              return True
90
 
   return False
91
 
 
92
 
def reapply(cache, pkgnames):
93
 
   for name in pkgnames:
94
 
      cache[name].mark_install(False)
95
 
 
96
 
def contains_blacklisted_pkg(cache):
97
 
   for pkg in cache:
98
 
      if pkg.marked_install and blacklisted(pkg.name):
99
 
         return True
100
 
   return False
101
 
 
102
 
def appinstall_pkgs():
103
 
    try:
104
 
        import configparser
105
 
    except ImportError:
106
 
        import ConfigParser as configparser
107
 
 
108
 
    APPINSTALL_DIR = "/usr/share/app-install/desktop"
109
 
 
110
 
    content = configparser.ConfigParser()
111
 
    pkgs = []
112
 
 
113
 
    # List of sections to skip. This must be a valid regular expression
114
 
    # We must exclude window managers to not kill ourselves
115
 
    for dsk in os.listdir(APPINSTALL_DIR):
116
 
        dskfile = os.path.join(APPINSTALL_DIR, dsk)
117
 
        if not 'desktop' in dsk[-7:]:
118
 
            continue
119
 
        try:
120
 
            content.read(dskfile)
121
 
            pkg = content.get('Desktop Entry', 'X-AppInstall-Package')
122
 
            if not pkg in pkgs:
123
 
                pkgs.append(pkg)
124
 
        except:
125
 
            print("Error: unable to parse %s" % dskfile)
126
 
            continue
127
 
 
128
 
    return pkgs
129
 
 
130
 
# ----------------------------------------------------------------
131
 
 
132
 
#apt_pkg.config.set("Dir::State::status","./empty")
133
 
 
134
 
# debug stuff
135
 
#apt_pkg.config.set("Debug::pkgProblemResolver","true")
136
 
#apt_pkg.config.set("Debug::pkgDepCache::AutoInstall","true")
137
 
#apt_pkg.config.set("Debug::pkgDpkgPM","true")
138
 
 
139
 
# Increase the maxsize limits here
140
 
#
141
 
# this code in apt that splits the argument list if its too long
142
 
#  is problematic, because it may happen that
143
 
# the argument list is split in a way that A depends on B
144
 
# and they are in the same "--configure A B" run
145
 
# - with the split they may now be configured in different
146
 
#   runs
147
 
 
148
 
apt_pkg.config.set("Dpkg::MaxArgs",str(16*1024))
149
 
apt_pkg.config.set("Dpkg::MaxArgBytes",str(64*1024))
150
 
 
151
 
print("*** installings all packages from app-install-data ***")
152
 
os.environ["DEBIAN_FRONTEND"] = "noninteractive"
153
 
os.environ["APT_LISTCHANGES_FRONTEND"] = "none"
154
 
 
155
 
cache = apt.Cache()
156
 
 
157
 
# dapper does not have this yet
158
 
group = cache.actiongroup()
159
 
#print([pkg.name for pkg in cache if pkg.is_installed])
160
 
 
161
 
# see what gives us problems
162
 
troublemaker = set()
163
 
best = set()
164
 
 
165
 
# first install all of main, then the rest
166
 
comps= ["main","universe"]
167
 
i=0
168
 
 
169
 
# reapply checkpoints
170
 
if os.path.exists("best.txt"):
171
 
   with open("best.txt") as best_file:
172
 
      best = [line.strip() for line in best_file]
173
 
   reapply(cache, best)
174
 
 
175
 
comp = None
176
 
if os.path.exists("pos.txt"):
177
 
   (comp, i) = open("pos.txt").read().split()
178
 
   i = int(i)
179
 
 
180
 
sorted_pkgs = appinstall_pkgs()
181
 
sorted_pkgs.sort()
182
 
 
183
 
for pkgname in sorted_pkgs[i:]:
184
 
  # skip multiarch packages
185
 
  i += 1
186
 
  if ":" in pkgname:
187
 
     continue
188
 
  try:
189
 
     pkg = cache[pkgname]
190
 
  except:
191
 
     print("WARNING: No package named %s" % pkg)
192
 
     continue
193
 
  percent = (float(i)/len(sorted_pkgs))*100.0
194
 
  print("\r%.3f     " % percent, end="")
195
 
  sys.stdout.flush()
196
 
  # ignore stuff that does not match the whitelist pattern
197
 
  # (if we use this)
198
 
  if pkg_whitelist:
199
 
     if not re.match(pkg_whitelist, pkg.name):
200
 
        #print("skipping '%s' (not in whitelist)" % pkg.name)
201
 
        continue
202
 
  print("looking at ", pkg.name)
203
 
  # only work on stuff that has a origin
204
 
  if pkg.candidate:
205
 
     for c in pkg.candidate.origins:
206
 
        comp = c.component
207
 
        if not (pkg.is_installed or blacklisted(pkg.name)):
208
 
          current = set([p.name for p in cache if p.marked_install])
209
 
          try:
210
 
             pkg.mark_install()
211
 
          except SystemError as e:
212
 
             print("Installing '%s' cause problems: %s" % (pkg.name, e))
213
 
             pkg.mark_keep()
214
 
          # check blacklist
215
 
          if contains_blacklisted_pkg(cache):
216
 
             cache.clear()
217
 
             reapply(cache, best)
218
 
             continue
219
 
          new = set([p.name for p in cache if p.marked_install])
220
 
          #if not pkg.marked_install or len(new) < len(current):
221
 
          if not (pkg.is_installed or pkg.marked_install):
222
 
             print("Can't install: %s" % pkg.name)
223
 
          if len(current-new) > 0:
224
 
             troublemaker.add(pkg.name)
225
 
             print("Installing '%s' caused removals %s" % (pkg.name, current - new))
226
 
          # FIXME: instead of len() use score() and score packages
227
 
          #        according to criteria like "in main", "priority" etc
228
 
          if len(new) >= len(best):
229
 
             best = new
230
 
             open("best.txt","w").write("\n".join(best))
231
 
             open("pos.txt","w").write("%s %s" % (comp, i))
232
 
          else:
233
 
             print("Installing '%s' reduced the set (%s < %s)" % (pkg.name, len(new), len(best)))
234
 
             cache.clear()
235
 
             reapply(cache, best)
236
 
i=0
237
 
 
238
 
# make sure that the ubuntu base packages are installed (and a bootloader)
239
 
print(len(troublemaker))
240
 
for pkg in ["ubuntu-desktop", "ubuntu-minimal", "ubuntu-standard", "grub-pc"]:
241
 
    cache[pkg].mark_install()
242
 
 
243
 
# make sure we don't install blacklisted stuff
244
 
for pkg in cache:
245
 
        if blacklisted(pkg.name):
246
 
                pkg.mark_keep()
247
 
 
248
 
# install it
249
 
print("We can install:", len([pkg.name for pkg in cache if pkg.marked_install]))
250
 
# get size
251
 
pm = apt_pkg.PackageManager(cache._depcache)
252
 
fetcher = apt_pkg.Acquire()
253
 
pm.get_archives(fetcher, cache._list, cache._records)
254
 
print("Download: ", apt_pkg.size_to_str(fetcher.fetch_needed))
255
 
print("Total space: ", apt_pkg.size_to_str(cache._depcache.usr_size))
256
 
 
257
 
# write out file with all pkgs
258
 
outf = "all_pkgs.cfg"
259
 
print("writing out file with the selected package names to '%s'" % outf)
260
 
f = open(outf, "w")
261
 
f.write("\n".join([pkg.name for pkg in cache if pkg.marked_install]))
262
 
f.close()
263
 
 
264
 
# now do the real install
265
 
res = do_install(cache)
266
 
 
267
 
if not res:
268
 
   # FIXME: re-exec itself
269
 
   sys.exit(1)
270
 
 
271
 
sys.exit(0)