From 473f8b3b52db1ab8f2b3e325dfd0b675bcb153dc Mon Sep 17 00:00:00 2001 From: nguermond <51957369+nguermond@users.noreply.github.com> Date: Sat, 10 Jun 2023 02:45:18 -0500 Subject: [PATCH 1/3] quote open command with Filename.quote_command, and specify two packages: one with Lwt and one without --- dune-project | 20 ++++++++++++++++---- examples/basic/dune | 22 ++++++++++++++++++++-- examples/graphviz/dune | 29 +++++++++++++++++++++++++---- examples/graphviz/graphviz.ml | 24 +++++++++++++----------- open.opam | 32 ++++++++++++++++++++------------ src/base.ml | 23 +++++++++++++++++++++++ src/base.mli | 9 +++++++++ src/dune | 21 ++++++++++++++++++++- src/open.ml | 35 ++++++----------------------------- src/open.mli | 5 +++++ src/open_lwt.ml | 11 +++++++++++ src/open_lwt.mli | 9 +++++++++ 12 files changed, 177 insertions(+), 63 deletions(-) create mode 100644 src/base.ml create mode 100644 src/base.mli create mode 100644 src/open_lwt.ml create mode 100644 src/open_lwt.mli diff --git a/dune-project b/dune-project index 7c06949..18864b0 100644 --- a/dune-project +++ b/dune-project @@ -1,8 +1,8 @@ -(lang dune 1.10) +(lang dune 2.8) (generate_opam_files true) (name open) -(version 0.2.2) +(version 0.3.0) (license MIT) (source (github smolkaj/ocaml-open)) (authors "Steffen Smolka ") @@ -13,8 +13,20 @@ (name open) (synopsis "Open files in their default applications") (depends - (ocaml (>= 4.02.3)) - (dune (and :build (>= 1.10))) + (ocaml (>= 4.02.3)) + dune (odoc :with-doc) ) ) + +(package + (name open_lwt) + (synopsis "Open files in their default applications") + (depends + (ocaml (>= 4.02.3)) + dune + (odoc :with-doc) + ) + (depopts + lwt) +) diff --git a/examples/basic/dune b/examples/basic/dune index 9ba325e..7612fe6 100644 --- a/examples/basic/dune +++ b/examples/basic/dune @@ -1,9 +1,16 @@ (executable (name basic) + (modules basic) (libraries open unix)) -(alias - (name runtest) +(executable + (name basic_lwt) + (modules basic_lwt) + (optional) + (libraries lwt open_lwt unix)) + +(rule + (alias runtest) (deps (:< basic.exe) "%{workspace_root}/examples/basic/ocaml logo.pdf" @@ -11,3 +18,14 @@ "%{workspace_root}/examples/basic/ocaml logo.svg") (action (run %{<}))) + +(rule + (alias runtest) + (enabled_if %{lib-available:lwt}) + (deps + (:< basic_lwt.exe) + "%{workspace_root}/examples/basic/ocaml logo.pdf" + "%{workspace_root}/examples/basic/ocaml logo.png" + "%{workspace_root}/examples/basic/ocaml logo.svg") + (action + (run %{<}))) diff --git a/examples/graphviz/dune b/examples/graphviz/dune index b830e98..20e54f6 100644 --- a/examples/graphviz/dune +++ b/examples/graphviz/dune @@ -1,11 +1,32 @@ (executable (name graphviz) - (libraries open core)) + (enabled_if (>= %{ocaml_version} 4.14.0)) + (optional) + (modules graphviz) + (libraries open unix)) -(alias - (name graphviz) +(executable + (name graphviz_lwt) + (enabled_if (>= %{ocaml_version} 4.14.0)) + (optional) + (modules graphviz_lwt) + (libraries lwt open_lwt unix)) + +(rule + (alias runtest) + (enabled_if (>= %{ocaml_version} 4.14.0)) (deps (:< graphviz.exe) - %{workspace_root}/examples/graphviz/unix.dot) + "%{workspace_root}/examples/graphviz/unix.dot") + (action + (run %{<}))) + +(rule + (alias runtest) + (enabled_if (and (>= %{ocaml_version} 4.14.0) + %{lib-available:lwt})) + (deps + (:< graphviz_lwt.exe) + "%{workspace_root}/examples/graphviz/unix.dot") (action (run %{<}))) diff --git a/examples/graphviz/graphviz.ml b/examples/graphviz/graphviz.ml index ee7c1ef..ea3bb22 100644 --- a/examples/graphviz/graphviz.ml +++ b/examples/graphviz/graphviz.ml @@ -1,17 +1,19 @@ -open Core let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = - let output_file = Filename.temp_file title ("." ^ format) in - let cmd = sprintf "dot -T%s -o %s" format output_file in + Printf.printf "Compiling dot file...\n"; + let output_file = Filename.temp_file ~temp_dir:"." title ("." ^ format) in + let cmd = Format.sprintf "dot -T%s -o %s" format output_file in let dot_process = Unix.open_process_out cmd in - Out_channel.output_string dot_process data; - Out_channel.close dot_process; + Printf.fprintf dot_process "%s" data; ignore (Unix.close_process_out dot_process); + Printf.printf "Output saved to %s...\n" output_file; output_file -;; -In_channel.read_all "unix.dot" -|> compile_dot -|> Open.in_default_app -|> Format.printf "file opened successfully: %b\n" -;; +let _ = + Printf.printf "Running graphviz test...\n"; + In_channel.open_text "unix.dot" + |> In_channel.input_all (* requires ocaml 4.14.0 *) + |> compile_dot + |> Open.in_default_app + |> Printf.printf "file opened successfully: %b\n" + diff --git a/open.opam b/open.opam index c939560..1b04db4 100644 --- a/open.opam +++ b/open.opam @@ -1,22 +1,30 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -build: [ - ["dune" "subst"] {pinned} - ["dune" "build" "-p" name "-j" jobs] - ["dune" "runtest" "-p" name "-j" jobs] {with-test} - ["dune" "build" "-p" name "@doc"] {with-doc} -] +version: "0.3.0" +synopsis: "Open files in their default applications" maintainer: ["Steffen Smolka "] authors: ["Steffen Smolka "] -bug-reports: "https://github.com/smolkaj/ocaml-open/issues" +license: "MIT" homepage: "https://github.com/smolkaj/ocaml-open" doc: "https://smolkaj.github.io/ocaml-open/" -license: "MIT" -version: "0.2.2" -dev-repo: "git+https://github.com/smolkaj/ocaml-open.git" -synopsis: "Open files in their default applications" +bug-reports: "https://github.com/smolkaj/ocaml-open/issues" depends: [ "ocaml" {>= "4.02.3"} - "dune" {build & >= "1.10"} + "dune" {>= "2.8"} "odoc" {with-doc} ] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/smolkaj/ocaml-open.git" diff --git a/src/base.ml b/src/base.ml new file mode 100644 index 0000000..ef7207f --- /dev/null +++ b/src/base.ml @@ -0,0 +1,23 @@ +type os = + | MacOS + | Linux + | Windows + | Cygwin + +let detect_os () : os = + if Sys.win32 then Windows else + if Sys.cygwin then Cygwin else + let in_ch,_,_ as uname = Unix.open_process_full "uname" [||] in + let os = input_line in_ch in + ignore (Unix.close_process_full uname); + match os with + | "Darwin" -> MacOS + | "Linux" -> Linux + | _ -> failwith "unknown operating system" + +let open_cmd os = + match os with + | MacOS -> "open" + | Linux -> "xdg-open" + | Windows -> "start" + | Cygwin -> "cygstart" diff --git a/src/base.mli b/src/base.mli new file mode 100644 index 0000000..55e7442 --- /dev/null +++ b/src/base.mli @@ -0,0 +1,9 @@ +type os = + | MacOS + | Linux + | Windows + | Cygwin + +val detect_os : unit -> os + +val open_cmd : os -> string diff --git a/src/dune b/src/dune index 42625d2..e203996 100644 --- a/src/dune +++ b/src/dune @@ -1,5 +1,24 @@ +(library + (name open_base) + (wrapped false) + (package open) ;; require dune 2.8, allows library to be private + (modules + base) +) + (library (name open) (public_name open) (wrapped false) - (libraries unix)) + (modules + open) + (libraries unix open_base)) + +(library + (name open_lwt) + (public_name open_lwt) + (wrapped false) + (optional) + (modules + open_lwt) + (libraries unix lwt.unix open_base)) diff --git a/src/open.ml b/src/open.ml index 67ed530..f1c2597 100644 --- a/src/open.ml +++ b/src/open.ml @@ -1,36 +1,13 @@ -type os = - | MacOS - | Linux - | Windows - | Cygwin -let detect_os () : os = - if Sys.win32 then Windows else - if Sys.cygwin then Cygwin else - let in_ch,_,_ as uname = Unix.open_process_full "uname" [||] in - let os = input_line in_ch in - ignore (Unix.close_process_full uname); - match os with - | "Darwin" -> MacOS - | "Linux" -> Linux - | _ -> failwith "unknown operating system" -let open_cmd os = - match os with - | MacOS -> "open" - | Linux -> "xdg-open" - | Windows -> "start" - | Cygwin -> "cygstart" - -let silence os = - match os with - | MacOS | Linux | Cygwin-> "> /dev/null 2>&1" - | Windows -> "> nul 2>&1" +let in_default_app_status file : Unix.process_status = + let os = Base.detect_os () in + (Filename.quote_command (Base.open_cmd os) [file]) + |> Unix.open_process_out + |> Unix.close_process_out let in_default_app file : bool = - let os = detect_os () in - Format.sprintf "%s %S %s" (open_cmd os) file (silence os) - |> Unix.system + in_default_app_status file |> function | Unix.WEXITED 0 -> true | _ -> false diff --git a/src/open.mli b/src/open.mli index 2af0152..c849448 100644 --- a/src/open.mli +++ b/src/open.mli @@ -2,3 +2,8 @@ Returns [true] if the open command exits normally, or [false] otherwise. *) val in_default_app : string -> bool + +(** Same as above, but returns process status instead. + *) +val in_default_app_status : string -> Unix.process_status + diff --git a/src/open_lwt.ml b/src/open_lwt.ml new file mode 100644 index 0000000..b5dc007 --- /dev/null +++ b/src/open_lwt.ml @@ -0,0 +1,11 @@ + +let in_default_app_status file : Unix.process_status Lwt.t = + let os = Base.detect_os () in + let cmd = Filename.quote_command (Base.open_cmd os) [file] in + Lwt_process.exec ~stdout:(`Dev_null) (Lwt_process.shell cmd) + +let in_default_app file : bool Lwt.t = + Lwt.bind (in_default_app_status file) + (function + | Unix.WEXITED 0 -> Lwt.return true + | _ -> Lwt.return false) diff --git a/src/open_lwt.mli b/src/open_lwt.mli new file mode 100644 index 0000000..11dd6fe --- /dev/null +++ b/src/open_lwt.mli @@ -0,0 +1,9 @@ + +(** Opens the given file in the default app associated with the file's type. + Returns [true] if the open command exits normally, or [false] otherwise. + *) +val in_default_app : string -> bool Lwt.t + +(** Same as above, but returns process status instead. + *) +val in_default_app_status : string -> Unix.process_status Lwt.t From d85b4bedcca39a620e92cf9e3b1304bbad25ab46 Mon Sep 17 00:00:00 2001 From: nguermond <51957369+nguermond@users.noreply.github.com> Date: Sat, 10 Jun 2023 02:53:46 -0500 Subject: [PATCH 2/3] forgot to add some files --- examples/basic/basic_lwt.ml | 10 ++++++++++ examples/graphviz/graphviz_lwt.ml | 20 ++++++++++++++++++++ open_lwt.opam | 31 +++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 examples/basic/basic_lwt.ml create mode 100644 examples/graphviz/graphviz_lwt.ml create mode 100644 open_lwt.opam diff --git a/examples/basic/basic_lwt.ml b/examples/basic/basic_lwt.ml new file mode 100644 index 0000000..e3fae13 --- /dev/null +++ b/examples/basic/basic_lwt.ml @@ -0,0 +1,10 @@ +let extensions = ["pdf"; "png"; "svg"];; + +List.iter (fun ext -> + Format.printf "attempting to open %s file...%!" ext; + let file = "ocaml logo." ^ ext in + let ok = Lwt_main.run (Open_lwt.in_default_app file) in + if ok then Format.printf "ok.\n%!" else Format.printf "failed.\n%!" +) extensions;; + +Format.printf "Done.\n";; diff --git a/examples/graphviz/graphviz_lwt.ml b/examples/graphviz/graphviz_lwt.ml new file mode 100644 index 0000000..bf47fe7 --- /dev/null +++ b/examples/graphviz/graphviz_lwt.ml @@ -0,0 +1,20 @@ + +let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = + Printf.printf "Compiling dot file...\n"; + let output_file = Filename.temp_file ~temp_dir:"." title ("." ^ format) in + let cmd = Format.sprintf "dot -T%s -o %s" format output_file in + let dot_process = Unix.open_process_out cmd in + Printf.fprintf dot_process "%s" data; + ignore (Unix.close_process_out dot_process); + Printf.printf "Output saved to %s...\n" output_file; + output_file + +let _ = + Printf.printf "Running graphviz test...\n"; + In_channel.open_text "unix.dot" + |> In_channel.input_all (* requires ocaml 4.14.0 *) + |> compile_dot + |> Open_lwt.in_default_app + |> Lwt_main.run + |> Printf.printf "file opened successfully: %b\n" + diff --git a/open_lwt.opam b/open_lwt.opam new file mode 100644 index 0000000..f5eb030 --- /dev/null +++ b/open_lwt.opam @@ -0,0 +1,31 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +version: "0.3.0" +synopsis: "Open files in their default applications" +maintainer: ["Steffen Smolka "] +authors: ["Steffen Smolka "] +license: "MIT" +homepage: "https://github.com/smolkaj/ocaml-open" +doc: "https://smolkaj.github.io/ocaml-open/" +bug-reports: "https://github.com/smolkaj/ocaml-open/issues" +depends: [ + "ocaml" {>= "4.02.3"} + "dune" {>= "2.8"} + "odoc" {with-doc} +] +depopts: ["lwt"] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/smolkaj/ocaml-open.git" From 382d114aa5e54e013843bc19a17220571d6742da Mon Sep 17 00:00:00 2001 From: nguermond <51957369+nguermond@users.noreply.github.com> Date: Sun, 11 Jun 2023 17:55:48 -0500 Subject: [PATCH 3/3] address comments --- dune-project | 5 ++--- examples/graphviz/graphviz.ml | 4 +--- examples/graphviz/graphviz_lwt.ml | 4 +--- open.opam | 2 +- open_lwt.opam | 4 ++-- src/open.ml | 2 -- src/open.mli | 4 ++-- src/open_lwt.ml | 1 - src/open_lwt.mli | 4 ++-- 9 files changed, 11 insertions(+), 19 deletions(-) diff --git a/dune-project b/dune-project index 18864b0..c15a399 100644 --- a/dune-project +++ b/dune-project @@ -5,7 +5,7 @@ (version 0.3.0) (license MIT) (source (github smolkaj/ocaml-open)) -(authors "Steffen Smolka ") +(authors "Steffen Smolka , Nathan Guermond") (maintainers "Steffen Smolka ") (documentation "https://smolkaj.github.io/ocaml-open/") @@ -26,7 +26,6 @@ (ocaml (>= 4.02.3)) dune (odoc :with-doc) + lwt ) - (depopts - lwt) ) diff --git a/examples/graphviz/graphviz.ml b/examples/graphviz/graphviz.ml index ea3bb22..f69cefc 100644 --- a/examples/graphviz/graphviz.ml +++ b/examples/graphviz/graphviz.ml @@ -1,4 +1,3 @@ - let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = Printf.printf "Compiling dot file...\n"; let output_file = Filename.temp_file ~temp_dir:"." title ("." ^ format) in @@ -9,11 +8,10 @@ let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = Printf.printf "Output saved to %s...\n" output_file; output_file -let _ = +let () = Printf.printf "Running graphviz test...\n"; In_channel.open_text "unix.dot" |> In_channel.input_all (* requires ocaml 4.14.0 *) |> compile_dot |> Open.in_default_app |> Printf.printf "file opened successfully: %b\n" - diff --git a/examples/graphviz/graphviz_lwt.ml b/examples/graphviz/graphviz_lwt.ml index bf47fe7..e572d5c 100644 --- a/examples/graphviz/graphviz_lwt.ml +++ b/examples/graphviz/graphviz_lwt.ml @@ -1,4 +1,3 @@ - let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = Printf.printf "Compiling dot file...\n"; let output_file = Filename.temp_file ~temp_dir:"." title ("." ^ format) in @@ -9,7 +8,7 @@ let compile_dot ?(format="pdf") ?(engine="dot") ?(title=engine) data : string = Printf.printf "Output saved to %s...\n" output_file; output_file -let _ = +let () = Printf.printf "Running graphviz test...\n"; In_channel.open_text "unix.dot" |> In_channel.input_all (* requires ocaml 4.14.0 *) @@ -17,4 +16,3 @@ let _ = |> Open_lwt.in_default_app |> Lwt_main.run |> Printf.printf "file opened successfully: %b\n" - diff --git a/open.opam b/open.opam index 1b04db4..438bfa6 100644 --- a/open.opam +++ b/open.opam @@ -3,7 +3,7 @@ opam-version: "2.0" version: "0.3.0" synopsis: "Open files in their default applications" maintainer: ["Steffen Smolka "] -authors: ["Steffen Smolka "] +authors: ["Steffen Smolka , Nathan Guermond"] license: "MIT" homepage: "https://github.com/smolkaj/ocaml-open" doc: "https://smolkaj.github.io/ocaml-open/" diff --git a/open_lwt.opam b/open_lwt.opam index f5eb030..5a275b9 100644 --- a/open_lwt.opam +++ b/open_lwt.opam @@ -3,7 +3,7 @@ opam-version: "2.0" version: "0.3.0" synopsis: "Open files in their default applications" maintainer: ["Steffen Smolka "] -authors: ["Steffen Smolka "] +authors: ["Steffen Smolka , Nathan Guermond"] license: "MIT" homepage: "https://github.com/smolkaj/ocaml-open" doc: "https://smolkaj.github.io/ocaml-open/" @@ -12,8 +12,8 @@ depends: [ "ocaml" {>= "4.02.3"} "dune" {>= "2.8"} "odoc" {with-doc} + "lwt" ] -depopts: ["lwt"] build: [ ["dune" "subst"] {dev} [ diff --git a/src/open.ml b/src/open.ml index f1c2597..4f31ec9 100644 --- a/src/open.ml +++ b/src/open.ml @@ -1,5 +1,3 @@ - - let in_default_app_status file : Unix.process_status = let os = Base.detect_os () in (Filename.quote_command (Base.open_cmd os) [file]) diff --git a/src/open.mli b/src/open.mli index c849448..ff65009 100644 --- a/src/open.mli +++ b/src/open.mli @@ -1,9 +1,9 @@ (** Opens the given file in the default app associated with the file's type. + Filenames are quoted using [Filename.quote]. Returns [true] if the open command exits normally, or [false] otherwise. *) val in_default_app : string -> bool -(** Same as above, but returns process status instead. +(** Same as above, but returns the process status instead. *) val in_default_app_status : string -> Unix.process_status - diff --git a/src/open_lwt.ml b/src/open_lwt.ml index b5dc007..2598dbb 100644 --- a/src/open_lwt.ml +++ b/src/open_lwt.ml @@ -1,4 +1,3 @@ - let in_default_app_status file : Unix.process_status Lwt.t = let os = Base.detect_os () in let cmd = Filename.quote_command (Base.open_cmd os) [file] in diff --git a/src/open_lwt.mli b/src/open_lwt.mli index 11dd6fe..87507b6 100644 --- a/src/open_lwt.mli +++ b/src/open_lwt.mli @@ -1,9 +1,9 @@ - (** Opens the given file in the default app associated with the file's type. + Filenames are quoted using [Filename.quote]. Returns [true] if the open command exits normally, or [false] otherwise. *) val in_default_app : string -> bool Lwt.t -(** Same as above, but returns process status instead. +(** Same as above, but returns the process status instead. *) val in_default_app_status : string -> Unix.process_status Lwt.t