From a9db63637ecbc5a5a84ae62de74d0bcbd285343a Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 20 Sep 2013 15:00:56 +0100 Subject: [PATCH] Generate ocamldoc, multiple documentation fixes. --- .gitignore | 1 + Makefile.am | 28 ++++++++++++++ configure.ac | 4 ++ goaljobs.mli | 116 ++++++++++++++++++++++++++++++-------------------------- html/.gitignore | 2 + 5 files changed, 98 insertions(+), 53 deletions(-) create mode 100644 html/.gitignore diff --git a/.gitignore b/.gitignore index 68cd58c..42a7a0b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ Makefile /META /missing /stamp-h1 +/stamp-ocamldoc diff --git a/Makefile.am b/Makefile.am index e752ae5..11d4fbd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,6 +85,34 @@ depend: .depend rpm: dist rpmbuild -ta $(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz +if HAVE_OCAMLDOC + +# HTML library documentation. +# XXX The list below probably changes with every ocamldoc version. +# How can we use a wildcard? +doc_DATA = \ + html/Goaljobs.html \ + html/index_attributes.html \ + html/index_classes.html \ + html/index_class_types.html \ + html/index_exceptions.html \ + html/index.html \ + html/index_methods.html \ + html/index_modules.html \ + html/index_module_types.html \ + html/index_types.html \ + html/index_values.html \ + html/style.css \ + html/type_Goaljobs.html + +$(doc_DATA): stamp-ocamldoc +stamp-ocamldoc: goaljobs.mli goaljobs.ml + rm -f $@ + $(OCAMLFIND) ocamldoc -html -d html $(OCAMLCPACKAGES) $^ + touch $@ + +endif + # License check. licensecheck: licensecheck $$(git ls-files) diff --git a/configure.ac b/configure.ac index 755c339..cdf9cfb 100644 --- a/configure.ac +++ b/configure.ac @@ -94,6 +94,10 @@ if test "x$CURL" = "x"; then AC_MSG_ERROR([You must install the 'curl' program]) fi +dnl ocamldoc (optional) +AM_CONDITIONAL([HAVE_OCAMLDOC], + [test "x$OCAMLDOC" != "xno"]) + dnl Check for POD (for manual pages). AC_CHECK_PROG(PERLDOC,perldoc,perldoc) if test "x$PERLDOC" = "x"; then diff --git a/goaljobs.mli b/goaljobs.mli index daaf0b2..3d342fa 100644 --- a/goaljobs.mli +++ b/goaljobs.mli @@ -18,16 +18,16 @@ (** {1 Goaljobs library of useful helper functions.} *) -(** {2 Targets and requires} +(** {2 Target and require} These are used to write goals. - Normally you write a goal with one or more [target]s and + Normally you write a goal with zero or one [target] and zero or more [require]s, as the examples below should make clear. - In the first example, there are two targets: that [o_file] (object) - exists, and that it is newer than [c_file] (source). The rule + In the first example, the target is that the [o_file] (object) exists + and is newer than the [c_file] (source). The goal meets that target by running the C compiler ([cc]) which, if it succeeds, will ensure that the object file exists and is newer than the source file. @@ -38,10 +38,10 @@ target (more_recent [o_file] [c_file]); sh "cd $builddir && cc -c %s -o %s" c_file o_file - } + v} - In the second example, the rule requires that several files - have been compiled ([require (compiled ...)] + In the second example, the goal requires that several files + have been compiled ([require (compiled ...)]) before it can link the final program: {v @@ -52,13 +52,16 @@ let object = change_file_extension "o" source in sh "cd $builddir && cc %s -o %s" object program - } + v} *) val target : bool -> unit (** [target] {i condition} defines the target condition that {b will} - be met once the current rule has run. + 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 @@ -67,30 +70,33 @@ val target : bool -> unit {v foo.o: foo.c ... + v} + {v let goal compiled () = target (more_recent ["foo.o"] ["foo.c"]); - requires (file_exists "foo.c"); + require (file_exists "foo.c"); ... - } + v} + + Targets in goaljobs can be any arbitrary expression. For + example, it can access network resources or test URLs. - Targets in goaljobs can be any arbitrary expression, and you - can have any number of different targets. + Almost every goal should have one target, which should + accurately state the outcome once the goal has been run. - Almost every rule should have one or more targets, which should - accurately state the outcome once the rule has been run. + It is possible to have no target. This means the goal + always runs (like using "force" in make). - If you have more than one [target]s then it's as if they have - been ORed together ({b not} ANDed which you might expect). - You can make this explicit by using a single target and [&&] - or [||] between the expressions. See also {!target_all} - and {!target_exists}. + 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 rule, before any + Normally you put the target(s) early on in the goal, before any running code and before any [require]s. This is not a hard-and-fast rule and it is not enforced, but doing it will - ensure the rule runs most efficiently since if the target is met - already then the rest of the rule doesn't run. *) + 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 @@ -101,20 +107,25 @@ val target_exists : bool list -> unit [target (t1 || t2 || ...)] *) val require : (unit -> unit) -> unit - (** [require] {!goal} defines the requirements of this rule, that - is, other goals that have to be met before this rule is able to run. + (** [require] {i 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], [require]s 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 rules don't need any [require]s. Unlike with [make], - the requirements of a rule can be placed anywhere within the - rule, as long as you put them before they are needed. *) + Some very simple goals don't need any [require]s. You can + have as many [require]s 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. *) (** {2 Periodic jobs} - If you want to have a rule that runs when some outside event + If you want to have a goal 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 @@ -131,16 +142,16 @@ val require : (unit -> unit) -> unit let repo = Sys.getenv "HOME" // "repo" let goal git_commit_tested commit = - let key = sprintf "repo-tested-%s" commit in - target (memory_exists key); + let key = sprintf "repo-tested-%s" commit in + target (memory_exists key); - sh " - git clone %s test - cd test - ./configure - make - make check - "; + sh " + git clone %s test + cd test + ./configure + make + make check + "; (* Record that this commit was tested successfully. *) memory_set key "1" @@ -150,7 +161,7 @@ val require : (unit -> unit) -> unit (* Require that this commit has been tested. *) require (git_commit_tested commit) ) - } + v} Some notes about the above example: Firstly only the current HEAD commit is required to be tested. This is because older commits @@ -197,7 +208,7 @@ val file_exists : string -> bool (** Return true if the named file exists. This function also exists as a goal. Writing: - {v require (file_exists "somefile");} + {v require (file_exists "somefile"); v} will die unless ["somefile"] exists. *) val directory_exists : string -> bool @@ -215,7 +226,7 @@ val file_newer_than : string -> string -> bool val more_recent : string list -> string list -> bool (** [more_recent objects sources] expresses the [make] relationship: - {v object(s) ...: source(s) ...} + {v object(s) ...: source(s) ... v} in a convenient way: @@ -223,7 +234,7 @@ val more_recent : string list -> string list -> bool let goal built objects sources = target (more_recent objects sources); ... code to rebuild ... - } + v} It is roughly equivalent to checking that all the object files exist and are newer than all of the source files. @@ -269,7 +280,7 @@ val quote : string -> string {v sh "rsync foo-%s.tar.gz example.com:/html/" version - } + v} Each invocation of {!sh} (etc) is a single shell (this is slightly different from how [make] works). For example: @@ -347,7 +358,7 @@ val filter_file_extension : string -> string list -> string would return [["bar.o"]] (a single element list). *) *) -(** {2 Memory (persistent key/value storage) +(** {2 Memory (persistent key/value storage)} "The Memory" is key/value storage which persists across goaljobs sessions. It is stored in the file [$HOME/.goaljobs-memory] @@ -370,19 +381,18 @@ val filter_file_extension : string -> string list -> string ... some work to test version ... memory_set key "1" - } + v} Note in that example the value ["1"] is arbitrary. You just want to store {i any} value so that a later call to {!memory_exists} - will succeed. -*) + will succeed. *) 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 - [requires (memory_exists key)] *) + [require (memory_exists key)] *) val memory_set : string -> string -> unit (** Set [key] to [value] in the Memory. *) @@ -404,15 +414,15 @@ val memory_delete : string -> unit {v let goal clean () = sh "rm *~" - } + v} can be used on the command line: - {v ./script clean } + {v ./script clean v} The special goal called [all] (if it exists) is run implicitly unless the user specifies another goal. Unlike [make], there is - nothing special about the first rule in the file. + nothing special about the first goal in the file. You can also publish goals, especially ones which take a non-zero number of parameters, by calling {!publish}. @@ -433,11 +443,11 @@ val publish : string -> (string list -> unit) -> unit let sources = List.tl args in require (compiled program sources) ) - } + v} This could be used as follows: - {v ./script compiled program main.c utils.c } + {v ./script compiled program main.c utils.c v} You will notice you have to write a bit of OCaml code to map the string arguments from the command line on to the diff --git a/html/.gitignore b/html/.gitignore new file mode 100644 index 0000000..d0098b4 --- /dev/null +++ b/html/.gitignore @@ -0,0 +1,2 @@ +*.css +*.html -- 1.8.3.1