View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker and Richard O'Keefe
    4    E-mail:        J.Wielemaker@cs.vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2014-2019, VU University Amsterdam
    7                              CWI, Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(check_installation,
   37          [ check_installation/0,
   38            check_installation/1,               % -Issues
   39            check_config_files/0,
   40            update_config_files/0,
   41            test_installation/0,
   42            test_installation/1                 % +Options
   43          ]).   44:- use_module(option).   45:- use_module(lists).   46:- use_module(apply).

Check installation issues and features

This library performs checks on the installed system to verify which optional components are available and whether all libaries that load shared objects/DLLs can be loaded. */

 component(?Component, -Features) is nondet
This predicate describes the test components. Features is a dict with the following components:
test:Goal
(Additional) test that must succeed for the component to be functional.
url:URL
URL with additional information, relative to http://www.swi-prolog.org/build/issues/. If not provided, the library file with extension .html is used.
optional:true
If the library does not exist, do not complain.
os:OS
One of windows, unix or linux. If present, the component is only checked for if we are running on a version of the specified operating system.
features:Goal
After successful evaluation that loading and basic operation of the component succeeds, run this to check additional features.
   78% Feature tests
   79component(gmp,
   80          _{ test:current_prolog_flag(bounded, false),
   81             url:'gmp.html'
   82           }).
   83% Packages that depend on foreign libraries
   84component(library(archive), _{features:archive_features}).
   85component(library(cgi), _{}).
   86component(library(crypt), _{}).
   87component(library(bdb), _{}).
   88component(library(double_metaphone), _{}).
   89component(library(filesex), _{}).
   90component(library(http/http_stream), _{}).
   91component(library(http/json), _{}).
   92component(library(http/jquery), _{features:jquery_file}).
   93component(library(isub), _{}).
   94component(library(jpl), _{}).
   95component(library(memfile), _{}).
   96component(library(odbc), _{}).
   97component(library(pce),
   98          _{pre:load_foreign_library(pce_principal:foreign(pl2xpce)),
   99            url:'xpce.html'}).
  100component(library(pcre), _{features:pcre_features}).
  101component(library(pdt_console), _{}).
  102component(library(porter_stem), _{}).
  103component(library(process), _{}).
  104component(library(protobufs), _{}).
  105component(library(editline), _{os:unix}).
  106component(library(readline), _{os:unix}).
  107component(library(readutil), _{}).
  108component(library(rlimit), _{os:unix}).
  109component(library(semweb/rdf_db), _{}).
  110component(library(semweb/rdf_ntriples), _{}).
  111component(library(semweb/turtle), _{}).
  112component(library(sgml), _{}).
  113component(library(sha), _{}).
  114component(library(snowball), _{}).
  115component(library(socket), _{}).
  116component(library(ssl), _{}).
  117component(library(crypto), _{}).
  118component(library(syslog), _{os:unix}).
  119component(library(table), _{}).
  120component(library(time), _{}).
  121component(library(tipc/tipc), _{os:linux}).
  122component(library(unicode), _{}).
  123component(library(uri), _{}).
  124component(library(uuid), _{}).
  125component(library(zlib), _{}).
  126component(library(yaml), _{}).
  127
  128issue_base('http://www.swi-prolog.org/build/issues/').
  129
  130:- thread_local
  131    issue/1.  132
  133:- meta_predicate
  134    run_silent(0, +).
 check_installation
Check features of the installed system. Performs the following tests:
  1. Test whether features that depend on optional libraries are present (e.g., unbounded arithmetic support)
  2. Test that all standard libraries that depend on foreign code are present.
  3. provides a test_installation predicate to run the tests at runtime if the system was built with -DINSTALL_TESTS

If issues are found it prints a diagnostic message with a link to a wiki page with additional information about the issue.

  151check_installation :-
  152    print_message(informational, installation(checking)),
  153    check_installation_(InstallIssues),
  154    check_on_path,
  155    check_config_files(ConfigIssues),
  156    maplist(print_message(warning), ConfigIssues),
  157    append(InstallIssues, ConfigIssues, Issues),
  158    (   Issues == []
  159    ->  print_message(informational, installation(perfect))
  160    ;   length(Issues, Count),
  161        print_message(warning, installation(imperfect(Count)))
  162    ).
 check_installation(-Issues:list(pair)) is det
