Tidy Eio interface

Instead of passing in an FS capability and a path, the interface now
only takes an _ Eio.Path.t.

+6 -3
bin/mlgpx_cli.ml
···
open Cmdliner
open Gpx
(* Terminal and formatting setup *)
let setup_fmt style_renderer =
Fmt_tty.setup_std_outputs ?style_renderer ();
···
log_info "Reading GPX file: %a" (bold_style Fmt.string) input_file;
(* Read input GPX *)
-
let gpx = Gpx_eio.read ~fs input_file in
if verbose then
log_info "Found %d waypoints and %d existing tracks"
···
log_info "Writing output to: %a" (bold_style Fmt.string) output_file;
(* Write output GPX *)
-
Gpx_eio.write ~fs output_file output_gpx;
if verbose then (
Fmt.pf Format.std_formatter "%a\n" (success_style Fmt.string) "Conversion completed successfully!";
···
if verbose then
log_info "Analyzing GPX file: %a" (bold_style Fmt.string) input_file;
-
let gpx = Gpx_eio.read ~fs input_file in
(* Header *)
Fmt.pf Format.std_formatter "%a\n" (bold_style Fmt.string) "GPX File Information";
···
let duration_span = Ptime.diff stop_time start_time in
match Ptime.Span.to_int_s duration_span with
| Some seconds ->
let days = seconds / 86400 in
let hours = (seconds mod 86400) / 3600 in
let minutes = (seconds mod 3600) / 60 in
···
open Cmdliner
open Gpx
+
let ( / ) = Eio.Path.( / )
+
(* Terminal and formatting setup *)
let setup_fmt style_renderer =
Fmt_tty.setup_std_outputs ?style_renderer ();
···
log_info "Reading GPX file: %a" (bold_style Fmt.string) input_file;
(* Read input GPX *)
+
let gpx = Gpx_eio.read (fs / input_file) in
if verbose then
log_info "Found %d waypoints and %d existing tracks"
···
log_info "Writing output to: %a" (bold_style Fmt.string) output_file;
(* Write output GPX *)
+
Gpx_eio.write (fs / output_file) output_gpx;
if verbose then (
Fmt.pf Format.std_formatter "%a\n" (success_style Fmt.string) "Conversion completed successfully!";
···
if verbose then
log_info "Analyzing GPX file: %a" (bold_style Fmt.string) input_file;
+
let gpx = Gpx_eio.read (fs / input_file) in
(* Header *)
Fmt.pf Format.std_formatter "%a\n" (bold_style Fmt.string) "GPX File Information";
···
let duration_span = Ptime.diff stop_time start_time in
match Ptime.Span.to_int_s duration_span with
| Some seconds ->
+
let ( / ) = Int.div in
let days = seconds / 86400 in
let hours = (seconds mod 86400) / 3600 in
let minutes = (seconds mod 3600) / 60 in
+3 -3
lib/gpx_eio/gpx_eio.ml
···
module IO = Gpx_io
(** Read and parse GPX file *)
-
let read ?(validate=false) ~fs path = IO.read_file ~validate ~fs path
(** Write GPX to file *)
-
let write ?(validate=false) ~fs path gpx = IO.write_file ~validate ~fs path gpx
(** Write GPX to file with backup *)
-
let write_with_backup ?(validate=false) ~fs path gpx = IO.write_file_with_backup ~validate ~fs path gpx
(** Read GPX from Eio source *)
let from_source ?(validate=false) source = IO.read_source ~validate source
···
module IO = Gpx_io
(** Read and parse GPX file *)
+
let read ?(validate=false) path = IO.read_file ~validate path
(** Write GPX to file *)
+
let write ?(validate=false) path gpx = IO.write_file ~validate path gpx
(** Write GPX to file with backup *)
+
let write_with_backup ?(validate=false) path gpx = IO.write_file_with_backup ~validate path gpx
(** Read GPX from Eio source *)
let from_source ?(validate=false) source = IO.read_source ~validate source
+7 -10
lib/gpx_eio/gpx_eio.mli
···
These functions provide simple file I/O with the filesystem from {!Eio.Stdenv.fs}. *)
(** Read and parse GPX file.
-
@param fs Filesystem capability
@param path File path to read
@param ?validate Optional validation flag (default: false)
@return GPX document
@raises Gpx.Gpx_error on read or parse failure *)
-
val read : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t
(** Write GPX to file.
-
@param fs Filesystem capability
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
-
val write : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> unit
(** Write GPX to file with automatic backup.
-
@param fs Filesystem capability
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
-
@return Backup file path (empty if no backup created)
@raises Gpx.Gpx_error on failure *)
-
val write_with_backup : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> string
(** {2 Stream Operations}
···
@param ?validate Optional validation flag (default: false)
@return GPX document
@raises Gpx.Gpx_error on read or parse failure *)
-
val from_source : ?validate:bool -> [> Eio.Flow.source_ty ] Eio.Resource.t -> Gpx.t
(** Write GPX to Eio sink.
@param sink Output flow
@param gpx GPX document
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
-
val to_sink : ?validate:bool -> [> Eio.Flow.sink_ty ] Eio.Resource.t -> Gpx.t -> unit
(** Print GPX statistics to sink.
@param sink Output sink
@param gpx GPX document *)
-
val print_stats : [> Eio.Flow.sink_ty ] Eio.Resource.t -> Gpx.t -> unit
···
These functions provide simple file I/O with the filesystem from {!Eio.Stdenv.fs}. *)
(** Read and parse GPX file.
@param path File path to read
@param ?validate Optional validation flag (default: false)
@return GPX document
@raises Gpx.Gpx_error on read or parse failure *)
+
val read : ?validate:bool -> _ Eio.Path.t -> Gpx.t
(** Write GPX to file.
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
+
val write : ?validate:bool -> _ Eio.Path.t -> Gpx.t -> unit
(** Write GPX to file with automatic backup.
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
+
@return Backup file path ([None] if no backup created)
@raises Gpx.Gpx_error on failure *)
+
val write_with_backup : ?validate:bool -> 'a Eio.Path.t -> Gpx.t -> 'a Eio.Path.t option
(** {2 Stream Operations}
···
@param ?validate Optional validation flag (default: false)
@return GPX document
@raises Gpx.Gpx_error on read or parse failure *)
+
val from_source : ?validate:bool -> _ Eio.Flow.source -> Gpx.t
(** Write GPX to Eio sink.
@param sink Output flow
@param gpx GPX document
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
+
val to_sink : ?validate:bool -> _ Eio.Flow.sink -> Gpx.t -> unit
(** Print GPX statistics to sink.
@param sink Output sink
@param gpx GPX document *)
+
val print_stats : _ Eio.Flow.sink -> Gpx.t -> unit
+27 -29
lib/gpx_eio/gpx_io.ml
···
(** GPX Eio I/O operations *)
(** Read GPX from file path *)
-
let read_file ?(validate=false) ~fs path =
-
let content = Eio.Path.load Eio.Path.(fs / path) in
match Gpx.parse_string ~validate content with
| Ok gpx -> gpx
| Error err -> raise (Gpx.Gpx_error err)
(** Write GPX to file path *)
-
let write_file ?(validate=false) ~fs path gpx =
match Gpx.write_string ~validate gpx with
| Ok xml_string ->
-
Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / path) xml_string
| Error err -> raise (Gpx.Gpx_error err)
(** Read GPX from Eio source *)
···
| Error err -> raise (Gpx.Gpx_error err)
(** Check if file exists *)
-
let file_exists ~fs path =
-
try
-
let _stat = Eio.Path.stat ~follow:true Eio.Path.(fs / path) in
-
true
-
with
-
| _ -> false
(** Get file size *)
-
let file_size ~fs path =
try
-
let stat = Eio.Path.stat ~follow:true Eio.Path.(fs / path) in
Optint.Int63.to_int stat.size
with
| exn -> raise (Gpx.Gpx_error (Gpx.Error.io_error (Printexc.to_string exn)))
(** Create backup of existing file *)
-
let create_backup ~fs path =
-
if file_exists ~fs path then
-
let backup_path = path ^ ".backup" in
-
let content = Eio.Path.load Eio.Path.(fs / path) in
-
Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / backup_path) content;
-
backup_path
else
-
""
(** Write GPX to file with automatic backup *)
-
let write_file_with_backup ?(validate=false) ~fs path gpx =
-
let backup_path = create_backup ~fs path in
try
-
write_file ~validate ~fs path gpx;
backup_path
with
| Gpx.Gpx_error _ as err ->
(* Try to restore backup if write failed *)
-
if backup_path <> "" && file_exists ~fs backup_path then (
-
try
-
let backup_content = Eio.Path.load Eio.Path.(fs / backup_path) in
-
Eio.Path.save ~create:(`Or_truncate 0o644) Eio.Path.(fs / path) backup_content
-
with _ -> () (* Ignore restore errors *)
-
);
-
raise err
···
(** GPX Eio I/O operations *)
(** Read GPX from file path *)
+
let read_file ?(validate=false) path =
+
let content = Eio.Path.load path in
match Gpx.parse_string ~validate content with
| Ok gpx -> gpx
| Error err -> raise (Gpx.Gpx_error err)
(** Write GPX to file path *)
+
let write_file ?(validate=false) path gpx =
match Gpx.write_string ~validate gpx with
| Ok xml_string ->
+
Eio.Path.save ~create:(`Or_truncate 0o644) path xml_string
| Error err -> raise (Gpx.Gpx_error err)
(** Read GPX from Eio source *)
···
| Error err -> raise (Gpx.Gpx_error err)
(** Check if file exists *)
+
let file_exists = Eio.Path.is_file
(** Get file size *)
+
let file_size path =
try
+
let stat = Eio.Path.stat ~follow:true path in
Optint.Int63.to_int stat.size
with
| exn -> raise (Gpx.Gpx_error (Gpx.Error.io_error (Printexc.to_string exn)))
(** Create backup of existing file *)
+
let create_backup ((fs, inner_path) as path) =
+
if file_exists path then
+
let backup_path = inner_path ^ ".backup" in
+
let content = Eio.Path.load path in
+
Eio.Path.save ~create:(`Or_truncate 0o644) (fs, backup_path) content;
+
Some (fs, backup_path)
else
+
None
(** Write GPX to file with automatic backup *)
+
let write_file_with_backup ?(validate=false) path gpx =
+
let backup_path = create_backup path in
try
+
write_file ~validate path gpx;
backup_path
with
| Gpx.Gpx_error _ as err ->
(* Try to restore backup if write failed *)
+
match backup_path with
+
| Some backup_path ->
+
if file_exists backup_path then (
+
try
+
let backup_content = Eio.Path.load backup_path in
+
Eio.Path.save ~create:(`Or_truncate 0o644) path backup_content
+
with _ -> () (* Ignore restore errors *)
+
);
+
raise err
+
| _ -> raise err
+7 -13
lib/gpx_eio/gpx_io.mli
···
(** {1 File Operations} *)
(** Read GPX from file path.
-
@param fs Filesystem capability
@param path File path to read
@param ?validate Optional validation flag (default: false)
@return GPX document or error *)
-
val read_file : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t
(** Write GPX to file path.
-
@param fs Filesystem capability
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
-
val write_file : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> unit
(** {1 Stream Operations}
···
(** {1 Utility Functions} *)
(** Check if file exists.
-
@param fs Filesystem capability
@param path File path to check
@return [true] if file exists and is readable *)
-
val file_exists : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> bool
(** Get file size.
-
@param fs Filesystem capability
@param path File path
@return File size in bytes *)
-
val file_size : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> int
(** Create backup of existing file.
-
@param fs Filesystem capability
@param path Original file path
@return Backup file path *)
-
val create_backup : fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> string
(** Write GPX to file with automatic backup.
Creates a backup of existing file before writing new content.
-
@param fs Filesystem capability
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
-
@return Backup file path (empty string if no backup needed) *)
-
val write_file_with_backup : ?validate:bool -> fs:[> Eio.Fs.dir_ty ] Eio.Path.t -> string -> Gpx.t -> string
···
(** {1 File Operations} *)
(** Read GPX from file path.
@param path File path to read
@param ?validate Optional validation flag (default: false)
@return GPX document or error *)
+
val read_file : ?validate:bool -> _ Eio.Path.t -> Gpx.t
(** Write GPX to file path.
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
@raises Gpx.Gpx_error on write failure *)
+
val write_file : ?validate:bool -> _ Eio.Path.t -> Gpx.t -> unit
(** {1 Stream Operations}
···
(** {1 Utility Functions} *)
(** Check if file exists.
@param path File path to check
@return [true] if file exists and is readable *)
+
val file_exists : _ Eio.Path.t -> bool
(** Get file size.
@param path File path
@return File size in bytes *)
+
val file_size : _ Eio.Path.t -> int
(** Create backup of existing file.
@param path Original file path
@return Backup file path *)
+
val create_backup : 'a Eio.Path.t -> 'a Eio.Path.t option
(** Write GPX to file with automatic backup.
Creates a backup of existing file before writing new content.
@param path File path to write
@param gpx GPX document to write
@param ?validate Optional validation flag (default: false)
+
@return Backup file path ([None] if no backup needed) *)
+
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
···
open Alcotest
let test_data_dir = "test/data"
let test_files = [
···
let fs = Eio.Stdenv.fs env in
let path = Filename.concat test_data_dir filename in
try
-
let gpx = Gpx_eio.read ~fs path in
let validation = Gpx.validate_gpx gpx in
check bool "GPX is valid" true validation.is_valid;
check bool "Has some content" true (
···
try
Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
-
Ok (Gpx_eio.read ~fs path)
with
| Gpx.Gpx_error err -> Error err
in
···
let fs = Eio.Stdenv.fs env in
let path = Filename.concat test_data_dir filename in
try
-
let gpx_original = Gpx_eio.read ~fs path in
(* Write to temporary string via GPX core *)
match Gpx.write_string gpx_original with
| Ok xml_string ->
···
(try
Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
-
let _ = Gpx_eio.read ~fs path in
failf "Eio should have failed to parse invalid.gpx"
with
| Gpx.Gpx_error _ ->
···
let start_eio = Sys.time () in
let _ = Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
-
try Some (Gpx_eio.read ~fs path)
with Gpx.Gpx_error _ -> None
in
let eio_time = Sys.time () -. start_eio in
···
open Alcotest
+
let ( / ) = Eio.Path. ( / )
+
let test_data_dir = "test/data"
let test_files = [
···
let fs = Eio.Stdenv.fs env in
let path = Filename.concat test_data_dir filename in
try
+
let gpx = Gpx_eio.read (fs / path) in
let validation = Gpx.validate_gpx gpx in
check bool "GPX is valid" true validation.is_valid;
check bool "Has some content" true (
···
try
Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
+
Ok (Gpx_eio.read (fs / path))
with
| Gpx.Gpx_error err -> Error err
in
···
let fs = Eio.Stdenv.fs env in
let path = Filename.concat test_data_dir filename in
try
+
let gpx_original = Gpx_eio.read (fs / path) in
(* Write to temporary string via GPX core *)
match Gpx.write_string gpx_original with
| Ok xml_string ->
···
(try
Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
+
let _ = Gpx_eio.read (fs / path) in
failf "Eio should have failed to parse invalid.gpx"
with
| Gpx.Gpx_error _ ->
···
let start_eio = Sys.time () in
let _ = Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.fs env in
+
try Some (Gpx_eio.read (fs / path))
with Gpx.Gpx_error _ -> None
in
let eio_time = Sys.time () -. start_eio in