source: code/trunk/lib/file_store.ml@ 3

Last change on this file since 3 was 3, checked in by fox, 3 years ago
  • Removed 'txt init'

Format

  • New B32 ID

Index

  • New option: txt index --print
  • Move scheme to peers
  • Replace peer.*.conf files with index packed locations Instead of adding a URL to peers.*.conf, run txt pull <url>

Conversion

  • Rewritten converters
  • txt-convert looks for a .convert.conf containing key: value lines.
  • Specifiable topic-roots from .convert.conf.
  • Added Topics: key, with comma seperated topics.

If set only those topics will appear in the main index and used as topic roots.
Other topics will have sub-indices generated, but won't be listed in the main index.

  • HTML converter header & footer options
  • HTML-index renamed to HTM-index

Internal

  • Change types: uuid:Uuid -> id:string
  • File_store merges identical texts
  • Use peer ID for store path, store peers' texts in .local/share/texts
  • Simple URN resolution for converter

Continue to next feed if parsing one fails

  • Phasing-out Archive, replaced by improved packs
  • Eliminate Bos, Cohttp, lwt, uri, tls, Re, Ptime, dependencies
  • Lock version for Cmdliner, fix dune-project
  • Optional resursive store
  • Improve header_pack
  • Fix recursive mkdir
