[1] | 1 | let version = "0.5"
|
---|
| 2 | open Cmdliner
|
---|
| 3 | open Logarion
|
---|
| 4 | module C = Archive.Configuration
|
---|
| 5 | module Lpath = Logarion.Lpath
|
---|
| 6 |
|
---|
| 7 | let conf () =
|
---|
| 8 | let module Config = Confix.Config.Make (Confix.ConfixToml) in
|
---|
| 9 | let archive_res =
|
---|
| 10 | let open Confix.Config in
|
---|
| 11 | Confix.Config.Path.with_file "config.toml"
|
---|
| 12 | &> Config.from_path
|
---|
| 13 | |> Config.to_record C.of_config
|
---|
| 14 | in
|
---|
| 15 | match archive_res with
|
---|
| 16 | | Ok config -> config
|
---|
| 17 | | Error str -> prerr_endline str; exit 1
|
---|
| 18 |
|
---|
| 19 | let create_dir dir = Bos.OS.Dir.create (Fpath.v dir)
|
---|
| 20 |
|
---|
| 21 | let create_dir_msg ?(descr="") dir res =
|
---|
| 22 | let () = match res with
|
---|
| 23 | | Ok true -> print_endline ("Created " ^ descr ^ " directory " ^ dir)
|
---|
| 24 | | Ok false -> print_endline ("Reinitialise existing " ^ descr ^ " directory " ^ dir)
|
---|
| 25 | | Error (`Msg msg) -> prerr_endline @@ "Failed making " ^ descr ^ ". " ^ msg
|
---|
| 26 | in
|
---|
| 27 | res
|
---|
| 28 |
|
---|
| 29 | let copy ?(recursive = false) src dst =
|
---|
| 30 | Bos.OS.Cmd.run (Bos.Cmd.(v "cp" %% (on recursive @@ v "-r") % src % dst))
|
---|
| 31 |
|
---|
| 32 | let init _force =
|
---|
| 33 | let rec create_dirs = function
|
---|
| 34 | | [] -> ()
|
---|
| 35 | | (dir,descr)::tl ->
|
---|
| 36 | match create_dir dir |> create_dir_msg ~descr dir with
|
---|
| 37 | | Ok _ -> create_dirs tl
|
---|
| 38 | | Error _ -> ()
|
---|
| 39 | in
|
---|
| 40 | let dirs = [
|
---|
| 41 | ".logarion", "Logarion";
|
---|
| 42 | ".logarion/static", "static files";
|
---|
| 43 | ".logarion/html-templates", "templates";
|
---|
| 44 | ]
|
---|
| 45 | in
|
---|
| 46 | let toml_data =
|
---|
| 47 | let open Toml in
|
---|
| 48 | let open TomlTypes in
|
---|
| 49 | of_key_values [
|
---|
| 50 | key "archive",
|
---|
| 51 | TTable (
|
---|
| 52 | of_key_values [
|
---|
| 53 | key "title", TString "";
|
---|
| 54 | key "owner", TString (Bos.OS.Env.opt_var "USER" ~absent:"");
|
---|
| 55 | key "email", TString (Bos.OS.Env.opt_var "EMAIL" ~absent:"");
|
---|
| 56 | key "uuid", TString (Meta.Id.(generate () |> to_string));
|
---|
| 57 | ]);
|
---|
| 58 | key "web",
|
---|
| 59 | TTable (
|
---|
| 60 | of_key_values [
|
---|
| 61 | key "url", TString "http://localhost:3666";
|
---|
| 62 | key "stylesheets", TArray ( NodeString ["main.css"] );
|
---|
| 63 | key "static_dir", TString ".logarion/static";
|
---|
| 64 | ]);
|
---|
| 65 | key "templates", TTable (of_key_values []);
|
---|
| 66 | ]
|
---|
| 67 | in
|
---|
| 68 | create_dirs dirs;
|
---|
| 69 | let config_file = open_out "config.toml" in
|
---|
| 70 | output_bytes config_file (Toml.Printer.string_of_table toml_data |> Bytes.of_string);
|
---|
| 71 | close_out config_file
|
---|
| 72 |
|
---|
| 73 | let init_term =
|
---|
| 74 | let force =
|
---|
| 75 | let doc = "Initialise repository even if directory is non empty" in
|
---|
| 76 | Arg.(value & flag & info ["f"; "force"] ~doc)
|
---|
| 77 | in
|
---|
| 78 | Term.(const init $ force),
|
---|
| 79 | Term.info
|
---|
| 80 | "init" ~doc:"initialise a logarion repository in present directory"
|
---|
| 81 | ~man:[ `S "DESCRIPTION"; `P "Create a repository in current directory" ]
|
---|
| 82 |
|
---|
| 83 | let create_term =
|
---|
| 84 | let title =
|
---|
| 85 | Arg.(value & pos 0 string "" & info [] ~docv:"TITLE" ~doc:"Title for new article")
|
---|
| 86 | in
|
---|
| 87 | let f title =
|
---|
| 88 | let conf = conf () in
|
---|
| 89 | let t = match title with "" -> "Draft" | _ -> title in
|
---|
| 90 | let note =
|
---|
| 91 | let meta =
|
---|
| 92 | let open Meta in
|
---|
| 93 | let authors = AuthorSet.singleton Author.({ name = conf.C.owner; address = Uri.of_string conf.C.email }) in
|
---|
| 94 | let date = Date.({ created = Some (Ptime_clock.now ()); published = None; edited = None }) in
|
---|
| 95 | { (blank ()) with title = t; authors; date }
|
---|
| 96 | in
|
---|
| 97 | Note.({ (blank ()) with meta })
|
---|
| 98 | in
|
---|
| 99 | File.Lwt.with_note (File.store conf.C.repository) note
|
---|
| 100 | |> Lwt_main.run
|
---|
| 101 | |> ignore
|
---|
| 102 | in
|
---|
| 103 | Term.(const f $ title),
|
---|
| 104 | Term.info "create"
|
---|
| 105 | ~doc:"create a new article"
|
---|
| 106 | ~man:[ `S "DESCRIPTION"; `P "Create a new article, with title 'Draft' when none provided"]
|
---|
| 107 |
|
---|
| 108 | let convert directory =
|
---|
| 109 | let module Config = Confix.Config.Make (Confix.ConfixToml) in
|
---|
| 110 |
|
---|
| 111 | let toml_config =
|
---|
| 112 | let open Confix.Config in
|
---|
| 113 | Path.with_file "config.toml"
|
---|
| 114 | |> function Ok cfg -> Config.from_path cfg | Error str -> prerr_endline str; exit 1
|
---|
| 115 | in
|
---|
| 116 | let config = Config.to_record_or_exit Logarion.Archive.Configuration.of_config toml_config in
|
---|
| 117 |
|
---|
| 118 | let module L = Logarion.Archive.Make(File) in
|
---|
| 119 | let store = File.store config.repository in
|
---|
| 120 | let archive = L.{ config; store } in
|
---|
| 121 | let notes =
|
---|
| 122 | List.filter Meta.(fun n -> CategorySet.published n.Note.meta.categories)
|
---|
| 123 | @@ File.to_list L.note_lens archive.store
|
---|
| 124 | in
|
---|
| 125 | let metas =
|
---|
| 126 | List.filter Meta.(fun m -> CategorySet.published m.categories && CategorySet.listed m.categories)
|
---|
| 127 | @@ File.to_list ~order:(L.recency_order) L.meta_lens archive.store
|
---|
| 128 | in
|
---|
| 129 |
|
---|
| 130 | let template_config = toml_config in
|
---|
| 131 | let module T = Converters.Template in
|
---|
| 132 | let header = T.header_converter template_config in
|
---|
| 133 | let body = T.body_converter template_config in
|
---|
| 134 | let style = T.default_style in
|
---|
| 135 | let linker x = match Fpath.(relativize ~root:(v "/") (v x)) with Some l -> Fpath.to_string l | None -> "" in
|
---|
| 136 | let page_of_log metas = T.page_of_log linker header config metas in
|
---|
| 137 | let page_of_index metas = T.page_of_index linker header config metas in
|
---|
| 138 | let page_of_note note = T.page_of_note linker header body config note in
|
---|
| 139 | let path_of_note note = directory ^ "/" ^ Meta.alias note.Note.meta ^ ".html" in
|
---|
| 140 | let file_creation path content =
|
---|
| 141 | let out = open_out path in
|
---|
| 142 | output_string out content;
|
---|
| 143 | close_out out
|
---|
| 144 | in
|
---|
| 145 | match create_dir directory |> create_dir_msg ~descr:"export" directory with
|
---|
| 146 | | Error _ -> ()
|
---|
| 147 | | Ok _ ->
|
---|
| 148 | match copy ~recursive:true ".logarion/static" (directory) with
|
---|
| 149 | | Ok _ ->
|
---|
| 150 | let note_write note = file_creation (path_of_note note) (page_of_note ~style note) in
|
---|
| 151 | List.iter note_write notes;
|
---|
| 152 | file_creation (directory ^ "/log.html") (page_of_log ~style metas);
|
---|
| 153 | file_creation (directory ^ "/index.html") (page_of_index ~style metas);
|
---|
| 154 | file_creation (directory ^ "/feed.atom") (Converters.Atom.feed config "/" (L.note_with_id archive) metas)
|
---|
| 155 | | Error (`Msg m) -> prerr_endline m
|
---|
| 156 |
|
---|
| 157 | let convert_term =
|
---|
| 158 | let directory =
|
---|
| 159 | Arg.(value & pos 0 string "html-conversion" & info [] ~docv:"Directory" ~doc:"Directory to convert to")
|
---|
| 160 | in
|
---|
| 161 | Term.(const convert $ directory),
|
---|
| 162 | Term.info
|
---|
| 163 | "convert" ~doc:"convert archive to HTML"
|
---|
| 164 | ~man:[ `S "DESCRIPTION"; `P "Create a repository in current directory" ]
|
---|
| 165 |
|
---|
| 166 | let default_cmd =
|
---|
| 167 | Term.(ret (const (`Help (`Pager, None)))),
|
---|
| 168 | Term.info "logarion" ~version ~doc:"an article collection & publishing system"
|
---|
| 169 | ~man:[ `S "BUGS";
|
---|
| 170 | `P "Submit bugs <mailto:logarion@lists.orbitalfox.eu?subject=[Issue] summary-here>"; ]
|
---|
| 171 |
|
---|
| 172 | let cmds = [ init_term; create_term; convert_term ]
|
---|
| 173 |
|
---|
| 174 | let () =
|
---|
| 175 | Random.self_init();
|
---|
| 176 | match Term.eval_choice default_cmd cmds with `Error _ -> exit 1 | _ -> exit 0
|
---|