28
29
self._apt_cache = None
29
30
self._contents_dir = None
30
31
self._mirror = None
31
# Checking whether we should use the API from python-apt 0.7.9
32
self.apt_pre_079 = not hasattr(apt.Package, 'installed')
34
33
self.configuration = '/etc/default/apport'
64
63
return self._cache()[package]
66
raise ValueError, 'package does not exist'
65
raise ValueError('package does not exist')
68
67
def get_version(self, package):
69
68
'''Return the installed version of a package.'''
71
70
pkg = self._apt_pkg(package)
73
if not pkg.isInstalled:
74
raise ValueError, 'package does not exist'
75
return pkg.installedVersion
79
raise ValueError, 'package does not exist'
73
raise ValueError('package does not exist')
82
76
def get_available_version(self, package):
83
77
'''Return the latest available version of a package.'''
86
return self._apt_pkg(package).candidateVersion
88
return self._apt_pkg(package).candidate.version
79
return self._apt_pkg(package).candidate.version
90
81
def get_dependencies(self, package):
91
82
'''Return a list of packages a package depends on.'''
100
91
def get_source(self, package):
101
92
'''Return the source package name for a package.'''
104
return self._apt_pkg(package).sourcePackageName
94
if self._apt_pkg(package).installed:
95
return self._apt_pkg(package).installed.source_name
96
elif self._apt_pkg(package).candidate:
97
return self._apt_pkg(package).candidate.source_name
106
if self._apt_pkg(package).installed:
107
return self._apt_pkg(package).installed.source_name
108
elif self._apt_pkg(package).candidate:
109
return self._apt_pkg(package).candidate.source_name
111
raise ValueError, 'package %s does not exist' % package
99
raise ValueError('package %s does not exist' % package)
113
101
def is_distro_package(self, package):
114
102
'''Check if a package is a genuine distro package (True) or comes from
122
110
pkg = self._apt_pkg(package)
123
111
# some PPA packages have installed version None, see LP#252734
125
if pkg.isInstalled and pkg.installedVersion is None:
128
if pkg.installed and pkg.installed.version is None:
112
if pkg.installed and pkg.installed.version is None:
131
115
native_origins = [this_os]
143
origins = pkg.candidateOrigin
145
origins = pkg.candidate.origins
126
origins = pkg.candidate.origins
146
127
if origins: # might be None
147
128
for o in origins:
148
129
if o.origin in native_origins:
155
136
This might differ on multiarch architectures (e. g. an i386 Firefox
156
137
package on a x86_64 system)'''
159
return self._apt_pkg(package).architecture or 'unknown'
139
if self._apt_pkg(package).installed:
140
return self._apt_pkg(package).installed.architecture or 'unknown'
141
elif self._apt_pkg(package).candidate:
142
return self._apt_pkg(package).candidate.architecture or 'unknown'
161
if self._apt_pkg(package).installed:
162
return self._apt_pkg(package).installed.architecture or 'unknown'
163
elif self._apt_pkg(package).candidate:
164
return self._apt_pkg(package).candidate.architecture or 'unknown'
166
raise ValueError, 'package %s does not exist' % package
144
raise ValueError('package %s does not exist' % package)
168
146
def get_files(self, package):
169
147
'''Return list of files shipped by a package.'''
198
176
# ignore lines with NUL bytes (happens, LP#96050)
200
print >> sys.stderr, 'WARNING:', sumfile, 'contains NUL character, ignoring line'
178
apport.warning('%s contains NUL character, ignoring line', sumfile)
202
180
words = line.split()
204
print >> sys.stderr, 'WARNING:', sumfile, 'contains empty line, ignoring line'
182
apport.warning('%s contains empty line, ignoring line', sumfile)
206
184
s = os.stat('/' + words[-1])
207
185
if max(s.st_mtime, s.st_ctime) <= max_time:
364
342
debug_pkgname = 'linux-image-debug-%s' % kver
365
343
c = self._cache()
366
344
if c.has_key(debug_pkgname) and c[debug_pkgname].isInstalled:
367
#print 'kernel ddeb already installed'
345
#print('kernel ddeb already installed')
368
346
return (installed, outdated)
369
347
target_dir = apt_pkg.Config.FindDir('Dir::Cache::archives')+'/partial'
370
348
deb = '%s_%s_%s.ddeb' % (debug_pkgname, ver, arch)
416
394
c.open(apt.progress.OpProgress())
417
except SystemError, e:
395
except SystemError as e:
418
396
if 'Hash Sum mismatch' in str(e):
419
397
# temporary archive inconsistency
420
print >> sys.stderr, str(e), 'aborting'
398
apport.error('%s, aborting' % str(e))
421
399
sys.exit(99) # signal crash digger about transient error
424
402
except apt.cache.LockFailedException:
425
403
if os.geteuid() != 0:
426
print >> sys.stderr, 'WARNING: Could not update apt, you need to be root'
404
apport.error('Could not update apt, you need to be root')
440
418
(pkg, version) = l.split()[:2]
441
419
except ValueError:
442
print >> sys.stderr, 'WARNING: invalid Package/Dependencies line: ', l
420
apport.warning('invalid Package/Dependencies line: %s', l)
443
421
# invalid line, ignore
445
423
dependency_versions[pkg] = version
448
426
dependency_versions[pkg+'-dbg'] = dependency_versions[pkg]
449
427
dependency_versions[pkg+'-dbgsym'] = dependency_versions[pkg]
450
428
except ValueError:
451
print >> sys.stderr, 'WARNING: package %s not known to package cache' % pkg
429
apport.warning('package %s not known to package cache', pkg)
453
431
for pkg, ver in dependency_versions.iteritems():
454
432
if not c.has_key(pkg):
455
print >> sys.stderr, 'WARNING: package %s not available' % pkg
433
apport.warning('package %s not available', pkg)
458
436
# ignore packages which are already installed in the right version
460
if (ver and c[pkg].isInstalled and c[pkg].installedVersion ==\
461
ver) or (not ver and c[pkg].isInstalled):
464
if (ver and c[pkg].installed and c[pkg].installed.version ==\
465
ver) or (not ver and c[pkg].installed):
437
if (ver and c[pkg].installed and c[pkg].installed.version ==\
438
ver) or (not ver and c[pkg].installed):
468
441
candidate_version = None
470
candidate_version = c[pkg].candidateVersion
472
candidate_version = c[pkg].candidate.version
442
candidate_version = c[pkg].candidate.version
473
443
if ver and candidate_version != ver:
474
444
if not pkg.endswith('-dbgsym'):
475
445
outdated += '%s: installed version %s, latest version: %s\n' % (
476
446
pkg, ver, candidate_version)
477
print >> sys.stderr, 'WARNING: %s version %s required, but %s is available' % (
478
pkg, ver, candidate_version)
447
apport.warning('%s version %s required, but %s is available',
448
pkg, ver, candidate_version)
479
449
if not unpack_only:
480
450
uninstallable.append (c[pkg].name)
503
473
c.commit(fetchProgress, installProgress)
504
474
except SystemError:
505
print >> sys.stderr, 'Error: Could not install all archives. If you use this tool on a production system, it is recommended to use the -u option. See --help for details.'
475
apport.fatal('Could not install all archives. If you use this tool on a production system, it is recommended to use the -u option. See --help for details.')
508
477
# after commit(), the Cache object does not empty the pending
509
478
# changes, so we need to reinitialize it to avoid applying the same
510
479
# changes again below
511
480
installed = [p.name for p in c.getChanges()]
514
483
pass # we will complain to the user later
516
485
# package hooks might reassign Package:, check that we have the originally crashing binary
518
487
if path in report and not os.path.exists(report[path]):
519
488
pkg = self.get_file_package(report[path], True)
521
print 'Installing extra package', pkg, 'to get', path
490
print('Installing extra package %s to get %s' % (pkg, path))
522
491
c[pkg].markInstall(False)
524
493
err = 'current version of package %s does not contain the program %s any more' % (report['Package'], path)
525
494
outdated += err + '\n'
526
print >> sys.stderr, 'WARNING:', err
528
497
# check list of libraries that the crashed process referenced at
529
498
# runtime and warn about those which are not available
547
516
if not os.path.exists(l):
548
517
if pkg in uninstallable:
549
print >> sys.stderr, 'WARNING: %s cannot be installed (incompatible version)' % pkg
518
apport.warning('%s cannot be installed (incompatible version)', pkg)
551
520
if c.has_key(pkg):
552
521
c[pkg].markInstall(False)
554
print >> sys.stderr, 'WARNING: %s was loaded at runtime, but its package %s is not available' % (l, pkg)
523
apport.warning('%s was loaded at runtime, but its package %s is not available', l, pkg)
556
525
if c.has_key(pkg+'-dbgsym') and pkg+'-dbgsym' not in uninstallable :
557
526
c[pkg+'-dbgsym'].markInstall(False)
559
print >> sys.stderr, 'WARNING: %s-dbgsym is not available or is incompatible' % pkg
528
apport.warning('%s-dbgsym is not available or is incompatible', pkg)
561
print >> sys.stderr, 'WARNING: %s is needed, but cannot be mapped to a package' % l
530
apport.warning('%s is needed, but cannot be mapped to a package', l)
564
533
if c.getChanges():
569
538
c.commit(fetchProgress, installProgress)
570
539
installed += [p.name for p in c.getChanges()]
571
except (SystemError, IOError), e:
572
print >> sys.stderr, 'WARNING: could not install missing packages:', e
540
except (SystemError, IOError) as e:
541
apport.warning('could not install missing packages: %s', str(e))
573
542
if os.geteuid() != 0:
574
print >> sys.stderr, 'You either need to call this program as root or install these packages manually:'
543
apport.error('You either need to call this program as root or install these packages manually:')
575
544
for p in c.getChanges():
577
print >> sys.stderr, ' %s %s' % (p.name,
580
print >> sys.stderr, ' %s %s' % (p.name,
545
apport.error(' %s %s', p.name, p.candidate.version)
583
547
return (installed, outdated)
613
577
if dpkg.returncode == 0:
616
raise ValueError, 'package does not exist'
580
raise ValueError('package does not exist')
618
582
def _check_files_md5(self, sumfile):
619
583
'''Internal function for calling md5sum.
795
759
pm = apt.apt_pkg.GetPackageManager(cache._depcache)
797
761
res = cache._fetchArchives(fetcher, pm)
799
print >> sys.stderr, 'ERROR: could not fetch all archives:', e
763
apport.error('could not fetch all archives: %s', str(e))
807
771
for i in fetcher.Items:
809
print 'Extracting', i.DestFile
773
print('Extracting ' + i.DestFile)
810
774
if subprocess.call(['dpkg', '-x', i.DestFile, '/'], stdout=so,
811
775
stderr=subprocess.STDOUT) != 0:
812
print >> sys.stderr, 'WARNING: %s failed to extract' % i.DestFile
776
apport.warning('%s failed to extract', i.DestFile)
814
778
res = subprocess.call(['dpkg', '--force-depends', '--force-overwrite', '--unpack'] +
815
779
[klass.deb_without_preinst(i.DestFile) for i in fetcher.Items], stdout=so)
817
raise IOError, 'dpkg failed to unpack archives'
781
raise IOError('dpkg failed to unpack archives')
819
783
# remove other maintainer scripts
820
784
for c in cache.getChanges():
875
839
def test_get_version(self):
876
840
'''get_version().'''
878
self.assert_(impl.get_version('libc6').startswith('2'))
842
self.assertTrue(impl.get_version('libc6').startswith('2'))
879
843
self.assertRaises(ValueError, impl.get_version, 'nonexisting')
880
844
self.assertRaises(ValueError, impl.get_version, 'wukrainian')
882
846
def test_get_available_version(self):
883
847
'''get_available_version().'''
885
self.assert_(impl.get_available_version('libc6').startswith('2'))
849
self.assertTrue(impl.get_available_version('libc6').startswith('2'))
886
850
self.assertRaises(ValueError, impl.get_available_version, 'nonexisting')
888
852
def test_get_dependencies(self):
891
855
# package with both Depends: and Pre-Depends:
892
856
d = impl.get_dependencies('bash')
893
self.assert_(len(d) > 2)
894
self.assert_('libc6' in d)
857
self.assertTrue(len(d) > 2)
858
self.assertTrue('libc6' in d)
896
self.assert_(impl.get_version(dep))
860
self.assertTrue(impl.get_version(dep))
898
862
# Pre-Depends: only
899
863
d = impl.get_dependencies('coreutils')
900
self.assert_(len(d) >= 1)
901
self.assert_('libc6' in d)
864
self.assertTrue(len(d) >= 1)
865
self.assertTrue('libc6' in d)
903
self.assert_(impl.get_version(dep))
867
self.assertTrue(impl.get_version(dep))
906
870
d = impl.get_dependencies('libc6')
907
self.assert_(len(d) >= 1)
871
self.assertTrue(len(d) >= 1)
909
self.assert_(impl.get_version(dep))
873
self.assertTrue(impl.get_version(dep))
911
875
def test_get_source(self):
912
876
'''get_source().'''
914
878
self.assertRaises(ValueError, impl.get_source, 'nonexisting')
915
879
self.assertEqual(impl.get_source('bash'), 'bash')
916
self.assert_('glibc' in impl.get_source('libc6'))
880
self.assertTrue('glibc' in impl.get_source('libc6'))
918
882
def test_is_distro_package(self):
919
883
'''is_distro_package().'''
921
885
self.assertRaises(ValueError, impl.is_distro_package, 'nonexisting')
922
self.assert_(impl.is_distro_package('bash'))
886
self.assertTrue(impl.is_distro_package('bash'))
923
887
# no False test here, hard to come up with a generic one
925
889
def test_get_architecture(self):
937
901
'''get_files().'''
939
903
self.assertRaises(ValueError, impl.get_files, 'nonexisting')
940
self.assert_('/bin/bash' in impl.get_files('bash'))
904
self.assertTrue('/bin/bash' in impl.get_files('bash'))
942
906
def test_get_file_package(self):
943
907
'''get_file_package() on installed files.'''
961
925
mapdir = os.path.join(basedir, 'dists', release_name)
962
926
os.makedirs(mapdir)
963
print >> gzip.open(os.path.join(mapdir, 'Contents-%s.gz' %
964
impl.get_system_architecture()), 'w'), '''
927
f = gzip.open(os.path.join(mapdir, 'Contents-%s.gz' %
928
impl.get_system_architecture()), 'w')
967
932
usr/bin/frobnicate foo/frob
968
933
usr/bin/frob foo/frob-utils
969
934
bo/gu/s na/mypackage
972
938
self.assertEqual(impl.get_file_package('usr/bin/frob', False, mapdir), None)
973
939
# must not match frob (same file name prefix)
988
954
os.mkdir(cache_dir)
989
955
self.assertEqual(impl.get_file_package('usr/bin/frob', True, cache_dir), 'frob-utils')
990
956
self.assertEqual(len(os.listdir(cache_dir)), 1)
991
self.assert_(os.listdir(cache_dir)[0].startswith('Contents-'))
957
self.assertTrue(os.listdir(cache_dir)[0].startswith('Contents-'))
992
958
self.assertEqual(impl.get_file_package('/bo/gu/s', True, cache_dir), 'mypackage')
994
960
shutil.rmtree(basedir)
1014
980
arch = impl.get_system_architecture()
1015
981
# must be nonempty without line breaks
1016
982
self.assertNotEqual(arch, '')
1017
self.assert_('\n' not in arch)
983
self.assertTrue('\n' not in arch)
1019
985
def test_compare_versions(self):
1020
986
'''compare_versions.'''
1056
1022
def test_get_kernel_pacakge(self):
1057
1023
'''get_kernel_package().'''
1059
self.assert_('linux' in impl.get_kernel_package())
1025
self.assertTrue('linux' in impl.get_kernel_package())
1061
1027
def test_package_name_glob(self):
1062
1028
'''package_name_glob().'''
1064
self.assert_(len(impl.package_name_glob('a*')) > 5)
1065
self.assert_('bash' in impl.package_name_glob('ba*h'))
1030
self.assertTrue(len(impl.package_name_glob('a*')) > 5)
1031
self.assertTrue('bash' in impl.package_name_glob('ba*h'))
1066
1032
self.assertEqual(impl.package_name_glob('bash'), ['bash'])
1067
1033
self.assertEqual(impl.package_name_glob('xzywef*'), [])