30
31:- module(cpack_dependency,
32 [ file_used_by_file_in_package/3, 33 cpack_requires/3, 34 cpack_conflicts/3, 35 cpack_list/2, 36 cpack_list/3, 37 cpack_not_satisfied/2, 38 file_not_satisfied/2, 39 file_imports_from/3, 40 file_calls_public_from/3 41 ]). 42:- use_module(library(assoc)). 43:- use_module(library(ugraphs)). 44:- use_module(library(semweb/rdf_db)). 45:- use_module(library(semweb/rdfs)). 46:- use_module(repository).
68file_used_by_file_in_package(File, UsedBy, Pack) :-
69 rdf_has(File, cpack:resolves, FileRef),
70 rdf_has(UsedBy, cpack:usesFile, FileRef),
71 rdf_has(UsedBy, cpack:inPack, Pack).
84cpack_requires(Package, Required, AllReasons) :-
85 setof(Why, cpack_requires_by(Package, Required, Why), AllReasons).
86
87cpack_requires_by(Package, Required, token(Token)) :-
88 rdf_has(Package, cpack:requires, Req),
89 ( rdf_is_literal(Req)
90 -> Token = Req
91 ; rdf_has(Req, cpack:name, Token)
92 ),
93 rdf_has(Required, cpack:provides, Token).
94
95cpack_requires_by(Package, Required, file_ref(FileRef)) :-
96 rdf_has(File, cpack:inPack, Package),
97 rdf_has(File, cpack:usesFile, FileRef),
98 rdf_has(ReqFile, cpack:resolves, FileRef),
99 rdf_has(ReqFile, cpack:inPack, Required),
100 Required \== Package.
116cpack_conflicts(Package, Conflict, AllReasons) :-
117 setof(Why, cpack_conflicts_by(Package, Conflict, Why), AllReasons).
118
119cpack_conflicts_by(Package, Conflict, same_module(M,File1,File2)) :-
120 rdf_has(File1, cpack:module, Module),
121 rdf_has(File2, cpack:module, Module),
122 File1 \== File2,
123 Module = literal(M),
124 rdf_has(Package, cpack:in_file, File1),
125 rdf_has(Conflict, cpack:in_file, File2).
126cpack_conflicts_by(Package, Conflict, same_file(Path,File1,File2)) :-
127 rdf_has(File1, cpack:path, LPath),
128 rdf_has(File2, cpack:path, LPath),
129 File1 \== File2,
130 LPath = literal(Path),
131 rdf_has(Package, cpack:in_file, File1),
132 rdf_has(Conflict, cpack:in_file, File2).
133
134
135
157cpack_list(Pack, Packs) :-
158 cpack_list(Pack, Packs, _).
159
160cpack_list(Pack, Packs, Ugraph) :-
161 dependency_ugraph(Pack, Ugraph),
162 ( sort_dependencies(Ugraph, Packs)
163 -> check_conflicts(Packs)
165 ; domain_error(non_cyclic_dependency_structure, Ugraph)
166 ).
167
168check_conflicts(Packs) :-
169 append(_,[P1|Rest], Packs),
170 cpack_conflicts(P1, Conflict, Reasons),
171 member(Conflict, Rest), !,
172 throw(error(cpack_error(conflict(P1, Conflict, Reasons)), _)).
173check_conflicts(_).
174
175check_satisfied(Packs) :-
176 maplist(cpack_satisfied, Packs).
177
178cpack_satisfied(Pack) :-
179 cpack_not_satisfied(Pack, Reasons), !,
180 throw(error(cpack_error(not_satisfied(Pack, Reasons)), _)).
181cpack_satisfied(_).
187dependency_ugraph(Pack, UGraph) :-
188 ( is_list(Pack)
189 -> Agenda = Pack
190 ; Agenda = [Pack]
191 ),
192 empty_assoc(Visited),
193 dependency_ugraph(Agenda, Visited, Graph),
194 keysort(Graph, UGraph).
195
196dependency_ugraph([], _, []).
197dependency_ugraph([H|T], Visited, Graph) :-
198 ( get_assoc(H, Visited, _)
199 -> dependency_ugraph(T, Visited, Graph)
200 ; findall(Required, cpack_requires(H, Required, _), RList0),
201 sort(RList0, RList),
202 Graph = [H-RList|More],
203 put_assoc(H, Visited, true, Visited2),
204 append(RList, T, Agenda),
205 dependency_ugraph(Agenda, Visited2, More)
206 ).
212sort_dependencies(Graph, List) :-
213 top_sort(Graph, RList), !,
214 reverse(RList, List).
215sort_dependencies(Graph, List) :-
216 connect_graph(Graph, Start, Connected),
217 top_sort(Connected, [Start|RList]), !,
218 reverse(RList, List).
225connect_graph([], 0, []) :- !.
226connect_graph(Graph, Start, [Start-Vertices|Graph]) :-
227 vertices(Graph, Vertices),
228 Vertices = [First|_],
229 before(First, Start).
238before(X, _) :-
239 var(X), !,
240 instantiation_error(X).
241before(Number, Start) :-
242 number(Number), !,
243 Start is Number - 1.
244before(_, 0).
245
246
247
255cpack_not_satisfied(Pack, AllReasons) :-
256 setof(Due, cpack_not_satisfied_due(Pack, Due), AllReasons).
257
258cpack_not_satisfied_due(Package, no_token(Token)) :-
259 rdf_has(Package, cpack:requires, Req),
260 ( rdf_is_literal(Req)
261 -> Token = Req
262 ; rdf_has(Req, cpack:name, Token)
263 ),
264 \+ rdf_has(_, cpack:provides, Token).
265cpack_not_satisfied_due(Package, file(File, Problems)) :-
266 rdf_has(File, cpack:inPack, Package),
267 file_not_satisfied(File, Problems).
274file_not_satisfied(File, AllReasons) :-
275 setof(Due, file_not_satisfied_due(File, Due), AllReasons).
298file_not_satisfied_due(File, file_not_found(FileRef)) :-
299 rdf_has(File, cpack:usesFile, FileRef),
300 rdfs_individual_of(FileRef, cpack:'FileRef'),
301 \+ rdf_has(_, cpack:resolves, FileRef).
302file_not_satisfied_due(File, predicate_not_found(PI)) :-
303 LPI = literal(PI),
304 rdf_has(File, cpack:requiresPredicate, LPI),
305 \+ file_imports_pi_from(File, _, PI),
306 \+ file_calls_public_from(File, _, PI),
307 \+ other_source(PI).
308
309other_source(API) :-
310 atom_to_term(API, PI, []),
311 pi_head(PI, Head),
312 ( predicate_property(Head, multifile)
313 ; predicate_property(Head, autoload(_))
314 ; predicate_property(Head, public)
315 ), !.
316
317pi_head(M:PI, M:Head) :- !,
318 pi_head(PI, Head).
319pi_head(Name/Arity, Head) :-
320 functor(Head, Name, Arity).
329file_imports_from(File, PIs, From) :-
330 setof(PI, file_imports_pi_from(File, From, PI), PIs).
331
332file_imports_pi_from(File, UsedFile, PI) :-
333 rdf_has(File, cpack:usesFile, Uses),
334 ( rdfs_individual_of(Uses, cpack:'FileRef')
335 -> rdf_has(UsedFile, cpack:resolves, Uses)
336 ; UsedFile = Uses
337 ),
338 rdf_has(UsedFile, cpack:exportsPredicate, literal(PI)).
345file_calls_public_from(File, UsedFile, PI) :-
346 ( rdf_has(UsedFile, cpack:publicPredicate, literal(PI))
347 -> true
348 ; atom_to_term(PI, M:PPI, []),
349 rdf_has(UsedFile, cpack:module, literal(M)),
350 format(atom(Plain), '~q', [PPI]),
351 ( rdf_has(UsedFile, cpack:exportsPredicate, literal(Plain))
352 -> true
353 ; rdf_has(UsedFile, cpack:publicPredicate, literal(Plain))
354 )
355 ),
356 ( rdf_has(File, cpack:usesFile, UsedFile)
357 -> true
358 ; rdf_has(UsedFile, cpack:resolves, Uses),
359 rdf_has(File, cpack:usesFile, Uses)
360 ), !
Query the CPACK dependency graph
This module queries the RDF graph produced by
xref.pl
to compute high-level dependencies between objects. Currently, we keep track of: