Use Bytes instead of String for mutable byte array.
[goaljobs.git] / goaljobs.mli
1 (* goaljobs
2  * Copyright (C) 2013 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *)
18
19 (** {1 Goaljobs library API} *)
20
21 (** {2 Target and require} *)
22
23 val target : bool -> unit
24   (** [target] {i condition} defines the target condition that {b will}
25       be met once the current goal has run.
26
27       You can think of the target as a promise or contract that you
28       make, which is met by running the rest of the goal.
29
30       Goaljobs is much more flexible than [make].  In [make] only a
31       single type of target is possible.  The following are roughly
32       equivalent:
33
34       {v
35       foo.o: foo.c
36         ...
37       v}
38
39       {v
40       let goal compiled () =
41         target (more_recent ["foo.o"] ["foo.c"]);
42         require (file_exists "foo.c");
43         ...
44       v}
45
46       Targets in goaljobs can be any arbitrary expression.  For
47       example, it can access network resources or test URLs.
48
49       Almost every goal should have one target, which should
50       accurately state the outcome once the goal has been run.
51
52       It is possible to have no target.  This means the goal
53       always runs (like using "force" in make).
54
55       You should not have multiple targets in a single goal.  They
56       won't work the way you expect, and future versions of goaljobs
57       will likely stop you from doing this.
58
59       Normally you put the target(s) early on in the goal, before any
60       running code and before any [require]s.  This is not a
61       hard-and-fast rule and it is not enforced, but doing it will
62       ensure the goal runs most efficiently since if the target is met
63       already then the rest of the goal doesn't run. *)
64
65 val target_all : bool list -> unit
66   (** [target_all [t1; t2; ...]] is the same as writing
67       [target (t1 && t2 && ...)] *)
68
69 val target_exists : bool list -> unit
70   (** [target_exists [t1; t2; ...]] is the same as writing
71       [target (t1 || t2 || ...)] *)
72
73 val require : string -> (unit -> unit) -> unit
74   (** [require] {i goal} defines the requirements of this goal, that
75       is, other goals that have to be met before the rest of the
76       goal is able to run.
77
78       In terms of [make], [require]s are roughly equivalent to the
79       right hand side after the [:], but in goaljobs the requirements
80       can be much richer than simply "that file must exist".
81
82       Some very simple goals don't need any [require]s.  You can
83       have as many [require]s as you need in a goal, and you can
84       use a loop or make them conditional if you want.
85
86       Unlike [make], the requirements of a goal can be
87       placed anywhere within the goal, as long as you put them
88       before they are needed. *)
89
90 (** {2 Periodic jobs} *)
91
92 (* This is what lets you write '30 minutes' etc: *)
93 type period_t = Seconds | Days | Months | Years
94 val seconds : int * period_t
95 val sec : int * period_t
96 val secs : int * period_t
97 val second : int * period_t
98 val minutes : int * period_t
99 val min : int * period_t
100 val mins : int * period_t
101 val minute : int * period_t
102 val hours : int * period_t
103 val hour : int * period_t
104 val days : int * period_t
105 val day : int * period_t
106 val weeks : int * period_t
107 val week : int * period_t
108 val months : int * period_t
109 val month : int * period_t
110 val years : int * period_t
111 val year : int * period_t
112
113 val every : ?name:string -> int -> int * period_t -> (unit -> unit) -> unit
114   (** [every N (seconds|minutes|hours|days|weeks|months|years) f]
115       runs the function [f] periodically.
116
117       The optional [~name] parameter can be used to name the job
118       (for debugging). *)
119
120 (** {2 File and URL testing}
121
122     Various functions to test the existence of files, URLs.
123 *)
124
125 val file_exists : string -> bool
126   (** Return true if the named file exists.
127
128       This function also exists as a goal.  Writing:
129       {v require (file_exists "somefile"); v}
130       will die unless ["somefile"] exists. *)
131
132 val directory_exists : string -> bool
133   (** Return true if the named directory exists.
134
135       There is also a goal version of this function. *)
136
137 val file_newer_than : string -> string -> bool
138   (** [file_newer_than file_a file_b] returns true if [file_a] is
139       newer than [file_b].  Note that if [file_a] does not exist, it
140       returns false.  If [file_b] does not exist, it is an error.
141
142       There is also a goal version of this function. *)
143
144 val more_recent : string list -> string list -> bool
145   (** [more_recent objects sources] expresses the [make] relationship:
146
147       {v object(s) ...: source(s) ... v}
148
149       in a convenient way:
150
151       {v
152       let goal built objects sources =
153         target (more_recent objects sources);
154         ... code to rebuild ...
155       v}
156
157       It is roughly equivalent to checking that all the object files
158       exist and are newer than all of the source files.
159
160       Note that both parameters are lists (since in [make] you can
161       have a list of source files and a list of object files).  If you
162       don't want a list, pass a single-element list containing the
163       single the object/source file.
164
165       There is also a goal version of this function. *)
166
167 val url_exists : string -> bool
168   (** The URL is tested to see if it exists.
169
170       There is also a goal version of this function. *)
171
172 val file_contains_string : string -> string -> bool
173   (** [file_contains_string filename str] checks if the named file
174       contains the given substring [str].
175
176       There is also a goal version of this function. *)
177
178 val url_contains_string : string -> string -> bool
179   (** [url_contains_string url str] downloads the URL and checks
180       whether the content contains the given substring [str].
181
182       There is also a goal version of this function. *)
183
184 val (//) : string -> string -> string
185   (** Concatenate two paths. *)
186
187 val quote : string -> string
188   (** Quote the string to make it safe to pass directly to the shell. *)
189
190 (** {2 Shell} *)
191
192 val sh : ?tmpdir:bool -> ('a, unit, string, unit) format4 -> 'a
193   (** Run the command(s).
194
195       The command runs in a newly created temporary directory (which
196       is deleted after the command exits), {i unless} you use
197       [~tmpdir:false]. *)
198
199 val shout : ?tmpdir:bool -> ('a, unit, string, string) format4 -> 'a
200   (** Run the command(s).
201
202       Anything printed on stdout is returned as a string.
203       The trailing [\n] character, if any, is not returned.
204
205       The command runs in a newly created temporary directory (which
206       is deleted after the command exits), {i unless} you use
207       [~tmpdir:false]. *)
208
209 val shlines : ?tmpdir:bool -> ('a, unit, string, string list) format4 -> 'a
210   (** Run the command(s).
211
212       Any lines printed to stdout is returned as a list of strings.
213       Trailing [\n] characters are not returned.
214
215       The command runs in a newly created temporary directory (which
216       is deleted after the command exits), {i unless} you use
217       [~tmpdir:false]. *)
218
219 val shell : string ref
220   (** Set this variable to override the default shell ([/bin/sh]). *)
221
222 (** {2 String functions}
223
224     Most string functions are provided by the OCaml standard
225     library (see the module [String]).  For convenience some
226     extra functions are provided here. *)
227
228 (*
229 val replace_substring : string -> string -> string -> string
230   (** [replace_substring patt repl string] replaces all occurrences
231       of [patt] with [repl] in [string]. *)
232 *)
233
234 val change_file_extension : string -> string -> string
235   (** [change_file_extension ext filename] changes the file extension
236       of [filename] to [.ext].  For example
237       [change_file_extension "o" "main.c"] returns ["main.o"].
238       If the original filename has no extension, this function
239       adds the extension. *)
240
241 (*
242 val filter_file_extension : string -> string list -> string
243   (** [filter_file_extension ext filenames] returns only those
244       filenames in the list which have the given file extension.
245       For example [filter_file_extension "o" ["foo.c"; "bar.o"]]
246       would return [["bar.o"]] (a single element list). *)
247 *)
248
249 (** {2 Memory (persistent key/value storage)} *)
250
251 val memory_exists : string -> bool
252   (** [memory_exists key] checks that the named [key] exists in
253       the Memory.  It doesn't matter what value it has.
254
255       This is also available as a goal, so you can write
256       [require (memory_exists key)] *)
257
258 val memory_set : string -> string -> unit
259   (** Set [key] to [value] in the Memory. *)
260
261 val memory_get : string -> string option
262   (** Return the current value of [key] in the Memory.  Returns [None]
263       if the key has never been set or was deleted. *)
264
265 val memory_delete : string -> unit
266   (** Delete the [key].  If the key doesn't exist, has no effect. *)
267
268 val memory_list : unit -> (string * string) list
269   (** Return all [(key, value)] pairs in the memory. *)
270
271 (** {2 Publishing goals} *)
272
273 val publish : string -> (string list -> unit) -> unit
274   (** Publish the named goal.
275
276       Use this function as in this example:
277
278       {v
279       let goal compiled program sources =
280         ... stuff for building the program from sources ...
281
282       let () = publish "compiled" (
283         fun args ->
284           let program = List.hd args in
285           let sources = List.tl args in
286           require (compiled program sources)
287       )
288       v}
289
290       This could be used as follows:
291
292       {v ./script compiled program main.c utils.c v}
293
294       You will notice you have to write a bit of OCaml code to
295       map the string arguments from the command line on to the
296       goal arguments.  In the example it means taking the first
297       string argument as the program name, and the rest of the
298       string arguments as the source filenames.  This is also
299       the place to perform string to int conversion, checks, and
300       so on (remember that OCaml is strongly typed). *)
301
302 (** {2 Logging script output} *)
303
304 val log_program_output : unit -> string
305   (** [log_program_output] should be called at most once, usually at
306       the top-level of the script.  It creates a temporary file
307       and redirects stdout and stderr into this file (they are still
308       sent to the ordinary output, so it acts like [tee]).  The
309       filename of the temporary file is returned. *)
310
311 (** {2 Sending email} *)
312
313 val mailto : ?from:string -> subject:string -> ?attach:string list-> string -> unit
314   (** Send email.
315
316       Optional [?from] is the sender email address.
317
318       Required [~subject] is the subject line.
319
320       Optional [?attach] is a list of attachments (filenames).
321
322       The bare argument is the destination email address. *)
323
324 (**/**)
325
326 (* Goal versions of some common functions.  You are using these
327  * versions when you write something like:
328  *   require (file_exists "foo");
329  * They work the same way as the regular function, except they die
330  * if the predicate returns false.
331  *)
332 val goal_file_exists : string -> unit
333 val goal_directory_exists : string -> unit
334 val goal_file_newer_than : string -> string -> unit
335 val goal_more_recent : string list -> string list -> unit
336 val goal_url_exists : string -> unit
337 val goal_file_contains_string : string -> string -> unit
338 val goal_url_contains_string : string -> string -> unit
339 val goal_memory_exists : string -> unit
340
341 (* A single call to this function is added by the 'goaljobs' script.
342  * It is responsible for parsing the command line and so on.
343  *)
344 val init : unit -> unit
345
346 (* Export this so the macros can catch these exceptions. *)
347 type goal_result_t = Goal_OK | Goal_failed of string
348 exception Goal_result of goal_result_t
349
350 (* Called to print debug message when we enter or leave a goal. *)
351 val _enter_goal : string -> unit
352 val _leave_goal : string -> unit