<commit_before>% * -*- Mode: Prolog -*- */

:- module(plmake,
          [
           build/1,
           build/2,
           consult_buildfile/0,
           consult_buildfile/1,

           target_bindrule/2,
           rule_dependencies/3,
           is_rebuild_required/4
           ]).

/** <module> Prolog implementation of Makefile-inspired build system

  See the README

  */



% ----------------------------------------
% TOP-LEVEL
% ----------------------------------------

%% build(+Target)
%% build(+Target, +Opts:list)
%% build(+Target, +Stack:list,+Opts:list)
%
% builds Target using rules

build(T) :-
        build(T,[]).
build(T,Opts) :-
        build(T,[],Opts).

build(T,SL,Opts) :-
        %report('Target: ~w',[T]),
        debug_report(build,'  Target: ~w',[T],SL),
        target_bindrule(T,Rule),
        debug_report(build,'  Bindrule: ~w',[Rule],SL),
        rule_dependencies(Rule,DL,Opts),
        report('NT: ~w <-- ~w',[T,DL],SL,Opts),
        !,
        build_targets(DL,[T|SL],Opts), % semidet
        (   is_rebuild_required(T,DL,SL,Opts)
        ->  rule_execs(Rule,Execs,Opts),
            run_execs(Execs,Opts)
        ;   true),
        report('NT: ~w is up to date',[T],SL,Opts).
build(T,SL,Opts) :-
        debug_report(build,'  checking if rebuild required for ~w',[T],SL),
        \+ is_rebuild_required(T,[],SL,Opts),
        !,
        report('T: ~w exists',[T],SL,Opts).
build(T,SL,Opts) :-
        report('T: ~w FAILED',[T],SL,Opts),
        !,
        fail.

% potentially split this into two steps:
%  phase 1 iterates through targets and initiates any jobs
%  phase 2 checks all jobs are done
build_targets([],_,_).
build_targets([T|TL],SL,Opts) :-
        build(T,SL,Opts),
        build_targets(TL,SL,Opts).

% ----------------------------------------
% REPORTING
% ----------------------------------------

report(Fmt,Args,Opts) :-
        report(Fmt,Args,[],Opts).

report(Fmt,Args,SL,_) :-
        stack_indent(SL,Fmt,IndentedFmt),
        format(IndentedFmt,Args),
        nl.

stack_indent([],Text,Text).
stack_indent([_|T],Text,Indented) :-
        string_concat('    ',Text,Tab),
	stack_indent(T,Tab,Indented).

debug_report(Topic,Fmt,Args) :-
        debug_report(Topic,Fmt,Args,[]).

debug_report(Topic,Fmt,Args,SL) :-
        stack_indent(SL,Fmt,IndentedFmt),
	debug(Topic,IndentedFmt,Args).

% ----------------------------------------
% DEPENDENCY MANAGEMENT
% ----------------------------------------

is_rebuild_required(T,_,SL,Opts) :-
        member(always_make(true),Opts), % TODO
        target_bindrule(T,_),
        !,
        report('Specified --always-make; building target ~w',[T],SL,Opts).
is_rebuild_required(T,_,SL,Opts) :-
        \+ exists_target(T,Opts),
        !,
        report('Target ~w not materialized - will rebuild if required',[T],SL,Opts).
is_rebuild_required(T,DL,SL,Opts) :-
        \+ exists_directory(T),
        member(D,DL),
        is_built_after(D,T,Opts),
        !,
        report('Target ~w built before dependency ~w - rebuilding',[T,D],SL,Opts).


is_built_after(A,B,_Opts) :-
        time_file(A,TA),
        time_file(B,TB),
        TA > TB.

exists_target(T,_Opts) :-
        exists_file(T).
exists_target(T,_Opts) :-
        exists_directory(T).
<commit_msg>Reordered is_rebuild_required to only check --always-make as a last resort, yielding more informative log messages<commit_after>% * -*- Mode: Prolog -*- */