As check_installation/0, but additionally returns a list of Component-Problem pairs. Problem is one of optional_not_found (optional component is not present), not_found (component is not present) or failed (component is present but cannot be loaded).
  172check_installation(Issues) :-
  173    check_installation_(Issues0),
  174    maplist(public_issue, Issues0, Issues).
  175
  176public_issue(installation(Term), Source-Issue) :-
  177    functor(Term, Issue, _),
  178    arg(1, Term, Properties),
  179    Source = Properties.source.
  180
  181check_installation_(Issues) :-
  182    retractall(issue(_)),
  183    forall(component(Source, _Properties),
  184           check_component(Source)),
  185    findall(I, retract(issue(I)), Issues).
  186
  187check_component(Source) :-
  188    component(Source, Properties),
  189    !,
  190    check_component(Source, Properties.put(source,Source)).
  191
  192check_component(Source, Properties) :-
  193    compound(Source),
  194    !,
  195    check_source(Source, Properties).
  196check_component(Feature, Properties) :-
  197    print_message(informational, installation(checking(Feature))),
  198    (   call(Properties.test)
  199    ->  print_message(informational, installation(ok))
  200    ;   print_issue(installation(missing(Properties)))
  201    ).
  202
  203check_source(_Source, Properties) :-
  204    OS = Properties.get(os),
  205    \+ current_os(OS),
  206    !.
  207check_source(Source, Properties) :-
  208    exists_source(Source),
  209    !,
  210    print_message(informational, installation(loading(Source))),
  211    (   run_silent(( (   Pre = Properties.get(pre)
  212                     ->  call(Pre)
  213                     ;   true
  214                     ),
  215                     load_files(Source, [silent(true), if(not_loaded)])
  216                   ),
  217                   Properties.put(action, load))
  218    ->  test_component(Properties),
  219        print_message(informational, installation(ok)),
  220        check_features(Properties)
  221    ;   true
  222    ).
  223check_source(_Source, Properties) :-
  224    Properties.get(optional) == true,
  225    !,
  226    print_message(silent,
  227                  installation(optional_not_found(Properties))).
  228check_source(_Source, Properties) :-
  229    print_issue(installation(not_found(Properties))).
  230
  231current_os(unix)    :- current_prolog_flag(unix, true).
  232current_os(windows) :- current_prolog_flag(windows, true).
  233current_os(linux)   :- current_prolog_flag(arch, Arch), sub_atom(Arch, _, _, _, linux).
 test_component(+Properties) is semidet
Run additional tests to see whether the componnent really works.
  239test_component(Dict) :-
  240    Test = Dict.get(test),
  241    !,
  242    call(Test).
  243test_component(_).
 check_features(+Properties) is semidet
Check for additional features of the components.
See also
- check_component/1 should be used for checking that the component works.
  252check_features(Dict) :-
  253    Test = Dict.get(features),
  254    !,
  255    call(Test).
  256check_features(_).
 run_silent(:Goal, +Properties) is semidet
Succeed if Goal succeeds and does not print any errors or warnings.
  264run_silent(Goal, Properties) :-
  265    run_collect_messages(Goal, Result, Messages),
  266    (   Result == true,
  267        Messages == []
  268    ->  true
  269    ;   print_issue(installation(failed(Properties, Result, Messages))),
  270        fail
  271    ).
 run_collect_messages(Goal, Result, Messages) is det
Run Goal, unify Result with true, false or exception(Error) and messages with a list of generated error and warning messages. Each message is a term:
message(Term,Kind,Lines)
See also
- message_hook/3.
  283:- thread_local
  284    got_message/1.  285
  286run_collect_messages(Goal, Result, Messages) :-
  287    setup_call_cleanup(
  288        asserta((user:thread_message_hook(Term,Kind,Lines) :-
  289                    error_kind(Kind),
  290                    assertz(got_message(message(Term,Kind,Lines)))), Ref),
  291        (   catch(Goal, E, true)
  292        ->  (   var(E)
  293            ->  Result0 = true
  294            ;   Result0 = exception(E)
  295            )
  296        ;   Result0 = false
  297        ),
  298        erase(Ref)),
  299    findall(Msg, retract(got_message(Msg)), Messages),
  300    Result = Result0.
  301
  302error_kind(warning).
  303error_kind(error).
  304
  305
  306                 /*******************************
  307                 *         SPECIAL TESTS        *
  308                 *******************************/
 archive_features
