summaryrefslogtreecommitdiff
path: root/multiarchanalyze.sql
blob: 79d62c3d0f5cdce45d74c799e97a6a2d88aa83ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
CREATE INDEX IF NOT EXISTS depends_dependee_index ON depends(dependee);
CREATE INDEX IF NOT EXISTS content_filename_index ON content(filename);

BEGIN;

/* Combinations of two packages and files with conflicting content. */
DROP VIEW IF EXISTS contentconflict;
CREATE VIEW contentconflict AS
	SELECT p1.id AS pid1,
		p2.id AS pid2,
		p1.name AS name1,
		p2.name AS name2,
		p1.version AS version1,
		p2.version AS version2,
		p1.architecture AS architecture1,
		p2.architecture AS architecture2,
		p1.source AS source1,
		p2.source AS source2,
		p1.hasscripts AS hasscripts1,
		p2.hasscripts AS hasscripts2,
		p1.multiarch AS multiarch1,
		p2.multiarch AS multiarch2,
		c1.filename,
		c1.id AS cid1,
		c2.id AS cid2,
		c1.hash AS hash1,
		c2.hash AS hash2
	FROM package AS p1, package AS p2, content AS c1, content AS c2
	WHERE p1.id = c1.pid
		AND p2.id = c2.pid
		AND c1.filename = c2.filename
		AND c1.hash != c2.hash;

/* Candidates for satisfying architecture-enforcing dependencies considering
 * provides. */
DROP VIEW IF EXISTS archdepcandidate;
CREATE VIEW archdepcandidate AS
	SELECT p1.id AS dependerid, p2.id AS dependeeid,
		p2.multiarch IS 'same' AS ismasame
	FROM package AS p1, depends AS d, package AS p2
	WHERE p1.id = d.pid
		AND d.dependee = p2.name
		AND p2.multiarch IS NOT 'foreign'
		AND (p2.multiarch IS NOT 'allowed' OR d.archqual IS NOT 'any')
		AND (p1.architecture = p2.architecture
			OR p1.architecture = 'all'
			OR p2.architecture = 'all'
			OR p2.architecture = d.archqual)
	UNION ALL
	SELECT p1.id AS dependerid, p2.id AS dependeeid,
		p2.multiarch IS 'same' AS ismasame
	FROM package AS p1, depends AS d, provides AS r, package AS p2
	WHERE p1.id = d.pid
		AND d.dependee = r.provided
		AND r.pid = p2.id
		AND p2.multiarch IS NOT 'foreign'
		AND (p2.multiarch IS NOT 'allowed' OR d.archqual IS NOT 'any')
		AND (p1.architecture = p2.architecture
			OR p1.architecture = 'all'
			OR p2.architecture = 'all'
			OR p2.architecture = d.archqual);

/* Describe properties of binary package names. */
DROP VIEW IF EXISTS packageapi;
CREATE VIEW packageapi AS
	SELECT name,
		count(*) AS instances,
		count(CASE architecture WHEN 'all' THEN 1 ELSE NULL END)
			AS hasindep,
		CASE count(CASE architecture WHEN 'all' THEN NULL ELSE 1 END)
			WHEN 0 THEN 0 ELSE 1 END
			AS hasarchdep,
		CASE min(source) WHEN max(source) THEN source ELSE NULL END
			AS source,
		max(hasscripts) AS hasscripts,
		CASE min(multiarch)
			WHEN max(multiarch) THEN multiarch
			ELSE NULL END
			AS multiarch
	FROM package GROUP BY name;

/* Architecture-dependent packages. */
DROP VIEW IF EXISTS archpackage;
CREATE VIEW archpackage AS
	SELECT
		p1.name,
		p1.hasscripts,
	       	p1.multiarch,
		exists(
			SELECT 1 FROM package AS p2, archdepcandidate AS c
			WHERE p2.name = p1.name AND c.dependerid = p2.id)
			AS hasarchdeps,
		exists(
			SELECT 1 FROM package AS p2, archdepcandidate AS c
			WHERE p2.name = p1.name AND c.dependerid = p2.id
				AND NOT c.ismasame) AS hasnoncoinstdeps
	FROM packageapi AS p1
	WHERE p1.instances >= 3 AND p1.hasindep = 0;

/* Architecture-independent packages. */
DROP VIEW IF EXISTS indeppackage;
CREATE VIEW indeppackage AS
	SELECT
		id,
		name,
		version,
		source,
		hasscripts,
		multiarch,
		exists(SELECT 1 FROM archdepcandidate WHERE dependerid = id)
			AS hasarchdeps
	FROM package
	WHERE architecture = 'all';

/* Packages violating M-A:same by shipping conflicting files. */
DROP VIEW IF EXISTS masame_conflict;
CREATE VIEW masame_conflict AS
	SELECT name1 AS name, version1 AS version, architecture1, architecture2, filename
	FROM contentconflict
	WHERE name1 = name2
		AND version1 = version2
		AND multiarch1 = 'same'
		AND multiarch2 = 'same';

