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