35
36:- module('$pack',
37 [ attach_packs/0,
38 attach_packs/1, 39 attach_packs/2, 40 '$pack_detach'/2, 41 '$pack_attach'/1 42 ]). 43
44:- multifile user:file_search_path/2. 45:- dynamic user:file_search_path/2. 46
47:- dynamic
48 pack_dir/3, 49 pack/2. 50:- volatile
51 pack_dir/3,
52 pack/2. 53
54user:file_search_path(pack, app_data(pack)).
55
56user:file_search_path(library, PackLib) :-
57 pack_dir(_Name, prolog, PackLib).
58user:file_search_path(foreign, PackLib) :-
59 pack_dir(_Name, foreign, PackLib).
60
65
66'$pack_detach'(Name, Dir) :-
67 ( atom(Name)
68 -> true
69 ; throw(error(type_error(atom, Name), _))
70 ),
71 ( retract(pack(Name, Dir))
72 -> retractall(pack_dir(Name, _, _)),
73 reload_library_index
74 ; throw(error(existence_error(pack, Name), _))
75 ).
76
80
81'$pack_attach'(Dir) :-
82 attach_package(Dir, []),
83 !.
84'$pack_attach'(Dir) :-
85 ( exists_directory(Dir)
86 -> throw(error(existence_error(directory, Dir), _))
87 ; throw(error(domain_error(pack, Dir), _))
88 ).
89
93
94attach_packs :-
95 set_prolog_flag(packs, true),
96 findall(PackDir, absolute_file_name(pack(.), PackDir,
97 [ file_type(directory),
98 access(read),
99 solutions(all)
100 ]),
101 PackDirs),
102 ( PackDirs \== []
103 -> remove_dups(PackDirs, UniquePackDirs, []),
104 forall('$member'(PackDir, UniquePackDirs),
105 attach_packs(PackDir))
106 ; true
107 ).
108
112
113remove_dups([], [], _).
114remove_dups([H|T0], T, Seen) :-
115 memberchk(H, Seen),
116 !,
117 remove_dups(T0, T, Seen).
118remove_dups([H|T0], [H|T], Seen) :-
119 remove_dups(T0, T, [H|Seen]).
120
121
139
140attach_packs(Dir) :-
141 attach_packs(Dir, []).
142
143attach_packs(Dir, Options) :-
144 absolute_file_name(Dir, Path,
145 [ file_type(directory),
146 file_errors(fail)
147 ]),
148 catch(directory_files(Path, Entries), _, fail),
149 !,
150 ensure_slash(Path, SPath),
151 attach_packages(Entries, SPath, Options).
152attach_packs(_, _).
153
154attach_packages([], _, _).
155attach_packages([H|T], Dir, Options) :-
156 attach_package(H, Dir, Options),
157 attach_packages(T, Dir, Options).
158
159attach_package(Entry, Dir, Options) :-
160 \+ special(Entry),
161 atom_concat(Dir, Entry, PackDir),
162 attach_package(PackDir, Options),
163 !.
164attach_package(_, _, _).
165
166special(.).
167special(..).
168
169
173
174attach_package(PackDir, Options) :-
175 atomic_list_concat([PackDir, '/pack.pl'], InfoFile),
176 access_file(InfoFile, read),
177 file_base_name(PackDir, Pack),
178 check_existing(Pack, PackDir, Options),
179 foreign_dir(Pack, PackDir, ForeignDir),
180 prolog_dir(PackDir, PrologDir),
181 !,
182 assertz(pack(Pack, PackDir)),
183 '$option'(search(Where), Options, last),
184 ( Where == last
185 -> assertz(pack_dir(Pack, prolog, PrologDir))
186 ; Where == first
187 -> asserta(pack_dir(Pack, prolog, PrologDir))
188 ; '$domain_error'(option_search, Where)
189 ),
190 update_autoload(PrologDir),
191 ( ForeignDir \== (-)
192 -> assertz(pack_dir(Pack, foreign, ForeignDir))
193 ; true
194 ),
195 print_message(silent, pack(attached(Pack, PackDir))).
196
197
201
202check_existing(Entry, Dir, _) :-
203 retract(pack(Entry, Dir)), 204 !,
205 retractall(pack_dir(Entry, _, _)).
206check_existing(Entry, Dir, Options) :-
207 pack(Entry, OldDir),
208 !,
209 '$option'(duplicate(Action), Options, warning),
210 ( Action == warning
211 -> print_message(warning, pack(duplicate(Entry, OldDir, Dir))),
212 fail
213 ; Action == keep
214 -> fail
215 ; Action == replace
216 -> print_message(silent, pack(replaced(Entry, OldDir, Dir))),
217 '$pack_detach'(Entry, OldDir)
218 ; '$domain_error'(option_duplicate, Action)
219 ).
220check_existing(_, _, _).
221
222
223prolog_dir(PackDir, PrologDir) :-
224 atomic_list_concat([PackDir, '/prolog'], PrologDir),
225 exists_directory(PrologDir).
226
227update_autoload(PrologDir) :-
228 atom_concat(PrologDir, '/INDEX.pl', IndexFile),
229 ( exists_file(IndexFile)
230 -> reload_library_index
231 ; true
232 ).
233
234foreign_dir(Pack, PackDir, ForeignDir) :-
235 current_prolog_flag(arch, Arch),
236 atomic_list_concat([PackDir, '/lib'], ForeignBaseDir),
237 exists_directory(ForeignBaseDir),
238 !,
239 atomic_list_concat([PackDir, '/lib/', Arch], ForeignDir),
240 ( exists_directory(ForeignDir)
241 -> assertz(pack_dir(Pack, foreign, ForeignDir))
242 ; print_message(warning, pack(no_arch(Pack, Arch))),
243 fail
244 ).
245foreign_dir(_, _, (-)).
246
247ensure_slash(Dir, SDir) :-
248 ( sub_atom(Dir, _, _, 0, /)
249 -> SDir = Dir
250 ; atom_concat(Dir, /, SDir)
251 )