File size: 5.3 KB
Line 
1type t = string
2type item_t = t list
3type record_t = Text.t * item_t
4
5let extension = ".txt"
6let def_dir = try Sys.getenv "LOGARION_DIR" with Not_found -> "."
7
8let to_string f =
9 let ic = open_in f in
10 let s = really_input_string ic (in_channel_length ic) in
11 close_in ic;
12 s
13
14let fold_file_line fn init file = match open_in file with
15 | exception (Sys_error msg) -> prerr_endline msg; init
16 | file ->
17 let rec read acc = match input_line file with
18 | "" as s | s when String.get s 0 = '#' -> read acc
19 | s -> read (fn s acc)
20 | exception End_of_file -> close_in file; acc
21 in read init
22
23let file path str = let o = open_out path in output_string o str; close_out o
24
25let to_text path =
26 if Filename.extension path = extension then
27 (to_string path |> Text.of_string |> Result.map_error (fun m -> path ^": "^ m))
28 else Error (Printf.sprintf "Not txt: %s" path)
29
30let newest (a,_pa) (b,_pb) = Text.newest a b
31let oldest (a,_pa) (b,_pb) = Text.oldest a b
32
33let list_iter fn dir paths =
34 let link f = match to_text (Filename.concat dir f) with
35 | Ok t -> fn dir t f | Error s -> prerr_endline s in
36 List.iter link paths
37
38module TextMap = Map.Make(Text)
39
40type iteration_t = item_t TextMap.t
41let new_iteration = TextMap.empty
42
43(*let iter_valid_text pred fn path =*)
44(* match to_text path with Error _ -> () | Ok t -> if pred t then fn (t, p)*)
45
46let fold_valid_text pred it path =
47 match to_text path with Error _ -> it
48 | Ok t -> if pred t then (TextMap.update t
49 (function None -> Some [path] | Some ps -> Some (path::ps)) it
50 ) else it
51
52(* Compare file system nodes to skip reparsing? *)
53let list_fs ?(r=false) dir =
54 let valid_dir f = r && String.get f 0 <> '.' && Sys.is_directory f in
55 let expand_dir d = Array.(to_list @@ map (Filename.concat d) (Sys.readdir d)) in
56 let rec loop result = function
57 | f::fs when valid_dir f -> expand_dir f |> List.append fs |> loop result
58 | f::fs -> loop (f::result) fs
59 | [] -> result in
60 let dirs = if dir = "." then Array.to_list (Sys.readdir dir) else
61 if not r then expand_dir dir else [dir] in
62 loop [] dirs
63
64let list_take n =
65 let rec take acc n = function [] -> []
66 | x::_ when n = 1 -> x::acc
67 | x::xs -> take (x::acc) (n-1) xs
68 in take [] n
69
70let fold_sort_take ?(predicate=fun _ -> true) ?(number=None) comp flist =
71 (match number with None -> (fun x -> x) | Some n -> list_take n)
72 @@ List.fast_sort comp @@ TextMap.bindings
73 @@ List.fold_left (fold_valid_text predicate) new_iteration flist
74
75let iter ?(r=false) ?(dir=def_dir) ?(predicate=fun _ -> true) ?order ?number fn =
76 let flist = list_fs ~r dir in match order with
77 | Some comp -> List.iter fn @@ fold_sort_take ~predicate ~number comp flist
78 | None -> List.iter fn @@ TextMap.bindings @@
79 List.fold_left (fold_valid_text predicate) new_iteration flist
80
81let fold ?(r=false) ?(dir=def_dir) ?(predicate=fun _ -> true) ?order ?number fn acc =
82 let flist = list_fs ~r dir in match order with
83 | Some comp -> List.fold_left fn acc @@ fold_sort_take ~predicate ~number comp flist
84 | None -> List.fold_left fn acc @@ TextMap.bindings @@
85 List.fold_left (fold_valid_text predicate) new_iteration flist
86
87let with_id ?(r=false) ?(dir=def_dir) id =
88 let matched acc path =
89 match to_text path with
90 | Error x -> prerr_endline x; acc
91 | Ok text when text.Text.id <> id -> acc
92 | Ok text ->
93 match acc with
94 | Ok None -> Ok (Some text)
95 | Ok (Some prev) -> if prev = text then acc else Error [text; prev]
96 | Error x -> Error (text :: x)
97 in List.fold_left matched (Ok None) (list_fs ~r dir)
98
99let with_dir ?(descr="") ?(perm=0o740) dir =
100 let mkdir dir = match Unix.mkdir dir perm with
101 | exception Unix.Unix_error (EEXIST, _, _) -> ()
102 | exception Unix.Unix_error (code, _fn, arg) ->
103 failwith @@ Printf.sprintf "Error %s making %s dir: %s"
104 (Unix.error_message code) descr arg
105 | _ -> () in
106 let rec mkeach path = function [] | [""] -> () | ""::t -> mkeach path t
107 | hd::t -> let d = Filename.concat path hd in mkdir d; mkeach d t in
108 mkeach
109 (if Filename.is_relative dir then "" else "/")
110 (String.split_on_char '/' dir)
111
112let rec with_dirs = function [] -> () | (d, descr)::tl -> with_dir ~descr d; with_dirs tl
113
114let versioned_basename_of_title ?(version=0) repo extension (title : string) =
115 let basename = Text.string_alias title in
116 let rec next version =
117 let candidate = Filename.concat repo
118 (basename ^ "." ^ string_of_int version ^ extension) in
119 if Sys.file_exists candidate then next (succ version) else candidate
120 in
121 next version
122
123let id_filename repo extension text =
124 let basename = Text.alias text in
125 let candidate = Filename.concat repo (text.id ^ "." ^ basename ^ extension) in
126 if Sys.file_exists candidate then Error "Name clash, try again" else Ok candidate
127
128let with_text ?(dir=def_dir) new_text =
129 match id_filename dir extension new_text with
130 | Error _ as e -> e
131 | Ok path ->
132 try file path (Text.to_string new_text); Ok (path, new_text)
133 with Sys_error s -> Error s
134
135module Config = struct
136 type t = string Store.KV.t
137 let key_value k v a = Store.KV.add k (String.trim v) a
138end
139
140let of_kv_file path =
141 let open Text_parse in
142 let subsyntaxes = Parsers.Key_value.[|
143 (module Make (Config) : Parser.S with type t = Config.t); (module Make (Config)); |] in
144 let of_string text acc =
145 Parser.parse subsyntaxes { text; pos = 0; right_boundary = String.length text - 1 } acc in
146 of_string (to_string @@ path) Store.KV.empty
Note: See TracBrowser for help on using the repository browser.