Compare changes

Choose any two refs to compare.

+6 -3
bin/mlgpx_cli.ml
··· 3 open Cmdliner 4 open Gpx 5 6 (* Terminal and formatting setup *) 7 let setup_fmt style_renderer = 8 Fmt_tty.setup_std_outputs ?style_renderer (); ··· 67 log_info "Reading GPX file: %a" (bold_style Fmt.string) input_file; 68 69 (* Read input GPX *) 70 - let gpx = Gpx_eio.read ~fs input_file in 71 72 if verbose then 73 log_info "Found %d waypoints and %d existing tracks" ··· 140 log_info "Writing output to: %a" (bold_style Fmt.string) output_file; 141 142 (* Write output GPX *) 143 - Gpx_eio.write ~fs output_file output_gpx; 144 145 if verbose then ( 146 Fmt.pf Format.std_formatter "%a\n" (success_style Fmt.string) "Conversion completed successfully!"; ··· 215 if verbose then 216 log_info "Analyzing GPX file: %a" (bold_style Fmt.string) input_file; 217 218 - let gpx = Gpx_eio.read ~fs input_file in 219 220 (* Header *) 221 Fmt.pf Format.std_formatter "%a\n" (bold_style Fmt.string) "GPX File Information"; ··· 255 let duration_span = Ptime.diff stop_time start_time in 256 match Ptime.Span.to_int_s duration_span with 257 | Some seconds -> 258 let days = seconds / 86400 in 259 let hours = (seconds mod 86400) / 3600 in 260 let minutes = (seconds mod 3600) / 60 in
··· 3 open Cmdliner 4 open Gpx 5 6 + let ( / ) = Eio.Path.( / ) 7 + 8 (* Terminal and formatting setup *) 9 let setup_fmt style_renderer = 10 Fmt_tty.setup_std_outputs ?style_renderer (); ··· 69 log_info "Reading GPX file: %a" (bold_style Fmt.string) input_file; 70 71 (* Read input GPX *) 72 + let gpx = Gpx_eio.read (fs / input_file) in 73 74 if verbose then 75 log_info "Found %d waypoints and %d existing tracks" ··· 142 log_info "Writing output to: %a" (bold_style Fmt.string) output_file; 143 144 (* Write output GPX *) 145 + Gpx_eio.write (fs / output_file) output_gpx; 146 147 if verbose then ( 148 Fmt.pf Format.std_formatter "%a\n" (success_style Fmt.string) "Conversion completed successfully!"; ··· 217 if verbose then 218 log_info "Analyzing GPX file: %a" (bold_style Fmt.string) input_file; 219 220 + let gpx = Gpx_eio.read (fs / input_file) in 221 222 (* Header *) 223 Fmt.pf Format.std_formatter "%a\n" (bold_style Fmt.string) "GPX File Information"; ··· 257 let duration_span = Ptime.diff stop_time start_time in 258 match Ptime.Span.to_int_s duration_span with 259 | Some seconds -> 260 + let ( / ) = Int.div in 261 let days = seconds / 86400 in 262 let hours = (seconds mod 86400) / 3600 in 263 let minutes = (seconds mod 3600) / 60 in
+3 -3
lib/gpx_eio/gpx_eio.ml
··· 3 module IO = Gpx_io 4 5 (** Read and parse GPX file *) 6 - let read ?(validate=false) ~fs path = IO.read_file ~validate ~fs path 7 8 (** Write GPX to file *) 9 - let write ?(validate=false) ~fs path gpx = IO.write_file ~validate ~fs path gpx 10 11 (** Write GPX to file with backup *) 12 - let write_with_backup ?(validate=false) ~fs path gpx = IO.write_file_with_backup ~validate ~fs path gpx 13 14 (** Read GPX from Eio source *) 15 let from_source ?(validate=false) source = IO.read_source ~validate source
··· 3 module IO = Gpx_io 4 5 (** Read and parse GPX file *) 6 + let read ?(validate=false) path = IO.read_file ~validate path 7 8 (** Write GPX to file *) 9 + let write ?(validate=false) path gpx = IO.write_file ~validate path gpx 10 11 (** Write GPX to file with backup *) 12 + let write_with_backup ?(validate=false) path gpx = IO.write_file_with_backup ~validate path gpx 13 14 (** Read GPX from Eio source *) 15 let from_source ?(validate=false) source = IO.read_source ~validate source
+7 -10
lib/gpx_eio/gpx_eio.mli
··· 38 These functions provide simple file I/O with the filesystem from {!Eio.Stdenv.fs}. *) 39 40 (** Read and parse GPX file. 41 - @param fs Filesystem capability 42 @param path File path to read 43 @param ?validate Optional validation flag (default: false) 44 @return GPX document 45 @raises Gpx.Gpx_error on read or parse failure *) 46 - val read : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t 47 48 (** Write GPX to file. 49 - @param fs Filesystem capability 50 @param path File path to write 51 @param gpx GPX document to write 52 @param ?validate Optional validation flag (default: false) 53 @raises Gpx.Gpx_error on write failure *) 54 - val write : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> unit 55 56 (** Write GPX to file with automatic backup. 57 - @param fs Filesystem capability 58 @param path File path to write 59 @param gpx GPX document to write 60 @param ?validate Optional validation flag (default: false) 61 - @return Backup file path (empty if no backup created) 62 @raises Gpx.Gpx_error on failure *) 63 - val write_with_backup : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> string 64 65 (** {2 Stream Operations} 66 ··· 71 @param ?validate Optional validation flag (default: false) 72 @return GPX document 73 @raises Gpx.Gpx_error on read or parse failure *) 74 - val from_source : ?validate:bool -> [> Eio.Flow.source_ty ] Eio.Resource.t -> Gpx.t 75 76 (** Write GPX to Eio sink. 77 @param sink Output flow 78 @param gpx GPX document 79 @param ?validate Optional validation flag (default: false) 80 @raises Gpx.Gpx_error on write failure *) 81 - val to_sink : ?validate:bool -> [> Eio.Flow.sink_ty ] Eio.Resource.t -> Gpx.t -> unit 82 83 (** Print GPX statistics to sink. 84 @param sink Output sink 85 @param gpx GPX document *) 86 - val print_stats : [> Eio.Flow.sink_ty ] Eio.Resource.t -> Gpx.t -> unit
··· 38 These functions provide simple file I/O with the filesystem from {!Eio.Stdenv.fs}. *) 39 40 (** Read and parse GPX file. 41 @param path File path to read 42 @param ?validate Optional validation flag (default: false) 43 @return GPX document 44 @raises Gpx.Gpx_error on read or parse failure *) 45 + val read : ?validate:bool -> _ Eio.Path.t -> Gpx.t 46 47 (** Write GPX to file. 48 @param path File path to write 49 @param gpx GPX document to write 50 @param ?validate Optional validation flag (default: false) 51 @raises Gpx.Gpx_error on write failure *) 52 + val write : ?validate:bool -> _ Eio.Path.t -> Gpx.t -> unit 53 54 (** Write GPX to file with automatic backup. 55 @param path File path to write 56 @param gpx GPX document to write 57 @param ?validate Optional validation flag (default: false) 58 + @return Backup file path ([None] if no backup created) 59 @raises Gpx.Gpx_error on failure *) 60 + val write_with_backup : ?validate:bool -> 'a Eio.Path.t -> Gpx.t -> 'a Eio.Path.t option 61 62 (** {2 Stream Operations} 63 ··· 68 @param ?validate Optional validation flag (default: false) 69 @return GPX document 70 @raises Gpx.Gpx_error on read or parse failure *) 71 + val from_source : ?validate:bool -> _ Eio.Flow.source -> Gpx.t 72 73 (** Write GPX to Eio sink. 74 @param sink Output flow 75 @param gpx GPX document 76 @param ?validate Optional validation flag (default: false) 77 @raises Gpx.Gpx_error on write failure *) 78 + val to_sink : ?validate:bool -> _ Eio.Flow.sink -> Gpx.t -> unit 79 80 (** Print GPX statistics to sink. 81 @param sink Output sink 82 @param gpx GPX document *) 83 + val print_stats : _ Eio.Flow.sink -> Gpx.t -> unit
+27 -29
lib/gpx_eio/gpx_io.ml
··· 1 (** GPX Eio I/O operations *) 2 3 (** Read GPX from file path *) 4 - let 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 *) 11 - let 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 *) ··· 29 | Error err -> raise (Gpx.Gpx_error err) 30 31 (** Check if file exists *) 32 - let 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 *) 40 - let 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 *) 48 - let 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 *) 58 - let 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
··· 1 (** GPX Eio I/O operations *) 2 3 (** Read GPX from file path *) 4 + let 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 *) 11 + let 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 *) ··· 29 | Error err -> raise (Gpx.Gpx_error err) 30 31 (** Check if file exists *) 32 + let file_exists = Eio.Path.is_file 33 34 (** Get file size *) 35 + let 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 *) 43 + let 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 *) 53 + let 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
+7 -13
lib/gpx_eio/gpx_io.mli
··· 8 (** {1 File Operations} *) 9 10 (** Read GPX from file path. 11 - @param fs Filesystem capability 12 @param path File path to read 13 @param ?validate Optional validation flag (default: false) 14 @return GPX document or error *) 15 - val read_file : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t 16 17 (** Write GPX to file path. 18 - @param fs Filesystem capability 19 @param path File path to write 20 @param gpx GPX document to write 21 @param ?validate Optional validation flag (default: false) 22 @raises Gpx.Gpx_error on write failure *) 23 - val write_file : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> unit 24 25 (** {1 Stream Operations} 26 ··· 41 (** {1 Utility Functions} *) 42 43 (** Check if file exists. 44 - @param fs Filesystem capability 45 @param path File path to check 46 @return [true] if file exists and is readable *) 47 - val file_exists : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> bool 48 49 (** Get file size. 50 - @param fs Filesystem capability 51 @param path File path 52 @return File size in bytes *) 53 - val file_size : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> int 54 55 (** Create backup of existing file. 56 - @param fs Filesystem capability 57 @param path Original file path 58 @return Backup file path *) 59 - val create_backup : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> string 60 61 (** Write GPX to file with automatic backup. 62 Creates a backup of existing file before writing new content. 63 - @param fs Filesystem capability 64 @param path File path to write 65 @param gpx GPX document to write 66 @param ?validate Optional validation flag (default: false) 67 - @return Backup file path (empty string if no backup needed) *) 68 - val write_file_with_backup : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> string
··· 8 (** {1 File Operations} *) 9 10 (** Read GPX from file path. 11 @param path File path to read 12 @param ?validate Optional validation flag (default: false) 13 @return GPX document or error *) 14 + val read_file : ?validate:bool -> _ Eio.Path.t -> Gpx.t 15 16 (** Write GPX to file path. 17 @param path File path to write 18 @param gpx GPX document to write 19 @param ?validate Optional validation flag (default: false) 20 @raises Gpx.Gpx_error on write failure *) 21 + val write_file : ?validate:bool -> _ Eio.Path.t -> Gpx.t -> unit 22 23 (** {1 Stream Operations} 24 ··· 39 (** {1 Utility Functions} *) 40 41 (** Check if file exists. 42 @param path File path to check 43 @return [true] if file exists and is readable *) 44 + val file_exists : _ Eio.Path.t -> bool 45 46 (** Get file size. 47 @param path File path 48 @return File size in bytes *) 49 + val file_size : _ Eio.Path.t -> int 50 51 (** Create backup of existing file. 52 @param path Original file path 53 @return Backup file path *) 54 + val create_backup : 'a Eio.Path.t -> 'a Eio.Path.t option 55 56 (** Write GPX to file with automatic backup. 57 Creates a backup of existing file before writing new content. 58 @param path File path to write 59 @param gpx GPX document to write 60 @param ?validate Optional validation flag (default: false) 61 + @return Backup file path ([None] if no backup needed) *) 62 + val write_file_with_backup : ?validate:bool -> 'a Eio.Path.t -> Gpx.t -> 'a Eio.Path.t option
+7 -5
test/test_corpus_unix_eio.ml
··· 2 3 open Alcotest 4 5 let test_data_dir = "test/data" 6 7 let test_files = [ ··· 44 let fs = Eio.Stdenv.fs env in 45 let path = Filename.concat test_data_dir filename in 46 try 47 - let gpx = Gpx_eio.read ~fs path in 48 let validation = Gpx.validate_gpx gpx in 49 check bool "GPX is valid" true validation.is_valid; 50 check bool "Has some content" true ( ··· 68 try 69 Eio_main.run @@ fun env -> 70 let fs = Eio.Stdenv.fs env in 71 - Ok (Gpx_eio.read ~fs path) 72 with 73 | Gpx.Gpx_error err -> Error err 74 in ··· 120 let fs = Eio.Stdenv.fs env in 121 let path = Filename.concat test_data_dir filename in 122 try 123 - let gpx_original = Gpx_eio.read ~fs path in 124 (* Write to temporary string via GPX core *) 125 match Gpx.write_string gpx_original with 126 | Ok xml_string -> ··· 171 (try 172 Eio_main.run @@ fun env -> 173 let fs = Eio.Stdenv.fs env in 174 - let _ = Gpx_eio.read ~fs path in 175 failf "Eio should have failed to parse invalid.gpx" 176 with 177 | Gpx.Gpx_error _ -> ··· 190 let start_eio = Sys.time () in 191 let _ = Eio_main.run @@ fun env -> 192 let fs = Eio.Stdenv.fs env in 193 - try Some (Gpx_eio.read ~fs path) 194 with Gpx.Gpx_error _ -> None 195 in 196 let eio_time = Sys.time () -. start_eio in
··· 2 3 open Alcotest 4 5 + let ( / ) = Eio.Path. ( / ) 6 + 7 let test_data_dir = "test/data" 8 9 let test_files = [ ··· 46 let fs = Eio.Stdenv.fs env in 47 let path = Filename.concat test_data_dir filename in 48 try 49 + let gpx = Gpx_eio.read (fs / path) in 50 let validation = Gpx.validate_gpx gpx in 51 check bool "GPX is valid" true validation.is_valid; 52 check bool "Has some content" true ( ··· 70 try 71 Eio_main.run @@ fun env -> 72 let fs = Eio.Stdenv.fs env in 73 + Ok (Gpx_eio.read (fs / path)) 74 with 75 | Gpx.Gpx_error err -> Error err 76 in ··· 122 let fs = Eio.Stdenv.fs env in 123 let path = Filename.concat test_data_dir filename in 124 try 125 + let gpx_original = Gpx_eio.read (fs / path) in 126 (* Write to temporary string via GPX core *) 127 match Gpx.write_string gpx_original with 128 | Ok xml_string -> ··· 173 (try 174 Eio_main.run @@ fun env -> 175 let fs = Eio.Stdenv.fs env in 176 + let _ = Gpx_eio.read (fs / path) in 177 failf "Eio should have failed to parse invalid.gpx" 178 with 179 | Gpx.Gpx_error _ -> ··· 192 let start_eio = Sys.time () in 193 let _ = Eio_main.run @@ fun env -> 194 let fs = Eio.Stdenv.fs env in 195 + try Some (Gpx_eio.read (fs / path)) 196 with Gpx.Gpx_error _ -> None 197 in 198 let eio_time = Sys.time () -. start_eio in