Module Goaljobs

module Goaljobs: sig .. end

Goaljobs library API




Target and require


val target : bool -> unit
target condition defines the target condition that will be met once the current goal has run.

You can think of the target as a promise or contract that you make, which is met by running the rest of the goal.

Goaljobs is much more flexible than make. In make only a single type of target is possible. The following are roughly equivalent:

      foo.o: foo.c
        ...
     

      let goal compiled () =
        target (more_recent ["foo.o"] ["foo.c"]);
        require (file_exists "foo.c");
        ...
     

Targets in goaljobs can be any arbitrary expression. For example, it can access network resources or test URLs.

Almost every goal should have one target, which should accurately state the outcome once the goal has been run.

It is possible to have no target. This means the goal always runs (like using "force" in make).

You should not have multiple targets in a single goal. They won't work the way you expect, and future versions of goaljobs will likely stop you from doing this.

Normally you put the target(s) early on in the goal, before any running code and before any requires. This is not a hard-and-fast rule and it is not enforced, but doing it will ensure the goal runs most efficiently since if the target is met already then the rest of the goal doesn't run.

val target_all : bool list -> unit
target_all [t1; t2; ...] is the same as writing target (t1 && t2 && ...)
val target_exists : bool list -> unit
target_exists [t1; t2; ...] is the same as writing target (t1 || t2 || ...)
val require : (unit -> unit) -> unit
require goal defines the requirements of this goal, that is, other goals that have to be met before the rest of the goal is able to run.

In terms of make, requires are roughly equivalent to the right hand side after the :, but in goaljobs the requirements can be much richer than simply "that file must exist".

Some very simple goals don't need any requires. You can have as many requires as you need in a goal, and you can use a loop or make them conditional if you want.

Unlike make, the requirements of a goal can be placed anywhere within the goal, as long as you put them before they are needed.


Periodic jobs


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).


File and URL testing

Various functions to test the existence of files, URLs.

val file_exists : string -> bool
Return true if the named file exists.

This function also exists as a goal. Writing:

require (file_exists "somefile");
will die unless "somefile" exists.
val directory_exists : string -> bool
Return true if the named directory exists.

There is also a goal version of this function.

val file_newer_than : string -> string -> bool
file_newer_than file_a file_b returns true if file_a is newer than file_b. Note that if file_a does not exist, it returns false. If file_b does not exist, it is an error.

There is also a goal version of this function.

val more_recent : string list -> string list -> bool
more_recent objects sources expresses the make relationship:

object(s) ...: source(s) ...

in a convenient way:

      let goal built objects sources =
        target (more_recent objects sources);
        ... code to rebuild ...
     

It is roughly equivalent to checking that all the object files exist and are newer than all of the source files.

Note that both parameters are lists (since in make you can have a list of source files and a list of object files). If you don't want a list, pass a single-element list containing the single the object/source file.

There is also a goal version of this function.

val url_exists : string -> bool
The URL is tested to see if it exists.

There is also a goal version of this function.

val file_contains_string : string -> string -> bool
file_contains_string filename str checks if the named file contains the given substring str.

There is also a goal version of this function.

val url_contains_string : string -> string -> bool
url_contains_string url str downloads the URL and checks whether the content contains the given substring str.

There is also a goal version of this function.

val (//) : string -> string -> string
Concatenate two paths.
val quote : string -> string
Quote the string to make it safe to pass directly to the shell.

Shell


val sh : ?tmpdir:bool -> ('a, unit, string, unit) Pervasives.format4 -> 'a
Run the command(s).

The command runs in a newly created temporary directory (which is deleted after the command exits), unless you use ~tmpdir:false.

val shout : ?tmpdir:bool -> ('a, unit, string, string) Pervasives.format4 -> 'a
Run the command(s).

Anything printed on stdout is returned as a string. The trailing \n character, if any, is not returned.

The command runs in a newly created temporary directory (which is deleted after the command exits), unless you use ~tmpdir:false.

val shlines : ?tmpdir:bool -> ('a, unit, string, string list) Pervasives.format4 -> 'a
Run the command(s).

Any lines printed to stdout is returned as a list of strings. Trailing \n characters are not returned.

The command runs in a newly created temporary directory (which is deleted after the command exits), unless you use ~tmpdir:false.

val shell : string Pervasives.ref
Set this variable to override the default shell (/bin/sh).

String functions

Most string functions are provided by the OCaml standard library (see the module String). For convenience some extra functions are provided here.

val change_file_extension : string -> string -> string
change_file_extension ext filename changes the file extension of filename to .ext. For example change_file_extension "o" "main.c" returns "main.o". If the original filename has no extension, this function adds the extension.

Memory (persistent key/value storage)


val memory_exists : string -> bool
memory_exists key checks that the named key exists in the Memory. It doesn't matter what value it has.

This is also available as a goal, so you can write require (memory_exists key)

val memory_set : string -> string -> unit
Set key to value in the Memory.
val memory_get : string -> string option
Return the current value of key in the Memory. Returns None if the key has never been set or was deleted.
val memory_delete : string -> unit
Delete the key. If the key doesn't exist, has no effect.

Publishing goals


val publish : string -> (string list -> unit) -> unit
Publish the named goal.

Use this function as in this example:

      let goal compiled program sources =
        ... stuff for building the program from sources ...

      let () = publish "compiled" (
        fun args ->
          let program = List.hd args in
          let sources = List.tl args in
          require (compiled program sources)
      )
     

This could be used as follows:

./script compiled program main.c utils.c

You will notice you have to write a bit of OCaml code to map the string arguments from the command line on to the goal arguments. In the example it means taking the first string argument as the program name, and the rest of the string arguments as the source filenames. This is also the place to perform string to int conversion, checks, and so on (remember that OCaml is strongly typed).