Cached at:
05/16/26, 07:09 AM
# Prolog Projects Tips
Source: [https://occasionallycogent.com/prolog_project_helpers/index.html](https://occasionallycogent.com/prolog_project_helpers/index.html)
This one is a little more involved, to the point it’s written in Prolog instead of bash\. I run it to generate a new release for the library\.
The first part is pretty simple:`update\_pack\_version/2`parses the version number in the`pack\.pl`file, increments it based on whether the new version is major, minor, or patch \(using`increment\_version/3`\), then writes the new number back\.`git\_commit\_and\_tag/1`does what it says, plus pushes it up`origin`\.
The final step, implemented by`register\_new\_pack/1`is a bit more mysterious\. It fixes the somewhat annoying issue that after pushing a new version, I have to manually install that new version by URL to get the SWI\-Prolog server to see the new version & register it \(so normal users can just run`pack\_upgrade\(Whatever\)`\)\. Previously I would just manually`pack\_remove/1`the package in a top\-level and run`pack\_install/2`, explicitly passing the URL of the bundle to install, but of course, we can automate that\!
Knowing that’s why we’re doing this hopefully makes`register\_new\_pack/1`less mysterious\. The`download\_pattern\_format\_string/2`helper predicate turns the pattern in`pack\.pl`into a format string \(e\.g\.`'https://example\.com/release/\*\.zip'`to`"https://example\.com/release/~w\.zip"`\) so we can use`format/3`to download the new archive for the new version\. Unfortunately there’s some special\-casing for repos that are still on Github, as for reasons I do not recall the actual download URL and the one specified in the pack file are different, hence the first clause of the predicate\.
Finally,`main/1`checks that a valid release type was given, prompts for confirmation, then does the thing\. I added the prompt after I accidentally ran the script from history when trying to re\-run tests and had to force\-push one too many times 😅
Listing 3:scripts/make\_release\.pl
```
#!/usr/bin/env swipl
:- module(make_release, []).
:- use_module(library(readutil), [read_file_to_terms/3,
read_line_to_string/2]).
:- initialization(main, main).
increment_version(major, [Major0, _Minor, _Patch], [Major1, 0, 0]) :- !,
succ(Major0, Major1).
increment_version(minor, [Major, Minor0, _Patch], [Major, Minor1, 0]) :- !,
succ(Minor0, Minor1).
increment_version(patch, [Major, Minor, Patch0], [Major, Minor, Patch1]) :- !,
succ(Patch0, Patch1).
update_pack_version(ReleaseType, NewVersion) :-
read_file_to_terms('pack.pl', PackTerms, []),
memberchk(version(OldVersion), PackTerms),
atomic_list_concat([MajorS, MinorS, PatchS], '.', OldVersion),
maplist(atom_number, [MajorS, MinorS, PatchS], VersionNums0),
increment_version(ReleaseType, VersionNums0, VersionNums1),
atomic_list_concat(VersionNums1, '.', NewVersion),
once(select(version(OldVersion), PackTerms, version(NewVersion), NewPackTerms)),
setup_call_cleanup(open('pack.pl', write, S, []),
forall(member(T, NewPackTerms),
write_term(S, T, [fullstop(true),
nl(true),
quoted(true),
spacing(next_argument)
])),
close(S)).
git_commit_and_tag(NewVersion) :-
shell('git add pack.pl'),
shell('git commit -m "Bump version"'),
format(atom(TagCmd), "git tag v~w", [NewVersion]),
shell(TagCmd),
format(atom(PushCmd), 'git push origin master v~w', [NewVersion]),
shell(PushCmd).
download_pattern_format_string(DownloadURLPat, FormatString) :-
string_concat("https://github.com", _, DownloadURLPat), !,
string_concat(Prefix, "releases/*.zip", DownloadURLPat),
string_concat(Prefix, "archive/refs/tags/v~w.zip", FormatString).
download_pattern_format_string(DownloadURLPat, FormatString) :-
file_name_extension(Base0, Ext, DownloadURLPat),
string_concat(Base, "*", Base0),
format(string(FormatString), "~s~s.~s", [Base, "v~w", Ext]).
register_new_pack(NewVersion) :-
read_file_to_terms('pack.pl', PackTerms, []),
memberchk(name(ProjectName), PackTerms),
memberchk(download(DownloadURLPattern), PackTerms),
download_pattern_format_string(DownloadURLPattern, URLFormat),
( pack_remove(ProjectName) -> true ; true ),
format(atom(Url), URLFormat, [NewVersion]),
pack_install(ProjectName, [url(Url), interactive(false)]).
main(Args) :-
( Args = [ReleaseType], increment_version(ReleaseType, [0, 0, 0], _)
-> true
; ( format(user_error, "Usage: make_release.pl [major|minor|patch]~n", []),
halt(1) ) ),
( stream_property(user_input, tty(true))
-> format("Make new release? [y/n]: ", []),
read_line_to_string(user_input, Input),
Input == "y"
; true ),
update_pack_version(ReleaseType, NewVersion),
format("Bumping to ~w~n", [NewVersion]),
git_commit_and_tag(NewVersion),
register_new_pack(NewVersion).
```
May these be of some use to you in using & learning Prolog\! Some day soon I will try to stitch these together, along with some other helpful libraries, tools, and templates I habitually use, into a nice unified tool that will help bring Prolog to more of a mainstream developer audience\. Until then, enjoy and use wisely\!