Added some code to peer into a data structure in Maemian/Schedule.pm. Also added the
[maemian] / nokia-lintian / depcheck / dependencies.py
1 #!/usr/bin/python
2
3 # Copyright (C) 1998 Richard Braakman
4 #
5 # This program is free software.  It is distributed under the terms of
6 # the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any
8 # later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, you can find it on the World Wide
17 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
18 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
20
21 import string
22
23 import package
24 from relation import Virtual
25 import version
26
27 # Create a dictionary of the available packages, including provided
28 # virtual packages.  The dictionary maps package names to versions.
29 def packagedict(packages):
30     pkdict = {}
31     for pk in packages.values():
32         pkdict[pk['name']] = pk['version']
33         for provided in pk['provides']:
34             if not pkdict.has_key(provided):
35                 pkdict[provided] = Virtual
36     return pkdict
37
38 def satisfy(relations, pkdict):
39     failed = []
40     for rel in relations:
41         needs = rel.satisfied_by(pkdict)
42         if needs is None:
43             failed.append(rel)
44     return failed
45     # Future dreams: check if the depended-on packages don't conflict.
46
47 def failure(name, rels, singular, plural):
48     use = singular
49     if len(rels) > 1:
50         use = plural
51     deps = string.join(map(str, rels), ', ')
52     return '%s: %s %s' % (name, use, deps)
53
54 def delete_relations(pk, relation, deletions):
55     for rel in deletions:
56         pk[relation].remove(rel)
57
58 def test_packages(packages):
59     pkdict = packagedict(packages)
60     warnings = []
61     for pk in packages.values():
62         if pk.has_key('depends'):
63             fl = satisfy(pk['depends'], pkdict)
64             if fl:
65                 warnings.append(failure(pk['name'], fl, 'dependency', 'dependencies'))
66                 delete_relations(pk, 'depends', fl)
67         if pk.has_key('recommends'):
68             fl = satisfy(pk['recommends'], pkdict)
69             if fl:
70                 warnings.append(failure(pk['name'], fl, 'recommendation', 'recommendations'))
71                 delete_relations(pk, 'recommends', fl)
72         if pk.has_key('pre-depends'):
73             fl = satisfy(pk['pre-depends'], pkdict)
74             if fl:
75                 warnings.append(failure(pk['name'], fl, 'pre-dependency', 'pre-dependencies'))
76                 delete_relations(pk, 'pre-depends', fl)
77     warnings.sort()
78     return warnings
79
80 def tosubtract(warning):
81     return warning not in subtract
82
83 def print_warnings(warnings, header):
84     warnings = filter(tosubtract, warnings)
85     if len(warnings):
86         print header + "\n"
87         for warning in warnings:
88             print "  " + warning
89         print ""
90
91
92 def test(packagefile):
93     filter = ['package', 'version', 'depends', 'recommends', 'provides',
94               'pre-depends', 'priority', 'section']
95     allpackages = package.parsepackages(open(packagefile), filter)
96     priorities = {'required': {}, 'important': {}, 'standard': {},
97                   'optional': {}, 'extra': {}}
98     for pk in allpackages.values():
99         priorities[pk['priority']][pk['name']] = pk
100
101     packages = allpackages
102     print_warnings(test_packages(packages),
103                    "Cannot satisfy with packages in main:");
104
105     # packages-in-base check moved up to here, because otherwise some
106     # of them will show up as "Cannot satisfy with required packages".
107     for pk in packages.keys():
108         if packages[pk]['section'] != 'base':
109             del packages[pk]
110     print_warnings(test_packages(packages),
111                    "Cannot satisfy with packages in base:");
112
113     packages = priorities['required']
114     print_warnings(test_packages(packages),
115                    "Cannot satisfy with required packages:");
116
117     packages.update(priorities['important'])
118     print_warnings(test_packages(packages),
119                    "Cannot satisfy with important packages:");
120
121     packages.update(priorities['standard'])
122     print_warnings(test_packages(packages),
123                    "Cannot satisfy with standard packages:");
124
125     packages.update(priorities['optional'])
126     print_warnings(test_packages(packages),
127                    "Cannot satisfy with optional packages:");
128
129     packages.update(priorities['extra'])
130     print_warnings(test_packages(packages),
131                    "Cannot satisfy with extra packages:");
132
133     for pk in packages.keys():
134         if packages[pk]['section'] == 'oldlibs':
135             del packages[pk]
136     print_warnings(test_packages(packages),
137                    "Cannot satisfy without packages in oldlibs:");
138
139 import sys
140
141 if len(sys.argv) == 3:
142    subtract = []
143    for line in open(sys.argv[2]).readlines():
144      subtract.append(line[2:-1])
145 else:
146    subtract = [];
147
148    
149
150 if len(sys.argv) > 1:
151    test(sys.argv[1])
152 else:
153    test("/var/lib/dpkg/methods/ftp/Packages.hamm_main")