36
37:- module('$pack',
38 [ attach_packs/0,
39 attach_packs/1, 40 attach_packs/2, 41 pack_attach/2, 42 '$pack_detach'/2 43 ]). 44
45:- multifile user:file_search_path/2. 46:- dynamic user:file_search_path/2. 47
48:- dynamic
49 pack_dir/3, 50 pack/2. 51
52user:file_search_path(pack, app_data(pack)).
53
54user:file_search_path(library, PackLib) :-
55 pack_dir(_Name, prolog, PackLib).
56user:file_search_path(foreign, PackLib) :-
57 pack_dir(_Name, foreign, PackLib).
58user:file_search_path(app, AppDir) :-
59 pack_dir(_Name, app, AppDir).
66'$pack_detach'(Name, Dir) :-
67 ( atom(Name)
68 -> true
69 ; '$type_error'(atom, Name)
70 ),
71 ( retract(pack(Name, Dir))
72 -> retractall(pack_dir(Name, _, _)),
73 reload_library_index
74 ; '$existence_error'(pack, Name)
75 ).
81pack_attach(Dir, Options) :-
82 attach_package(Dir, Options),
83 !.
84pack_attach(Dir, _) :-
85 ( exists_directory(Dir)
86 -> '$existence_error'(directory, Dir)
87 ; '$domain_error'(pack, Dir)
88 ).
95attach_packs :-
96 set_prolog_flag(packs, true),
97 set_pack_search_path,
98 findall(PackDir, absolute_file_name(pack(.), PackDir,
99 [ file_type(directory),
100 access(read),
101 solutions(all)
102 ]),
103 PackDirs),
104 ( PackDirs \== []
105 -> remove_dups(PackDirs, UniquePackDirs, []),
106 forall('$member'(PackDir, UniquePackDirs),
107 attach_packs(PackDir, [duplicate(keep)]))
108 ; true
109 ).
110
111set_pack_search_path :-
112 getenv('SWIPL_PACK_PATH', Value),
113 !,
114 retractall(user:file_search_path(pack, _)),
115 current_prolog_flag(path_sep, Sep),
116 atomic_list_concat(Dirs, Sep, Value),
117 register_pack_dirs(Dirs).
118set_pack_search_path.
119
120register_pack_dirs([]).
121register_pack_dirs([H|T]) :-
122 prolog_to_os_filename(Dir, H),
123 assertz(user:file_search_path(pack, Dir)),
124 register_pack_dirs(T).
131remove_dups([], [], _).
132remove_dups([H|T0], T, Seen) :-
133 memberchk(H, Seen),
134 !,
135 remove_dups(T0, T, Seen).
136remove_dups([H|T0], [H|T], Seen) :-
137 remove_dups(T0, T, [H|Seen]).
161attach_packs(Dir) :-
162 attach_packs(Dir, []).
163
164attach_packs(Dir, Options) :-
165 ( '$option'(replace(true), Options)
166 -> forall(pack(Name, PackDir),
167 '$pack_detach'(Name, PackDir)),
168 retractall(user:file_search_path(pack, _))
169 ; true
170 ),
171 register_packs_from(Dir),
172 absolute_file_name(Dir, Path,
173 [ file_type(directory),
174 file_errors(fail)
175 ]),
176 catch(directory_files(Path, Entries), _, fail),
177 !,
178 ensure_slash(Path, SPath),
179 attach_packages(Entries, SPath, Options),
180 reload_library_index.
181attach_packs(_, _).
182
183register_packs_from(Dir) :-
184 ( user:file_search_path(pack, Dir)
185 -> true
186 ; asserta(user:file_search_path(pack, Dir))
187 ).
188
189attach_packages([], _, _).
190attach_packages([H|T], Dir, Options) :-
191 attach_package(H, Dir, Options),
192 attach_packages(T, Dir, Options).
193
194attach_package(Entry, Dir, Options) :-
195 \+ special(Entry),
196 atom_concat(Dir, Entry, PackDir),
197 attach_package(PackDir, Options),
198 !.
199attach_package(_, _, _).
200
201special(.).
202special(..).
209attach_package(PackDir, Options) :-
210 atomic_list_concat([PackDir, '/pack.pl'], InfoFile),
211 access_file(InfoFile, read),
212 file_base_name(PackDir, Pack),
213 check_existing(Pack, PackDir, Options),
214 prolog_dir(PackDir, PrologDir),
215 !,
216 assertz(pack(Pack, PackDir)),
217 '$option'(search(Where), Options, last),
218 ( Where == last
219 -> assertz(pack_dir(Pack, prolog, PrologDir))
220 ; Where == first
221 -> asserta(pack_dir(Pack, prolog, PrologDir))
222 ; '$domain_error'(option_search, Where)
223 ),
224 update_autoload(PrologDir),
225 ( foreign_dir(Pack, PackDir, ForeignDir)
226 -> assertz(pack_dir(Pack, foreign, ForeignDir))
227 ; true
228 ),
229 ( app_dir(PackDir, AppDir)
230 -> assertz(pack_dir(Pack, app, AppDir))
231 ; true
232 ),
233 print_message(silent, pack(attached(Pack, PackDir))).
240check_existing(Entry, Dir, _) :-
241 retract(pack(Entry, Dir)), 242 !,
243 retractall(pack_dir(Entry, _, _)).
244check_existing(Entry, Dir, Options) :-
245 pack(Entry, OldDir),
246 !,
247 '$option'(duplicate(Action), Options, warning),
248 ( Action == warning
249 -> print_message(warning, pack(duplicate(Entry, OldDir, Dir))),
250 fail
251 ; Action == keep
252 -> fail
253 ; Action == replace
254 -> print_message(silent, pack(replaced(Entry, OldDir, Dir))),
255 '$pack_detach'(Entry, OldDir)
256 ; '$domain_error'(option_duplicate, Action)
257 ).
258check_existing(_, _, _).
259
260
261prolog_dir(PackDir, PrologDir) :-
262 atomic_list_concat([PackDir, '/prolog'], PrologDir),
263 exists_directory(PrologDir).
264
265update_autoload(PrologDir) :-
266 atom_concat(PrologDir, '/INDEX.pl', IndexFile),
267 ( exists_file(IndexFile)
268 -> reload_library_index
269 ; true
270 ).
271
272foreign_dir(Pack, PackDir, ForeignDir) :-
273 atomic_list_concat([PackDir, '/lib'], ForeignBaseDir),
274 exists_directory(ForeignBaseDir),
275 !,
276 ( arch(Arch),
277 atomic_list_concat([PackDir, '/lib/', Arch], ForeignDir),
278 exists_directory(ForeignDir)
279 -> assertz(pack_dir(Pack, foreign, ForeignDir))
280 ; findall(Arch, arch(Arch), Archs),
281 print_message(warning, pack(no_arch(Pack, Archs))),
282 fail
283 ).
284
285arch(Arch) :-
286 current_prolog_flag(apple_universal_binary, true),
287 Arch = 'fat-darwin'.
288arch(Arch) :-
289 current_prolog_flag(arch, Arch).
290
291ensure_slash(Dir, SDir) :-
292 ( sub_atom(Dir, _, _, 0, /)
293 -> SDir = Dir
294 ; atom_concat(Dir, /, SDir)
295 ).
296
297app_dir(PackDir, AppDir) :-
298 atomic_list_concat([PackDir, '/app'], AppDir),
299 exists_directory(AppDir)