/* Packages that could be marked M-A:foreign, because they
 *  * are Architecture: all
 *  * do not have maintainer scripts
 *  * do not have architecture enforcing dependencies
 */
DROP VIEW IF EXISTS maforeign_candidate;
CREATE VIEW maforeign_candidate AS
	SELECT p1.name FROM indeppackage AS p1
	WHERE p1.multiarch = 'no'
		AND p1.hasscripts = 0
		AND p1.hasarchdeps = 0;

/* Packages that could be converted from Arch:any to Arch:all M-A:foreign,
 * because they
 *  * do not have maintainer scripts
 *  * do not ship conflicting files
 *  * do not ship different file sets
 *  * do not have architecture enforcing dependencies
 */
DROP VIEW IF EXISTS archall_candidate;
CREATE VIEW archall_candidate AS
	SELECT p1.name FROM archpackage AS p1
	WHERE p1.hasscripts = 0
		AND NOT EXISTS (
			SELECT 1 FROM contentconflict
			WHERE name1 = p1.name AND name2 = p1.name)
		AND NOT EXISTS (
			SELECT 1
			FROM package AS p2, content AS c2, package AS p3
			WHERE p2.name = p1.name
				AND c2.pid = p2.id
				AND p3.name = p1.name
				AND NOT EXISTS (
					SELECT 1 FROM content AS c5
					WHERE c5.pid = p3.id
						AND c5.filename = c2.filename))
		AND NOT EXISTS (
			SELECT 1
			FROM package AS p4, package AS p5, provides AS r1
			WHERE p4.name = p1.name
				AND p5.name = p1.name
				AND r1.pid = p4.id
				AND NOT EXISTS (
					SELECT 1 FROM provides AS r2
					WHERE r2.pid = p5.id
						AND r1.provided = r2.provided))
		AND p1.hasarchdeps = 0;

/* Packages that coud be marked Multi-Arch:same, because they
 *  * are architecture dependent
 *  * do not have a Multi-Arch marking
 *  * do not have maintainer scripts
 *  * do not have file conflicts
 */
DROP VIEW IF EXISTS masame_candidate;
CREATE VIEW masame_candidate AS
	SELECT p1.name FROM archpackage AS p1
	WHERE p1.multiarch = 'no'
		AND p1.hasscripts = 0
		AND NOT p1.hasnoncoinstdeps
		AND NOT EXISTS (
			SELECT 1 FROM contentconflict
			WHERE name1 = p1.name AND name2 = p1.name);

/* Package 'depender' has a dependency on 'dependee' that can be annotated with
 * :any, because
 *  * 'depender' is architecture independent
 *  * 'depender' does not have maintainer scripts
 *  * the dependency on 'dependee' is the only architecture enforcing dependency
 *  * 'dependee' is Multi-Arch: allowed
 */
DROP VIEW IF EXISTS colonany_candidate;
CREATE VIEW colonany_candidate AS
	SELECT depender, dependee
	FROM (
		SELECT
			p1.name AS depender,
			p2.name AS dependee,
			CASE max(p2.multiarch)
				WHEN min(p2.multiarch) THEN p2.multiarch
				ELSE NULL END
				AS multiarch
		FROM indeppackage AS p1, archdepcandidate AS c, package AS p2
		WHERE p1.hasscripts = 0
			AND c.dependerid = p1.id
			AND c.dependeeid = p2.id
		GROUP BY p1.id, p2.name)
	GROUP BY depender
	HAVING count(dependee) = 1
		AND min(CASE multiarch WHEN 'allowed' THEN 1 ELSE 0 END) = 1;

/* Packages that are wrongly marked Multi-Arch:foreign, because they
 *  * are architecture dependent
 *  * ship a shared library in a public path
 *  * and the library is not a plugin for a contained program
 */
DROP VIEW IF EXISTS maforeign_library;
CREATE VIEW maforeign_library AS
	SELECT DISTINCT p.name
	FROM package AS p
	WHERE architecture != 'all'
		AND multiarch = 'foreign'
		AND EXISTS (
			SELECT 1 FROM content
			WHERE pid = p.id
				AND filename REGEXP '^\./(usr/)?lib/([a-z0-9_]*-linux-gnu[a-z0-9_]*/)?lib.*\.so$')
		AND NOT EXISTS (
			SELECT 1 FROM content
			WHERE pid = p.id
				AND filename REGEXP '^\./(usr/)?s?bin/.*');

/* Packages that should employ the m-a:interpreter workaround, because they
 *  * are known to expose the architecture of their dependencies (e.g. rust libraries)
 *  * are currently architecture-independent and multiarch:foreign
 *  * have an architecture-dependent dependency
 */
DROP VIEW IF EXISTS maworkaround_packages;
CREATE VIEW maworkaround_packages AS
	SELECT name
	FROM indeppackage AS i
	WHERE name LIKE 'librust%-dev'
		AND multiarch = 'foreign'
		AND EXISTS (SELECT 1 FROM archdepcandidate WHERE dependerid = i.id);

COMMIT;