Report features supported by library(archive).
  314archive_features :-
  315    tmp_file_stream(utf8, Name, Out),
  316    close(Out),
  317    findall(F, archive_filter(F, Name), Filters),
  318    print_message(informational, installation(archive(filters, Filters))),
  319    findall(F, archive_format(F, Name), Formats),
  320    print_message(informational, installation(archive(formats, Formats))),
  321    delete_file(Name).
  322
  323archive_filter(F, Name) :-
  324    a_filter(F),
  325    catch(archive_open(Name, A, [filter(F)]), E, true),
  326    (   var(E)
  327    ->  archive_close(A)
  328    ;   true
  329    ),
  330    \+ subsumes_term(error(domain_error(filter, _),_), E).
  331
  332archive_format(F, Name) :-
  333    a_format(F),
  334    catch(archive_open(Name, A, [format(F)]), E, true),
  335    (   var(E)
  336    ->  archive_close(A)
  337    ;   true
  338    ),
  339    \+ subsumes_term(error(domain_error(filter, _),_), E).
  340
  341a_filter(bzip2).
  342a_filter(compress).
  343a_filter(gzip).
  344a_filter(grzip).
  345a_filter(lrzip).
  346a_filter(lzip).
  347a_filter(lzma).
  348a_filter(lzop).
  349a_filter(none).
  350a_filter(rpm).
  351a_filter(uu).
  352a_filter(xz).
  353
  354a_format('7zip').
  355a_format(ar).
  356a_format(cab).
  357a_format(cpio).
  358a_format(empty).
  359a_format(gnutar).
  360a_format(iso9660).
  361a_format(lha).
  362a_format(mtree).
  363a_format(rar).
  364a_format(raw).
  365a_format(tar).
  366a_format(xar).
  367a_format(zip).
 pcre_features
  371pcre_features :-
  372    findall(X, pcre_missing(X), Missing),
  373    (   Missing == []
  374    ->  true
  375    ;   print_message(warning, installation(pcre_missing(Missing)))
  376    ).
  377
  378pcre_missing(X) :-
  379    pcre_must_have(X),
  380    Term =.. [X,true],
  381    \+ catch(re_config(Term), _, fail).
  382
  383pcre_must_have(utf8).
  384pcre_must_have(unicode_properties).
 jquery_file
Test whether jquery.js can be found
  390jquery_file :-
  391    setting(jquery:version, File),
  392    (   absolute_file_name(js(File), Path, [access(read), file_errors(fail)])
  393    ->  print_message(informational, installation(jquery(found(Path))))
  394    ;   print_message(warning, installation(jquery(not_found(File))))
  395    ).
 check_on_path
Validate that Prolog is installed in $PATH
  402check_on_path :-
  403    current_prolog_flag(executable, EXEFlag),
  404    prolog_to_os_filename(EXE, EXEFlag),
  405    file_base_name(EXE, Prog),
  406    absolute_file_name(EXE, AbsExe,
  407                       [ access(execute)
  408                       ]),
  409    prolog_to_os_filename(AbsExe, OsExe),
  410    (   absolute_file_name(path(Prog), OnPath,
  411                           [ access(execute),
  412                             file_errors(fail)
  413                           ])
  414    ->  (   same_file(EXE, OnPath)
  415        ->  true
  416        ;   absolute_file_name(path(Prog), OnPathAny,
  417                               [ access(execute),
  418                                 file_errors(fail),
  419                                 solutions(all)
  420                               ]),
  421            same_file(EXE, OnPathAny)
  422        ->  print_message(warning, installation(not_first_on_path(OsExe, OnPath)))
  423        ;   print_message(warning, installation(not_same_on_path(OsExe, OnPath)))
  424        )
  425    ;   print_message(warning, installation(not_on_path(OsExe, Prog)))
  426    ).
  427
  428
  429		 /*******************************
  430		 *           RUN TESTS		*
  431		 *******************************/
 test_installation is semidet
 test_installation(+Options) is semidet
Run regression tests in the installed system. Requires the system to be built using
cmake -DINSTALL_TESTS=ON

Options processed:

