source: code/trunk/cli/convert.ml@ 42

Last change on this file since 42 was 42, checked in by fox, 2 years ago

Preliminary support for cross-domain references

File size: 5.4 KB
Line 
1open Logarion
2
3(*TODO: move to converters (style, feed checks)*)
4let is_older s d = try Unix.((stat d).st_mtime < (stat s).st_mtime) with _-> true
5
6let convert cs r (text, files) = match Text.str "Content-Type" text with
7 | "" | "text/plain" ->
8 let source = List.hd files in
9 let dest = Filename.concat r.Conversion.dir (Text.short_id text) in
10 List.fold_left
11 (fun a f ->
12 match f.Conversion.page with None -> false || a
13 | Some page ->
14 let dest = dest ^ f.Conversion.ext in
15 (if is_older source dest then (File_store.file dest (page r text); true) else false)
16 || a)
17 false cs
18 | x -> Printf.eprintf "Can't convert Content-Type: %s file: %s" x text.Text.title; false
19
20let converters types kv =
21 let n = String.split_on_char ',' types in
22 let t = [] in
23 let t = if List.(mem "all" n || mem "htm" n) then (Html.converter kv)::t else t in
24 let t = if List.(mem "all" n || mem "atom" n) then (Atom.converter "text/html")::t else t in
25 let t = if List.(mem "all" n || mem "gmi" n) then (Gemini.converter)::t else t in
26 let t = if List.(mem "all" n || mem "gmi-atom" n) then (Atom.converter "text/gemini")::t else t in
27 t
28
29let acc_rel source target a =
30 prerr_endline source;
31 Conversion.Id_map.update target
32 (function Some set -> Some (Conversion.Ref_set.add source set)
33 | None -> Some (Conversion.Ref_set.singleton source))
34 a
35
36let empty_rels () = Conversion.Id_map.empty, Conversion.Id_map.empty
37
38let acc_txt_refs text refs = String_set.fold (acc_rel text.Text.id) (Text.set "references" text) refs
39let acc_txt_reps text reps = String_set.fold (acc_rel text.Text.id) (Text.set "in-reply-to" text) reps
40let acc_txt_rels (refs, reps) (elt, _paths) =
41 acc_txt_refs elt refs, acc_txt_reps elt reps
42
43let acc_pck_refs id refs_ls refs = String_set.fold (acc_rel id) (String_set.of_list refs_ls) refs
44let acc_pck_reps id reps_ls reps = String_set.fold (acc_rel id) (String_set.of_list reps_ls) reps
45let acc_pck_rels refs_reps peer =
46 let path = try List.hd peer.Peers.pack.Header_pack.info.locations with Failure _ -> "" in
47 try Header_pack.fold
48 (fun (refs, reps) id _t _title _authors _topics refs_ls reps_ls ->
49 let id = Filename.concat path id in
50 acc_pck_refs id refs_ls refs, acc_pck_reps id reps_ls reps)
51 refs_reps peer.Peers.pack
52 with e -> prerr_endline "acc_pck_rels"; raise e
53
54let directory converters noindex repo =
55 let order = File_store.oldest in
56 let repo =
57 let references, replies =
58 File_store.fold ~dir:repo.Conversion.dir ~order acc_txt_rels (empty_rels ()) in
59 let references, replies = Peers.fold acc_pck_rels (references, replies) in
60 Printf.eprintf "%s %d\n" repo.Conversion.dir (Conversion.Id_map.cardinal replies);
61 { repo with references; replies } in
62 let acc (ts,ls,acc) ((elt,_) as r) = Topic_set.to_map ts (Text.set "topics" elt), elt::ls,
63 if convert converters repo r then acc+1 else acc in
64 let topics, texts, count =
65 File_store.fold ~dir:repo.Conversion.dir ~order acc (Topic_set.Map.empty, [], 0) in
66 let topic_roots = try List.rev @@ String_set.list_of_csv (Store.KV.find "Topics" repo.kv)
67 with Not_found -> Topic_set.roots topics in
68 let repo = Conversion.{ repo with topic_roots; topics; texts = List.rev texts } in
69 if not noindex then
70 List.iter (fun c -> match c.Conversion.indices with None -> () | Some f -> f repo) converters;
71 Printf.printf "Converted: %d Indexed: %d\n" count (List.length texts)
72
73let load_kv dir =
74 let kv = File_store.of_kv_file () in
75 let idx = Filename.concat dir "index.pck" in
76 if not (Sys.file_exists idx) then kv else
77 match Header_pack.of_string @@ File_store.to_string (idx) with
78 | Error s -> prerr_endline s; kv
79 | Ok { info; peers; _ } ->
80 let kv = if Store.KV.mem "Id" kv then kv else Store.KV.add "Id" info.Header_pack.id kv in
81 let kv = if Store.KV.mem "Title" kv then kv else Store.KV.add "Title" info.Header_pack.title kv in
82 let kv = if Store.KV.mem "Locations" kv then kv else Store.KV.add "Locations" (String.concat ";\n" info.Header_pack.locations) kv in
83 let kv = Store.KV.add "Peers" (String.concat ";\n" Header_pack.(to_str_list peers)) kv in
84 kv
85
86let at_path types noindex path = match path with
87 | "" -> prerr_endline "unspecified text file or directory"
88 | path when Sys.file_exists path ->
89 if Sys.is_directory path then (
90 let kv = load_kv path in
91 let repo = { (Conversion.empty ()) with dir = path; kv } in
92 directory (converters types kv) noindex repo
93 ) else (
94 match File_store.to_text path with
95 | Error s -> prerr_endline s
96 | Ok text ->
97 let dir = "." in
98 let references, replies = File_store.(fold ~dir ~order:newest acc_txt_rels (empty_rels ())) in
99 let repo = { (Conversion.empty ()) with dir; kv = load_kv ""; references; replies } in
100 ignore @@ convert (converters types repo.kv) repo (text, [path])
101 )
102 | path -> Printf.eprintf "Path doesn't exist: %s" path
103
104open Cmdliner
105let term =
106 let path = Arg.(value & pos 0 string "" & info [] ~docv:"path"
107 ~doc:"Text file or directory to convert. If directory is provided, it must contain an index.pck (see: txt index)") in
108 let types = Arg.(value & opt string "all" & info ["t"; "type"] ~docv:"output type"
109 ~doc:"Convert to file type") in
110 let noindex = Arg.(value & flag & info ["noindex"]
111 ~doc:"Don't create indices in target format") in
112 Term.(const at_path $ types $ noindex $ path),
113 Term.info "convert" ~doc:"convert texts"
114 ~man:[ `S "DESCRIPTION"; `P "Convert text or indexed texts within a directory to another format.
115 If path is a directory must contain an index.pck. Run `txt index` first." ]
Note: See TracBrowser for help on using the repository browser.