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 '$pack_attach'/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).
58
63
64'$pack_detach'(Name, Dir) :-
65 ( atom(Name)
66 -> true
67 ; throw(error(type_error(atom, Name), _))
68 ),
69 ( retract(pack(Name, Dir))
70 -> retractall(pack_dir(Name, _, _)),
71 reload_library_index
72 ; throw(error(existence_error(pack, Name), _))
73 ).
74
78
79'$pack_attach'(Dir) :-
80 '$pack_attach'(Dir, []).
81
82'$pack_attach'(Dir, Options) :-
83 attach_package(Dir, Options),
84 !.
85'$pack_attach'(Dir, _) :-
86 ( exists_directory(Dir)
87 -> throw(error(existence_error(directory, Dir), _))
88 ; throw(error(domain_error(pack, Dir), _))
89 ).
90
95
96attach_packs :-
97 set_prolog_flag(packs, true),
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
114
115remove_dups([], [], _).
116remove_dups([H|T0], T, Seen) :-
117 memberchk(H, Seen),
118 !,
119 remove_dups(T0, T, Seen).
120remove_dups([H|T0], [H|T], Seen) :-
121 remove_dups(T0, T, [H|Seen]).
122
123
141
142attach_packs(Dir) :-
143 attach_packs(Dir, []).
144
145attach_packs(Dir, Options) :-
146 absolute_file_name(Dir, Path,
147 [ file_type(directory),
148 file_errors(fail)
149 ]),
150 catch(directory_files(Path, Entries), _, fail),
151 !,
152 ensure_slash(Path, SPath),
153 attach_packages(Entries, SPath, Options).
154attach_packs(_, _).
155
156attach_packages([], _, _).
157attach_packages([H|T], Dir, Options) :-
158 attach_package(H, Dir, Options),
159 attach_packages(T, Dir, Options).
160
161attach_package(Entry, Dir, Options) :-
162 \+ special(Entry),
163 atom_concat(Dir, Entry, PackDir),
164 attach_package(PackDir, Options),
165 !.
166attach_package(_, _, _).
167
168special(.).
169special(..).
170
171
175
176attach_package(PackDir, Options) :-
177 atomic_list_concat([PackDir, '/pack.pl'], InfoFile),
178 access_file(InfoFile, read),
179 file_base_name(PackDir, Pack),
180 check_existing(Pack, PackDir, Options),
181 foreign_dir(Pack, PackDir, ForeignDir),
182 prolog_dir(PackDir, PrologDir),
183 !,
184 assertz(pack(Pack, PackDir)),
185 '$option'(search(Where), Options, last),
186 ( Where == last
187 -> assertz(pack_dir(Pack, prolog, PrologDir))
188 ; Where == first
189 -> asserta(pack_dir(Pack, prolog, PrologDir))
190 ; '$domain_error'(option_search, Where)
191 ),
192 update_autoload(PrologDir),
193 ( ForeignDir \== (-)
194 -> assertz(pack_dir(Pack, foreign, ForeignDir))
195 ; true
196 ),
197 print_message(silent, pack(attached(Pack, PackDir))).
198
199
203
204check_existing(Entry, Dir, _) :-
205 retract(pack(Entry, Dir)), 206 !,
207 retractall(pack_dir(Entry, _, _)).
208check_existing(Entry, Dir, Options) :-
209 pack(Entry, OldDir),
210 !,
211 '$option'(duplicate(Action), Options, warning),
212 ( Action == warning
213 -> print_message(warning, pack(duplicate(Entry, OldDir, Dir))),
214 fail
215 ; Action == keep
216 -> fail
217 ; Action == replace
218 -> print_message(silent, pack(replaced(Entry, OldDir, Dir))),
219 '$pack_detach'(Entry, OldDir)
220 ; '$domain_error'(option_duplicate, Action)
221 ).
222check_existing(_, _, _).
223
224
225prolog_dir(PackDir, PrologDir) :-
226 atomic_list_concat([PackDir, '/prolog'], PrologDir),
227 exists_directory(PrologDir).
228
229update_autoload(PrologDir) :-
230 atom_concat(PrologDir, '/INDEX.pl', IndexFile),
231 ( exists_file(IndexFile)
232 -> reload_library_index
233 ; true
234 ).
235
236foreign_dir(Pack, PackDir, ForeignDir) :-
237 atomic_list_concat([PackDir, '/lib'], ForeignBaseDir),
238 exists_directory(ForeignBaseDir),
239 !,
240 ( arch(Arch),
241 atomic_list_concat([PackDir, '/lib/', Arch], ForeignDir),
242 exists_directory(ForeignDir)
243 -> assertz(pack_dir(Pack, foreign, ForeignDir))
244 ; findall(Arch, arch(Arch), Archs),
245 print_message(warning, pack(no_arch(Pack, Archs))),
246 fail
247 ).
248foreign_dir(_, _, (-)).
249
250arch(Arch) :-
251 current_prolog_flag(apple_universal_binary, true),
252 Arch = 'fat-darwin'.
253arch(Arch) :-
254 current_prolog_flag(arch, Arch).
255
256ensure_slash(Dir, SDir) :-
257 ( sub_atom(Dir, _, _, 0, /)
258 -> SDir = Dir
259 ; atom_concat(Dir, /, SDir)
260 )