packages(+Boolean)
When false, do not test the packages
package(+Package)
Only test package package.
  448test_installation :-
  449    test_installation([]).
  450
  451test_installation(Options) :-
  452    absolute_file_name(swi(test/test),
  453                       TestFile,
  454                       [ access(read),
  455                         file_errors(fail),
  456                         file_type(prolog)
  457                       ]),
  458    !,
  459    test_installation_run(TestFile, Options).
  460test_installation(_Options) :-
  461    print_message(warning, installation(testing(no_installed_tests))).
  462
  463test_installation_run(TestFile, Options) :-
  464    (   option(package(_), Options)
  465    ->  merge_options(Options,
  466                      [ core(false),
  467                        subdirs(false)
  468                      ], TestOptions)
  469    ;   merge_options(Options,
  470                      [ packages(true)
  471                      ], TestOptions)
  472    ),
  473    load_files(user:TestFile),
  474    current_prolog_flag(verbose, Old),
  475    setup_call_cleanup(
  476        set_prolog_flag(verbose, silent),
  477        user:test([], TestOptions),
  478        set_prolog_flag(verbose, Old)).
  479
  480
  481                 /*******************************
  482                 *            MESSAGES          *
  483                 *******************************/
  484
  485:- multifile
  486    prolog:message//1.  487
  488print_issue(Term) :-
  489    assertz(issue(Term)),
  490    print_message(warning, Term).
  491
  492issue_url(Properties, URL) :-
  493    Local = Properties.get(url),
  494    !,
  495    issue_base(Base),
  496    atom_concat(Base, Local, URL).
  497issue_url(Properties, URL) :-
  498    Properties.get(source) = library(Segments),
  499    !,
  500    path_segments_atom(Segments, Base),
  501    file_name_extension(Base, html, URLFile),
  502    issue_base(Issues),
  503    atom_concat(Issues, URLFile, URL).
  504
  505prolog:message(installation(Message)) -->
  506    message(Message).
  507
  508message(checking) -->
  509    { current_prolog_flag(address_bits, Bits) },
  510    { current_prolog_flag(arch, Arch) },
  511    { current_prolog_flag(home, Home) },
  512    { current_prolog_flag(cpu_count, Cores) },
  513    [ 'Checking your SWI-Prolog kit for common issues ...'-[], nl, nl ],
  514    [ 'Version: ~`.t~24| '-[] ], '$messages':prolog_message(version), [nl],
  515    [ 'Address bits: ~`.t~24| ~d'-[Bits] ], [nl],
  516    [ 'Architecture: ~`.t~24| ~w'-[Arch] ], [nl],
  517    [ 'Installed at: ~`.t~24| ~w'-[Home] ], [nl],
  518    [ 'Cores: ~`.t~24| ~w'-[Cores] ], [nl],
  519    [ nl ].
  520message(perfect) -->
  521    [ nl, 'Congratulations, your kit seems sound and complete!'-[] ].
  522message(imperfect(N)) -->
  523    [ 'Found ~w issues.'-[N] ].
  524message(checking(Feature)) -->
  525    [ 'Checking ~w ...'-[Feature], flush ].
  526message(missing(Properties)) -->
  527    [ at_same_line, '~`.t~48| not present'-[] ],
  528    details(Properties).
  529message(loading(Source)) -->
  530    [ 'Loading ~q ...'-[Source], flush ].
  531message(ok) -->
  532    [ at_same_line, '~`.t~48| ok'-[] ].
  533message(optional_not_found(Properties)) -->
  534    [ 'Optional ~q ~`.t~48| not present'-[Properties.source] ].
  535message(not_found(Properties)) -->
  536    [ '~q ~`.t~48| NOT FOUND'-[Properties.source] ],
  537    details(Properties).
  538message(failed(Properties, false, [])) -->
  539    !,
  540    [ at_same_line, '~`.t~48| FAILED'-[] ],
  541    details(Properties).
  542message(failed(Properties, exception(Ex0), [])) -->
  543    !,
  544    { strip_stack(Ex0, Ex),
  545      message_to_string(Ex, Msg) },
  546    [ '~w'-[Msg] ],
  547    details(Properties).
  548message(failed(Properties, true, Messages)) -->
  549    [ at_same_line, '~`.t~48| FAILED'-[] ],
  550    explain(Messages),
  551    details(Properties).
  552message(archive(What, Names)) -->
  553    [ '  Supported ~w: '-[What] ],
  554    list_names(Names).
  555message(pcre_missing(Features)) -->
  556    [ 'Missing libpcre features: '-[] ],
  557    list_names(Features).
  558message(not_first_on_path(EXE, OnPath)) -->
  559    { public_executable(EXE, PublicEXE),
  560      file_base_name(EXE, Prog)
  561    },
  562    [ 'The first ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  563    [ 'this version is ~p.'-[PublicEXE] ].
  564message(not_same_on_path(EXE, OnPath)) -->
  565    { public_executable(EXE, PublicEXE),
  566      file_base_name(EXE, Prog)
  567    },
  568    [ 'The ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  569    [ 'this version is ~p.'-[PublicEXE] ].
  570message(not_on_path(EXE, Prog)) -->
  571    { public_bin_dir(EXE, Dir),
  572      prolog_to_os_filename(Dir, OSDir)
  573    },
  574    [ 'Could not find ~w on '-[Prog] ], 'PATH', [ '. '-[], nl ],
  575    [ 'You may wish to add ~p to '-[OSDir] ], 'PATH', [ '. '-[], nl ].
  576message(jquery(found(Path))) -->
  577    [ '  jQuery from ~w'-[Path] ].
  578message(jquery(not_found(File))) -->
  579    [ '  Cannot find jQuery (~w)'-[File] ].
  580message(testing(no_installed_tests)) -->
  581    [ '  Runtime testing is not enabled.', nl],
  582    [ '  Please recompile the system with INSTALL_TESTS enabled.' ].
  583
  584
  585public_executable(EXE, PublicProg) :-
  586    file_base_name(EXE, Prog),
  587    file_directory_name(EXE, ArchDir),
  588    file_directory_name(ArchDir, BinDir),
  589    file_directory_name(BinDir, Home),
  590    file_directory_name(Home, Lib),
  591    file_directory_name(Lib, Prefix),
  592    atomic_list_concat([Prefix, bin, Prog], /, PublicProg),
  593    exists_file(PublicProg),
  594    same_file(EXE, PublicProg),
  595    !.
  596public_executable(EXE, EXE).
  597
  598public_bin_dir(EXE, Dir) :-
  599    public_executable(EXE, PublicEXE),
  600    file_directory_name(PublicEXE, Dir).
  601
  602
  603
  604'PATH' -->
  605    { current_prolog_flag(windows, true) },
  606    !,
  607    [ '%PATH%'-[] ].
  608'PATH' -->
  609    [ '$PATH'-[] ].
  610
  611strip_stack(error(Error, context(prolog_stack(S), Msg)),
  612            error(Error, context(_, Msg))) :-
  613    nonvar(S).
  614strip_stack(Error, Error).
  615
  616details(Properties) -->
  617    { issue_url(Properties, URL), !
  618    },
  619    [ nl, 'See ~w'-[URL] ].
  620details(_) --> [].
  621
  622explain(Messages) -->
  623    { Messages = [message(error(shared_object(open, _Message), _), _, _)|_]
  624    },
  625    !,
  626    [nl],
  627    (   { current_prolog_flag(windows, true) }
  628    ->  [ 'Cannot load required DLL'-[] ]
  629    ;   [ 'Cannot load required shared library'-[] ]
  630    ).
  631explain(Messages) -->
  632    print_messages(Messages).
  633
  634print_messages([]) --> [].
  635print_messages([message(_Term, _Kind, Lines)|T]) -->
  636    Lines, [nl],
  637    print_messages(T).
  638
  639list_names([]) --> [].
  640list_names([H|T]) -->
  641    [ '~w'-[H] ],
  642    (   {T==[]}
  643    ->  []
  644    ;   [ ', '-[] ],
  645        list_names(T)
  646    ).
  647
  648
  649		 /*******************************
  650		 *          CONFIG FILES	*
  651		 *******************************/
 check_config_files
Examines the locations of config files. The config files have moved in version 8.1.15
  658check_config_files :-
  659    check_config_files(Issues),
  660    maplist(print_message(warning), Issues).
  661
  662check_config_files(Issues) :-
  663    findall(Issue, check_config_file(Issue), Issues).
  664
  665check_config_file(config(Id, move(Type, OldFile, NewFile))) :-
  666    old_config(Type, Id, OldFile),
  667    access_file(OldFile, exist),
  668    \+ ( new_config(Type, Id, NewFile),
  669         access_file(NewFile, exist)
  670       ),
  671    once(new_config(Type, Id, NewFile)).
  672check_config_file(config(Id, different(Type, OldFile, NewFile))) :-
  673    old_config(Type, Id, OldFile),
  674    access_file(OldFile, exist),
  675    new_config(Type, Id, NewFile),
  676    access_file(NewFile, exist),
  677    \+ same_file(OldFile, NewFile).
 update_config_files
Move config files from their old location to the new if the file or directory exists in the old location but not in the new.
  684update_config_files :-
  685    old_config(Type, Id, OldFile),
  686    access_file(OldFile, exist),
  687    \+ ( new_config(Type, Id, NewFile),
  688         access_file(NewFile, exist)
  689       ),
  690    (   new_config(Type, Id, NewFile),
  691        \+ same_file(OldFile, NewFile),
  692        create_parent_dir(NewFile)
  693    ->  catch(rename_file(OldFile, NewFile), E,
  694              print_message(warning, E)),
  695        print_message(informational, config(Id, moved(Type, OldFile, NewFile)))
  696    ),
  697    fail.
  698update_config_files.
  699
  700old_config(file, init, File) :-
  701    current_prolog_flag(windows, true),
  702    win_folder(appdata, Base),
  703    atom_concat(Base, '/SWI-Prolog/swipl.ini', File).
  704old_config(file, init, File) :-
  705    expand_file_name('~/.swiplrc', [File]).
  706old_config(directory, lib, Dir) :-
  707    expand_file_name('~/lib/prolog', [Dir]).
  708old_config(directory, xpce, Dir) :-
  709    expand_file_name('~/.xpce', [Dir]).
  710old_config(directory, history, Dir) :-
  711    expand_file_name('~/.swipl-dir-history', [Dir]).
  712old_config(directory, pack, Dir) :-
  713    (   catch(expand_file_name('~/lib/swipl/pack', [Dir]), _, fail)
  714    ;   absolute_file_name(swi(pack), Dir,
  715                           [ file_type(directory), solutions(all) ])
  716    ).
  717
  718new_config(file, init, File) :-
  719    absolute_file_name(user_app_config('init.pl'), File,
  720                       [ solutions(all) ]).
  721new_config(directory, lib, Dir) :-
  722    config_dir(user_app_config(lib), Dir).
  723new_config(directory, xpce, Dir) :-
  724    config_dir(user_app_config(xpce), Dir).
  725new_config(directory, history, Dir) :-
  726    config_dir(user_app_config('dir-history'), Dir).
  727new_config(directory, pack, Dir) :-
  728    config_dir([app_data(pack), swi(pack)], Dir).
  729
  730config_dir(Aliases, Dir) :-
  731    is_list(Aliases),
  732    !,
  733    (   member(Alias, Aliases),
  734        absolute_file_name(Alias, Dir,
  735                           [ file_type(directory), solutions(all) ])
  736    *-> true
  737    ;   member(Alias, Aliases),
  738        absolute_file_name(Alias, Dir,
  739                           [ solutions(all) ])
  740    ).
  741config_dir(Alias, Dir) :-
  742    (   absolute_file_name(Alias, Dir,
  743                           [ file_type(directory), solutions(all) ])
  744    *-> true
  745    ;   absolute_file_name(Alias, Dir,
  746                           [ solutions(all) ])
  747    ).
  748
  749create_parent_dir(NewFile) :-
  750    file_directory_name(NewFile, Dir),
  751    create_parent_dir_(Dir).
  752
  753create_parent_dir_(Dir) :-
  754    exists_directory(Dir),
  755    '$my_file'(Dir),
  756    !.
  757create_parent_dir_(Dir) :-
  758    file_directory_name(Dir, Parent),
  759    Parent \== Dir,
  760    create_parent_dir_(Parent),
  761    make_directory(Dir).
  762
  763prolog:message(config(Id, Issue)) -->
  764    [ 'Config: '-[] ],
  765    config_description(Id),
  766    config_issue(Issue).
  767
  768config_description(init) -->
  769    [ '(user initialization file) '-[], nl ].
  770config_description(lib) -->
  771    [ '(user library) '-[], nl ].
  772config_description(pack) -->
  773    [ '(add-ons) '-[], nl ].
  774config_description(history) -->
  775    [ '(command line history) '-[], nl ].
  776config_description(xpce) -->
  777    [ '(gui) '-[], nl ].
  778
  779config_issue(move(Type, Old, New)) -->
  780    [ '  found ~w "~w"'-[Type, Old], nl ],
  781    [ '  new location is "~w"'-[New] ].
  782config_issue(moved(Type, Old, New)) -->
  783    [ '  found ~w "~w"'-[Type, Old], nl ],
  784    [ '  moved to new location "~w"'-[New] ].
  785config_issue(different(Type, Old, New)) -->
  786    [ '  found different ~w "~w"'-[Type, Old], nl ],
  787    [ '  new location is "~w"'-[New] ]