:- module(plmake,
          [
           build/1,
           build/2,
           consult_buildfile/0,
           consult_buildfile/1,

           target_bindrule/2,
           rule_dependencies/3,
           is_rebuild_required/4
           ]).

/** <module> Prolog implementation of Makefile-inspired build system

  See the README

  */



% ----------------------------------------
% TOP-LEVEL
% ----------------------------------------

%% build(+Target)
%% build(+Target, +Opts:list)
%% build(+Target, +Stack:list,+Opts:list)
%
% builds Target using rules

build(T) :-
        build(T,[]).
build(T,Opts) :-
        build(T,[],Opts).

build(T,SL,Opts) :-
        %report('Target: ~w',[T]),
        debug_report(build,'  Target: ~w',[T],SL),
        target_bindrule(T,Rule),
        debug_report(build,'  Bindrule: ~w',[Rule],SL),
        rule_dependencies(Rule,DL,Opts),
        report('NT: ~w <-- ~w',[T,DL],SL,Opts),
        !,
        build_targets(DL,[T|SL],Opts), % semidet
        (   is_rebuild_required(T,DL,SL,Opts)
        ->  rule_execs(Rule,Execs,Opts),
            run_execs(Execs,Opts)
        ;   true),
        report('NT: ~w is up to date',[T],SL,Opts).
build(T,SL,Opts) :-
        debug_report(build,'  checking if rebuild required for ~w',[T],SL),
        \+ is_rebuild_required(T,[],SL,Opts),
        !,
        report('T: ~w exists',[T],SL,Opts).
build(T,SL,Opts) :-
        report('T: ~w FAILED',[T],SL,Opts),
        !,
        fail.

% potentially split this into two steps:
%  phase 1 iterates through targets and initiates any jobs
%  phase 2 checks all jobs are done
build_targets([],_,_).
build_targets([T|TL],SL,Opts) :-
        build(T,SL,Opts),
        build_targets(TL,SL,Opts).

% ----------------------------------------
% REPORTING
% ----------------------------------------

report(Fmt,Args,Opts) :-
        report(Fmt,Args,[],Opts).

report(Fmt,Args,SL,_) :-
        stack_indent(SL,Fmt,IndentedFmt),
        format(IndentedFmt,Args),
        nl.

stack_indent([],Text,Text).
stack_indent([_|T],Text,Indented) :-
        string_concat('    ',Text,Tab),
	stack_indent(T,Tab,Indented).

debug_report(Topic,Fmt,Args) :-
        debug_report(Topic,Fmt,Args,[]).

debug_report(Topic,Fmt,Args,SL) :-
        stack_indent(SL,Fmt,IndentedFmt),
	debug(Topic,IndentedFmt,Args).

% ----------------------------------------
% DEPENDENCY MANAGEMENT
% ----------------------------------------

is_rebuild_required(T,_,SL,Opts) :-
        \+ exists_target(T,Opts),
        !,
        report('Target ~w not materialized - will rebuild if required',[T],SL,Opts).
is_rebuild_required(T,DL,SL,Opts) :-
        \+ exists_directory(T),
        member(D,DL),
        is_built_after(D,T,Opts),
        !,
        report('Target ~w built before dependency ~w - rebuilding',[T,D],SL,Opts).
is_rebuild_required(T,_,SL,Opts) :-
        member(always_make(true),Opts),
        target_bindrule(T,_),
        !,
        report('Specified --always-make; rebuilding target ~w',[T],SL,Opts).

is_built_after(A,B,_Opts) :-
        time_file(A,TA),
        time_file(B,TB),
        TA > TB.

exists_target(T,_Opts) :-
        exists_file(T).
exists_target(T,_Opts) :-
        exists_directory(T).

{'fraction_non_alphanumeric': 0.23079245283018868, 'fraction_numerical': 0.002716981132075472, 'mean_word_length': 2.0977092099111734, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3272049', 'n_tokens_mistral': 2293, 'n_tokens_neox': 2250, 'n_words': 337}