about summary refs log tree commit diff
diff options
context:
space:
mode:
authorsternenseemann <git@lukasepple.de>2017-02-17 22:49:07 +0100
committersternenseemann <git@lukasepple.de>2017-02-17 22:49:07 +0100
commit3b5d541fb8cf320783ad07776f88ce5b9aa8431c (patch)
tree7522c34eaf0c69e0789c429d41a8318c33db2f6d
parent61f32a011b2eeecbd9ba2dcc36cb42b117fb1e87 (diff)
Introduce logbook command line for generating HTML files of log files
-rw-r--r--README.md9
-rw-r--r--_tags3
-rw-r--r--example.log20
-rw-r--r--opam2
-rw-r--r--pkg/META2
-rwxr-xr-xpkg/pkg.ml3
-rw-r--r--src/log.ml8
-rw-r--r--src/log.mli2
-rw-r--r--src/logbook.ml34
-rw-r--r--src/logbook_models.ml21
-rw-r--r--src/logbook_template.ml25
11 files changed, 116 insertions, 13 deletions
diff --git a/README.md b/README.md
index 75304fd..1874b0f 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,15 @@ The 42nd day of the year.
 
 + Public information.
   foo bar
-
 - Private information.
   Additional block
-
 * Semi-private information.
   More text!
 ```
+
+## Installation & Usage
+
+```
+opam pin add logbook https://gitlab.glaxx.net/sternenseemann/logbook.git
+logbook --file example.log [ --private | --public | --semi-private ]
+```
diff --git a/_tags b/_tags
index 0dcebae..c94104e 100644
--- a/_tags
+++ b/_tags
@@ -1,3 +1,4 @@
 true : bin_annot, safe_string, package(bytes ptime angstrom astring)
-
 <src> : include
+
+<src/logbook*> : package(lwt lwt.unix jingoo)
diff --git a/example.log b/example.log
index 0c19185..1d23a9f 100644
--- a/example.log
+++ b/example.log
@@ -1,9 +1,17 @@
 [2017-02-14]
-Test
+Got the log parser into a working state
 
-+ Hi this is a test
-  Hi?
-  Is this working?
++ Implemented Angstrom parsers
+  Still kinda ugly and not perfect, need a bit of work.
+- This is private
+  Well not really, just testing this out…
 
-- private
-  foobar?
+[2017-02-17]
+Implemented logbook cli
+
++ Open & parse file with Lwt
+  Why is it so hard to even open a file in OCaml?
++ Reworked parser
+  I applied more applicative style, making the parser much better.
+  Also I fixed an annoying bug, where you could not omit the empty line between items.
+  Still not working are substitutes and proper failure whilst parsing.
diff --git a/opam b/opam
index 594bc29..7f99fd2 100644
--- a/opam
+++ b/opam
@@ -15,6 +15,8 @@ depends: [
   "ptime"
   "angstrom"
   "astring"
+  "lwt"
+  "jingoo"
   ]
 depopts: []
 build: [
diff --git a/pkg/META b/pkg/META
index 37cd0b8..bb2b70f 100644
--- a/pkg/META
+++ b/pkg/META
@@ -1,6 +1,6 @@
 description = "tool for personal log files"
 version = "%%VERSION_NUM%%"
-requires = "ptime angstrom astring"
+requires = "ptime angstrom astring lwt jingoo"
 archive(byte) = "logbook.cma"
 archive(native) = "logbook.cmxa"
 plugin(byte) = "logbook.cma"
diff --git a/pkg/pkg.ml b/pkg/pkg.ml
index ec3d818..0909c4d 100755
--- a/pkg/pkg.ml
+++ b/pkg/pkg.ml
@@ -5,4 +5,5 @@ open Topkg
 
 let () =
   Pkg.describe "logbook" @@ fun c ->
-  Ok [ Pkg.mllib "src/log.mllib"; ]
+  Ok [ Pkg.mllib "src/log.mllib";
+       Pkg.bin "src/logbook" ~dst:"logbook"; ]
diff --git a/src/log.ml b/src/log.ml
index d02fc8f..3a4b95a 100644
--- a/src/log.ml
+++ b/src/log.ml
@@ -22,6 +22,9 @@ let privacy_level_of_char = function
 
 type item = Item of privacy_level * string * string
 
+let filter_privacy_level mode items =
+  List.filter (fun (Item (p, _, _)) -> compatible_privacy p mode) items
+
 type log_entry = Log_entry of Ptime.date * string * item list
 
 type log = log_entry list
@@ -75,9 +78,10 @@ let log_entryp =
   <*> (skip_many empty_line *> spaced_list itemp)
 
 (* Parser TODO
- * - test edge cases (omitted, added parts, empty lines etc.)
  * - substitutions
- * - clean up block parser
+ * - markdown/other markup
+ * - proper failure if not
+ *   the whole output is consumed
  * …
  *)
 let log_parser =
diff --git a/src/log.mli b/src/log.mli
index a4bde39..e62acea 100644
--- a/src/log.mli
+++ b/src/log.mli
@@ -32,6 +32,8 @@ val compatible_privacy : privacy_level -> privacy_level -> bool
 (** Get the corresponding privacy level for a char *)
 val privacy_level_of_char : char -> privacy_level option
 
+val filter_privacy_level : privacy_level -> item list -> item list
+
 (** {2 Log Parsing} 
 
     log files are parsed using {{:https://github.com/inhabitedtype/angstrom}angstrom}.
diff --git a/src/logbook.ml b/src/logbook.ml
new file mode 100644
index 0000000..baef3ef
--- /dev/null
+++ b/src/logbook.ml
@@ -0,0 +1,34 @@
+open Lwt
+open Lwt.Infix
+
+let parse_file f =
+  Lwt_io.with_file Lwt_io.Input f (fun c ->
+    Lwt_io.read c >>= (fun s ->
+      return (Angstrom.parse_only Log.log_parser (`String s))))
+
+let input_file = ref None
+let privacy = ref Log.Public
+
+let arglist =
+  [ ("--file", Arg.String (fun f -> input_file := Some f), "log file to use");
+    ("--private", Arg.Unit (fun () -> privacy := Log.Private),
+    "set privacy level of output to private");
+    ("--public", Arg.Unit (fun () -> privacy := Log.Public),
+    "set privacy level of output to public");
+    ("--semi-private", Arg.Unit (fun () -> privacy := Log.Semi_private),
+    "set privacy level of output to semi-private");
+  ]
+
+let usage = Sys.argv.(0) ^ " --file [file.log] [other args]"
+
+let _ =
+  Arg.parse arglist (fun _ -> ()) usage;
+  match !input_file with
+  | None -> print_endline "No file supplied"
+  | Some f -> let log = Lwt_main.run (parse_file f >>= fun log ->
+      match log with
+      | Result.Error msg -> failwith msg
+      | Result.Ok log -> return log)
+  in print_string (Jg_template.from_string
+    Logbook_template.template
+    ~models:(Logbook_models.model_of_log !privacy log))
diff --git a/src/logbook_models.ml b/src/logbook_models.ml
new file mode 100644
index 0000000..6f64bac
--- /dev/null
+++ b/src/logbook_models.ml
@@ -0,0 +1,21 @@
+open Jg_types
+
+let string_of_date (y, m, d) =
+  string_of_int y ^ "-" ^ string_of_int m ^ "-" ^ string_of_int d
+
+let data_model_of_items mode items =
+  Log.filter_privacy_level mode items
+  |> List.map (fun (Log.Item (_, tt, tx)) ->
+      Tobj [ ("title", Tstr tt); ("text", Tstr tx); ])
+
+let model_of_log level log =
+  [ ("entries", Tlist (List.map
+    (fun (Log.Log_entry (date, summary, items)) ->
+      Tobj [
+        ("summary", Tstr summary);
+        ("date", Tstr (string_of_date date));
+        ("items", Tlist (data_model_of_items level items));
+      ])
+    log))
+  ]
+
diff --git a/src/logbook_template.ml b/src/logbook_template.ml
new file mode 100644
index 0000000..36fbc5f
--- /dev/null
+++ b/src/logbook_template.ml
@@ -0,0 +1,25 @@
+let template = "<!doctype html>
+<html>
+<head>
+  <meta charset=\"utf-8\">
+  <title>log</title>
+</head>
+<body>
+  <main>
+    <h1>log</h1>
+    {% for entry in entries %}
+    <article>
+      <h2>{{ entry.date }}</h2>
+      <p>{{ entry.summary }}</p>
+      <ul>
+      {% for item in entry.items %}
+        <li>
+          <p><em>{{ item.title }}</em></p>
+          <p>{{ item.text }}</p>
+        </li>
+      {% endfor %}
+      </ul>
+    </article>
+    {% endfor %}
+  </main>
+</body>"