1:- module(
    2  ppm_generic,
    3  [
    4    ansi_format/2,             % +Attributes, +Format
    5    atom_phrase/2,             % :Dcg_0, ?Atom
    6    compare_version/3,         % ?Order, @Version1, @Version2
    7    directory_by_name/2,       % +Root, +SubDirectories
    8    directory_by_name/3,       % +Root, +SubDirectories, -Directory
    9    directory_file/2,          % +Directory, -File
   10    directory_path/2,          % +Directory, -File
   11    ensure_directory_exists/1, % +Directory
   12    file_by_name/2,            % +Directory, +File
   13    file_by_name/3,            % +Directory, +File, -Path
   14    ppm_dependencies/2,        % +Directory, -Dependencies
   15    repository_directory/3,    % +User, +Repo, -Directory
   16    root_directory/1,          % -Root
   17    user_directory/2,          % +User, -Directory
   18    version//1                 % ?Version
   19  ]
   20).

Prolog Package Manager (PPM): Generic support predicates

author
- Wouter Beek
version
- 2017-2018 */
   28:- use_module(library(ansi_term)).   29:- use_module(library(dcg/basics)).   30:- use_module(library(git)).   31:- use_module(library(http/json)).   32:- use_module(library(filesex)).   33:- use_module(library(lists)).   34:- use_module(library(ordsets)).   35
   36:- meta_predicate
   37    atom_phrase(//, ?).
 ansi_format(+Attributes:list(term), +Format:string) is det
   45ansi_format(Attrs, Format) :-
   46  ansi_format(Attrs, Format, []).
 atom_phrase(:Dcg_0, +Atom:atom) is det
atom_phrase(:Dcg_0, -Atom:atom) is det
   53atom_phrase(Dcg_0, Atom) :-
   54  atom(Atom), !,
   55  atom_codes(Atom, Codes),
   56  phrase(Dcg_0, Codes).
   57atom_phrase(Dcg_0, Atom) :-
   58  phrase(Dcg_0, Codes),
   59  atom_codes(Atom, Codes).
 compare_version(?Order:oneof([<,=,>]), @Version1, @Version2) is det
Determine or test the order between two semantic version numbers.
   67compare_version(Order, version(Ma1,Mi1,Pa1), version(Ma2,Mi2,Pa2)) :-
   68  compare(OrderMa, Ma1, Ma2),
   69  (   OrderMa == =
   70  ->  compare(OrderMi, Mi1, Mi2),
   71      (   OrderMi == =
   72      ->  compare(Order, Pa1, Pa2)
   73      ;   Order = OrderMi
   74      )
   75  ;   Order = OrderMa
   76  ).
 directory_by_name(+Root:atom, +SubDirectories:atom) is semidet
 directory_by_name(+Root:atom, +SubDirectories:atom, -Directory:atom) is semidet
   83directory_by_name(Root, SubDirs) :-
   84  directory_by_name(Root, SubDirs, _).
   85
   86
   87directory_by_name(Root, SubDirs, Dir) :-
   88  absolute_file_name(
   89    SubDirs,
   90    Dir,
   91    [access(read),file_errors(fail),file_type(directory),relative_to(Root)]
   92  ).
 directory_file(+Directory:atom, -File:atom) is nondet
   98directory_file(Dir, File) :-
   99  directory_files(Dir, Files),
  100  member(File, Files),
  101  \+ is_dummy_file(File).
 directory_path(+Directory:atom, -File:atom) is nondet
Non-determinisitcally enumerates the Files that are in Dir.
Arguments:
Dir- is an atom denoting a directory on the filesystem.
File- is an atomic full path specifier of a file in Dir.

The dummy files `.' and `..' are not included.

  115directory_path(Dir, Path) :-
  116  directory_file(Dir, File),
  117  directory_file_path(Dir, File, Path).
 ensure_directory_exists(+Directory:atom) is det
  123ensure_directory_exists(Dir) :-
  124  exists_directory(Dir), !.
  125ensure_directory_exists(Dir) :-
  126  make_directory(Dir).
  127
  128
  129
  130% file_by_name(+Directory:atom, +File:atom) is semidet.
  131% file_by_name(+Directory:atom, +File:atom, -Path:atom) is semidet.
  132
  133file_by_name(Dir, File) :-
  134  file_by_name(Dir, File, _).
  135
  136
  137file_by_name(Dir, File, Path) :-
  138  absolute_file_name(
  139    File,
  140    Path,
  141    [access(read),file_errors(fail),relative_to(Dir)]
  142  ).
 get_dict(?Key, +Dict, +Default, -Value) is det
  148get_dict(Key, Dict, _, Value) :-
  149  get_dict(Key, Dict, Value), !.
  150get_dict(_, _, Value, Value).
 home_directory(-Directory:atom) is det
  156home_directory(Dir) :-
  157  expand_file_name('~', [Dir|_]).
 increment_version(+Kind:oneof([major,minor,patch]), +Version1:compound, -Version2:compound) is det
  164increment_version(major, version(Ma1,Mi,Pa), version(Ma2,Mi,Pa)) :- !,
  165  Ma2 is Ma1 + 1.
  166increment_version(minor, version(Ma,Mi1,Pa), version(Ma,Mi2,Pa)) :- !,
  167  Mi2 is Mi1 + 1.
  168increment_version(patch, version(Ma,Mi,Pa1), version(Ma,Mi,Pa2)) :-
  169  Pa2 is Pa1 + 1.
 is_dummy_file(+File:atom) is semidet
Succeeds if File is the local name of a dummy file, i.e., `.' or `..'.
  178is_dummy_file(.).
  179is_dummy_file(..).
 ppm_dependencies(+Directory:atom, -Dependencies:ordset(dict)) is semidet
  185ppm_dependencies(Dir, Dependencies2) :-
  186  file_by_name(Dir, 'ppm.json', File),
  187  setup_call_cleanup(
  188    open(File, read, In),
  189    json_read_dict(In, Dict, [value_string_as(atom)]),
  190    close(In)
  191  ),
  192  get_dict(dependencies, Dict, [], Dependencies1),
  193  list_to_ord_set(Dependencies1, Dependencies2).
 root_directory(-Directory:atom) is det
Arguments:
Directory- is bound to the directory used to store SWI packages in.

Creates Directory in case it does not yet exist.

  204root_directory(Dir) :-
  205  home_directory(Dir0),
  206  directory_file_path(Dir0, '.ppm', Dir).
 repository_directory(+User:atom, +Repo:atom, -Directory:atom) is semidet
repository_directory(+User:atom, -Repo:atom, -Directory:atom) is nondet
repository_directory(-User:atom, -Repo:atom, -Directory:atom) is nondet
  214repository_directory(User, Repo, Dir) :-
  215  repository_directory_(User, Repo, Dir),
  216  is_git_directory(Dir),
  217  % A package file must be present.
  218  file_by_name(Dir, 'ppm.json').
  219
  220repository_directory_(User, Repo, RepoDir) :-
  221  root_directory(Root),
  222  % User directory.
  223  (   var(User)
  224  ->  directory_files(Root, Users),
  225      member(User, Users),
  226      \+ is_dummy_file(User)
  227  ;   true
  228  ),
  229  directory_file_path(Root, User, UserDir),
  230  % Repository directory.
  231  (   var(Repo)
  232  ->  directory_files(UserDir, Repos),
  233      member(Repo, Repos),
  234      \+ is_dummy_file(Repo)
  235  ;   true
  236  ),
  237  directory_file_path(UserDir, Repo, RepoDir).
 user_directory(+User:atom, -Directory:atom) is det
  243user_directory(User, Dir) :-
  244  root_directory(Root),
  245  directory_file_path(Root, User, Dir),
  246  ensure_directory_exists(Dir).
 version(+Version:compound)// is det
version(-Version:compound)// is det
Parses/generates semantic versioning strings.
Arguments:
Version- is a compound term of the form `version(int,int,int)'.
  257version(version(Ma,Mi,Pa)) -->
  258  "v",
  259  integer(Ma),
  260  ".",
  261  integer(Mi),
  262  ".",
  263  integer(Pa)