GPS Exchange Format library/CLI in OCaml
1(** GPX Eio I/O operations *)
2
3(** Read GPX from file path *)
4let read_file ?(validate=false) ~fs path =
5 let content = Eio.Path.load Eio.Path.(fs / path) in
6 match Gpx.parse_string ~validate content with
7 | Ok gpx -> gpx
8 | Error err -> raise (Gpx.Gpx_error err)
9
10(** Write GPX to file path *)
11let write_file ?(validate=false) ~fs path gpx =
12 match Gpx.write_string ~validate gpx with
13 | Ok xml_string ->
14 Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / path) xml_string
15 | Error err -> raise (Gpx.Gpx_error err)
16
17(** Read GPX from Eio source *)
18let read_source ?(validate=false) source =
19 let content = Eio.Flow.read_all source in
20 match Gpx.parse_string ~validate content with
21 | Ok gpx -> gpx
22 | Error err -> raise (Gpx.Gpx_error err)
23
24(** Write GPX to Eio sink *)
25let write_sink ?(validate=false) sink gpx =
26 match Gpx.write_string ~validate gpx with
27 | Ok xml_string ->
28 Eio.Flow.copy_string xml_string sink
29 | Error err -> raise (Gpx.Gpx_error err)
30
31(** Check if file exists *)
32let file_exists ~fs path =
33 try
34 let _stat = Eio.Path.stat ~follow:true Eio.Path.(fs / path) in
35 true
36 with
37 | _ -> false
38
39(** Get file size *)
40let file_size ~fs path =
41 try
42 let stat = Eio.Path.stat ~follow:true Eio.Path.(fs / path) in
43 Optint.Int63.to_int stat.size
44 with
45 | exn -> raise (Gpx.Gpx_error (Gpx.Error.io_error (Printexc.to_string exn)))
46
47(** Create backup of existing file *)
48let create_backup ~fs path =
49 if file_exists ~fs path then
50 let backup_path = path ^ ".backup" in
51 let content = Eio.Path.load Eio.Path.(fs / path) in
52 Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / backup_path) content;
53 backup_path
54 else
55 ""
56
57(** Write GPX to file with automatic backup *)
58let write_file_with_backup ?(validate=false) ~fs path gpx =
59 let backup_path = create_backup ~fs path in
60 try
61 write_file ~validate ~fs path gpx;
62 backup_path
63 with
64 | Gpx.Gpx_error _ as err ->
65 (* Try to restore backup if write failed *)
66 if backup_path <> "" && file_exists ~fs backup_path then (
67 try
68 let backup_content = Eio.Path.load Eio.Path.(fs / backup_path) in
69 Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / path) backup_content
70 with _ -> () (* Ignore restore errors *)
71 );
72 raise err