1(** GPX Eio I/O operations *)
2
3(** Read GPX from file path *)
4let read_file ?(validate=false) path =
5 let content = Eio.Path.load 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) path gpx =
12 match Gpx.write_string ~validate gpx with
13 | Ok xml_string ->
14 Eio.Path.save ~create:(`Or_truncate 0o644) 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 = Eio.Path.is_file
33
34(** Get file size *)
35let file_size path =
36 try
37 let stat = Eio.Path.stat ~follow:true path in
38 Optint.Int63.to_int stat.size
39 with
40 | exn -> raise (Gpx.Gpx_error (Gpx.Error.io_error (Printexc.to_string exn)))
41
42(** Create backup of existing file *)
43let create_backup ((fs, inner_path) as path) =
44 if file_exists path then
45 let backup_path = inner_path ^ ".backup" in
46 let content = Eio.Path.load path in
47 Eio.Path.save ~create:(`Or_truncate 0o644) (fs, backup_path) content;
48 Some (fs, backup_path)
49 else
50 None
51
52(** Write GPX to file with automatic backup *)
53let write_file_with_backup ?(validate=false) path gpx =
54 let backup_path = create_backup path in
55 try
56 write_file ~validate path gpx;
57 backup_path
58 with
59 | Gpx.Gpx_error _ as err ->
60 (* Try to restore backup if write failed *)
61 match backup_path with
62 | Some backup_path ->
63 if file_exists backup_path then (
64 try
65 let backup_content = Eio.Path.load backup_path in
66 Eio.Path.save ~create:(`Or_truncate 0o644) path backup_content
67 with _ -> () (* Ignore restore errors *)
68 );
69 raise err
70 | _ -> raise err