1:- module(
2 ppm,
3 [
4 ppm_help/0,
5 ppm_install/2, % +User, +Repo
6 ppm_list/0,
7 ppm_remove/2, % +User, +Repo
8 ppm_run/2, % +User, +Repo
9 ppm_sync/0,
10 ppm_update/0,
11 ppm_update/2, % +User, +Repo
12 ppm_updates/0
13 ]
14).
26:- use_module(library(aggregate)). 27:- use_module(library(apply)). 28:- use_module(library(filesex)). 29:- use_module(library(git)). 30:- use_module(library(http/http_json), []). 31:- use_module(library(prolog_pack), []). 32 33:- use_module(library(ppm_generic)). 34:- use_module(library(ppm_git)). 35:- use_module(library(ppm_github)). 36 37:- initialization 38 init_ppm.
47ppm_current_update(User, Repo, CurrentVersion, LatestVersion) :-
48 repository_directory(User, Repo, Dir),
49 git_fetch(Dir),
50 git_current_version(Dir, CurrentVersion),
51 git_version_latest(Dir, LatestVersion),
52 CurrentVersion \== LatestVersion.
58ppm_help :-
59 ansi_format([fg(green)], "Welcome "),
60 ansi_format([fg(red)], "to "),
61 ansi_format([fg(blue)], "Prolog "),
62 ansi_format([fg(yellow)], "Package "),
63 ansi_format([fg(magenta)], "Manager"),
64 format("!"),
65 nl,
66 format("We are so happy that you're here :-)"),
67 nl,
68 nl.
77ppm_install(User, Repo) :- 78 ppm_install(User, Repo, package). 79 80ppm_install(User, Repo, Kind) :- 81 repository_directory(User, Repo, _), !, 82 ppm_update(User, Repo, Kind). 83ppm_install(User, Repo, Kind) :- 84 user_directory(User, UserDir), 85 ( github_version_latest(User, Repo, LatestVersion) 86 -> github_uri(User, Repo, Uri), 87 git_clone(UserDir, Uri), 88 directory_file_path(UserDir, Repo, RepoDir), 89 git_checkout(RepoDir, version(LatestVersion)), 90 ppm_dependencies(RepoDir, Dependencies), 91 maplist(ppm_install_dependency, Dependencies), 92 phrase(version(LatestVersion), Codes), 93 ansi_format( 94 [fg(green)], 95 "Successfully installed ~a ‘~a’ (~s)\n", 96 [Kind,Repo,Codes] 97 ), 98 ppm_sync 99 ; ansi_format( 100 [fg(red)], 101 "Could not find a version tag in ~a's ~a ‘~a’.", 102 [User,Kind,Repo] 103 ), 104 nl, 105 fail 106 ). 107 108ppm_install_dependency(Dependency) :- 109 _{user: User, repo: Repo} :< Dependency, 110 ppm_install(User, Repo, dependency).
118ppm_list :- 119 aggregate_all( 120 set(package(User,Repo,Version,Dependencies)), 121 ( 122 repository_directory(User, Repo, Dir), 123 git_current_version(Dir, Version), 124 ppm_dependencies(Dir, Dependencies) 125 ), 126 Packages 127 ), 128 ( Packages == [] 129 -> format("No packages are currently installed.\n") 130 ; maplist(ppm_list_row, Packages) 131 ). 132 133ppm_list_row(package(User,Repo,Version,Dependencies)) :- 134 phrase(version(Version), Codes), 135 format("~a/~a (~s)\n", [User,Repo,Codes]), 136 maplist(ppm_list_dep_row, Dependencies). 137 138ppm_list_dep_row(Dependency) :- 139 _{user: User, repo: Repo} :< Dependency, 140 format(" ⤷ ~a/~a\n", [User,Repo]).
TBD: Support for removing otherwise unused dependencies.
150ppm_remove(User, Repo) :-
151 repository_directory(User, Repo, Dir),
152 git_current_version(Dir, Version),
153 delete_directory_and_contents(Dir),
154 phrase(version(Version), Codes),
155 format("Deleted package ‘~a/~a’ (~s).", [User,Repo,Codes]).
161ppm_run(User, Repo) :-
162 repository_directory(User, Repo, Dir),
163 ( file_by_name(Dir, 'run.pl', File)
164 -> consult(File)
165 ; ansi_format([fg(red)], "Package ‘~a/~a’ is currently not installed.\n", [User,Repo])
166 ).
175ppm_sync :- 176 root_directory(Root), 177 ppm_sync_(Root). 178 179ppm_sync_(Root) :- 180 assertz(user:file_search_path(ppm, Root)), 181 current_prolog_flag(arch, Arch), 182 forall( 183 repository_directory(User, Repo, _), 184 ( 185 ( sync_directory(Root, User, Repo, [prolog], Dir) 186 -> assertz(user:file_search_path(library, ppm(Dir))) 187 ; true 188 ), 189 ( sync_directory(Root, User, Repo, [lib,Arch], Dir) 190 -> assertz(user:file_search_path(foreign, ppm(Dir))) 191 ; true 192 ) 193 ) 194 ). 195 196sync_directory(Root, User, Repo, T, Dir) :- 197 atomic_list_concat([User,Repo|T], /, Dir), 198 directory_by_name(Root, Dir).
207ppm_update :- 208 ppm_updates_(Updates), 209 forall( 210 member(update(User,Repo,_,_), Updates), 211 ppm_update(User, Repo) 212 ). 213 214 215ppm_update(User, Repo) :- 216 ppm_update(User, Repo, package). 217 218 219ppm_update(User, Repo, Kind) :- 220 repository_directory(User, Repo, Dir), 221 git_fetch(Dir), 222 git_current_version(Dir, CurrentVersion), 223 git_version_latest(Dir, LatestVersion), 224 ( compare_version(<, CurrentVersion, LatestVersion) 225 -> git_checkout(Dir, version(LatestVersion)), 226 % informational 227 phrase(version(CurrentVersion), Codes1), 228 phrase(version(LatestVersion), Codes2), 229 format("Updated ‘~a/~a’: ~s → ~s\n", [User,Repo,Codes1,Codes2]) 230 ; % informational 231 ( Kind == package 232 -> format("No need to update ~a ‘~a/~a’.\n", [Kind,User,Repo]) 233 ; true 234 ) 235 ), 236 % Update the dependencies after updating the main package. 237 ppm_dependencies(Dir, Dependencies), 238 maplist(ppm_install_dependency, Dependencies), 239 ppm_sync. 240 241ppm_update_dependency(Dependency) :- 242 _{user: User, repo: Repo} :< Dependency, 243 ppm_update(User, Repo, dependency).
251ppm_updates :- 252 format("Checking for updates…\n\n"), 253 ppm_updates_(Updates), 254 pp_available_updates(Updates), 255 maplist(ppm_updates_row, Updates). 256 257ppm_updates_(Updates) :- 258 aggregate_all( 259 set(update(User,Repo,CurrentVersion,LatestVersion)), 260 ppm_current_update(User, Repo, CurrentVersion, LatestVersion), 261 Updates 262 ). 263 264pp_available_updates([]) :- !, 265 format("No updates available.\n"). 266pp_available_updates([_]) :- !, 267 format("1 update available:\n"). 268pp_available_updates(Updates) :- 269 length(Updates, N), 270 format("~D updates available:\n", [N]). 271 272ppm_updates_row(update(User,Repo,CurrentVersion,LatestVersion)) :- 273 format(" • ~a/~a\t", [User,Repo]), 274 compare_version(Order, CurrentVersion, LatestVersion), 275 order_colors(Order, Color1, Color2), 276 phrase(version(CurrentVersion), CurrentCodes), 277 ansi_format([fg(Color1)], "~s", [CurrentCodes]), 278 format(" → "), 279 phrase(version(LatestVersion), LatestCodes), 280 ansi_format([fg(Color2)], "~s\n", [LatestCodes]). 281 282order_colors(<, red, green). 283order_colors(>, green, red). 284 285 286 287 288 289% INITIALIZATION % 290 291init_ppm :- 292 root_directory(Root), 293 ensure_directory_exists(Root), 294 ppm_sync_(Root)
Prolog Package Manager (PPM)
A simple package manager for SWI-Prolog.