the requirements of a rule can be placed anywhere within the
rule, as long as you put them before they are needed. *)
+(** {2 Periodic jobs}
+
+ If you want to have a rule that runs when some outside event
+ happens you have three choices: Manually run the script (this is
+ basically what [make] forces you to do). Have some sort of hook
+ that runs the script (eg. a git hook). Or use a periodic job to
+ poll for an event or change.
+
+ Periodic jobs run regularly to poll for an outside event or
+ change. If a script has periodic jobs, then it runs continuously
+ (or until you kill it).
+
+ An example of a script that checks for new git commits and when
+ it sees one it will ensure it passes the tests:
+
+ {v
+ let repo = Sys.getenv "HOME" // "repo"
+
+ let goal git_commit_tested commit =
+ let key = sprintf "repo-tested-%s" commit in
+ target (memory_exists key);
+
+ sh "
+ git clone %s test
+ cd test
+ ./configure
+ make
+ make check
+ ";
+
+ (* Record that this commit was tested successfully. *)
+ memory_set key "1"
+
+ every 30 minutes (fun () ->
+ let commit = shout "cd %s && git rev-parse HEAD" repo in
+ (* Require that this commit has been tested. *)
+ require (git_commit_tested commit)
+ )
+ }
+
+ Some notes about the above example: Firstly only the current HEAD
+ commit is required to be tested. This is because older commits
+ are irrelevant and because if they failed the test before there is
+ not point retesting them (commits are immutable). Secondly we use
+ the Memory to remember that we have successfully tested a commit.
+ This is what stops the program from repeatedly testing the same
+ commit. *)
+
+(* This is what lets you write '30 minutes' etc: *)
+type period_t = Seconds | Days | Months | Years
+val seconds : int * period_t
+val sec : int * period_t
+val secs : int * period_t
+val second : int * period_t
+val minutes : int * period_t
+val min : int * period_t
+val mins : int * period_t
+val minute : int * period_t
+val hours : int * period_t
+val hour : int * period_t
+val days : int * period_t
+val day : int * period_t
+val weeks : int * period_t
+val week : int * period_t
+val months : int * period_t
+val month : int * period_t
+val years : int * period_t
+val year : int * period_t
+
+val every : ?name:string -> int -> int * period_t -> (unit -> unit) -> unit
+ (** [every N (seconds|minutes|hours|days|weeks|months|years) f]
+ runs the function [f] periodically.
+
+ The optional [~name] parameter can be used to name the job
+ (for debugging). *)
+
(** {2 File and URL testing}
Various functions to test the existence of files, URLs.