-
Notifications
You must be signed in to change notification settings - Fork 400
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a command `dune tools exec ocamlformat` which downloads and builds ocamlformat as a dev tool before running it, passing all positional arguments to the ocamlformat executable. This is intended to be run by text editors. Signed-off-by: Stephen Sherratt <stephen@sherra.tt>
- Loading branch information
Showing
8 changed files
with
189 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
open! Import | ||
module Pkg_dev_tool = Dune_rules.Pkg_dev_tool | ||
|
||
let exe_path = Path.build @@ Pkg_dev_tool.exe_path Ocamlformat | ||
let exe_name = Pkg_dev_tool.exe_name Ocamlformat | ||
|
||
let run_dev_tool common ~args = | ||
let exe_path_string = Path.to_string exe_path in | ||
Console.print_user_message | ||
(Dune_rules.Pkg_build_progress.format_user_message | ||
~verb:"Running" | ||
~object_:(User_message.command (String.concat ~sep:" " (exe_name :: args)))); | ||
Console.finish (); | ||
restore_cwd_and_execve common exe_path_string (exe_path_string :: args) Env.initial | ||
;; | ||
|
||
let dev_tool_exe_exists () = Path.exists exe_path | ||
|
||
let build_dev_tool common = | ||
match dev_tool_exe_exists () with | ||
| true -> | ||
(* Avoid running the build system if the executable already exists | ||
to reduce unnecessary latency in the common case. *) | ||
Fiber.return () | ||
| false -> | ||
let open Fiber.O in | ||
let+ result = | ||
Build_cmd.run_build_system ~common ~request:(fun _build_system -> | ||
Action_builder.path exe_path) | ||
in | ||
(match result with | ||
| Error `Already_reported -> raise Dune_util.Report_error.Already_reported | ||
| Ok () -> ()) | ||
;; | ||
|
||
let is_in_dune_project builder = | ||
Workspace_root.create | ||
~default_is_cwd:(Common.Builder.default_root_is_cwd builder) | ||
~specified_by_user:(Common.Builder.root builder) | ||
|> Result.is_ok | ||
;; | ||
|
||
module Fallback = struct | ||
let run_command prog args env = | ||
let prog_string = Path.to_string prog in | ||
let argv = prog_string :: args in | ||
Console.print_user_message | ||
(Dune_rules.Pkg_build_progress.format_user_message | ||
~verb:"Running" | ||
~object_:(User_message.command (String.concat ~sep:" " argv))); | ||
Console.finish (); | ||
Proc.restore_cwd_and_execve prog_string argv ~env | ||
;; | ||
|
||
let run_via_opam args env = | ||
match Bin.which ~path:(Env_path.path env) "opam" with | ||
| None -> Error () | ||
| Some opam_path -> | ||
Console.print_user_message | ||
(User_message.make | ||
[ Pp.textf | ||
"Not in a dune project but opam appears to be installed. Dune will \ | ||
attempt to run %s via opam." | ||
exe_name | ||
]); | ||
run_command opam_path ([ "exec"; exe_name; "--" ] @ args) env | ||
;; | ||
|
||
let run_via_path args env = | ||
match Bin.which ~path:(Env_path.path env) exe_name with | ||
| None -> Error () | ||
| Some path -> | ||
Console.print_user_message | ||
(User_message.make | ||
[ Pp.textf | ||
"Not in a dune project but %s appears to be installed. Dune will attempt \ | ||
to run %s from your PATH." | ||
exe_name | ||
exe_name | ||
]); | ||
run_command path args env | ||
;; | ||
|
||
(* Attempt to launch ocamlformat from the current opam switch, and | ||
failing that from the PATH. This is necessary so that editors | ||
configured to run ocamlformat via dune can still be used to format | ||
ocaml code outside of dune projects. *) | ||
let run args env = | ||
match run_via_opam args env with | ||
| Ok () -> () | ||
| Error () -> | ||
(match run_via_path args env with | ||
| Ok () -> () | ||
| Error () -> | ||
User_error.raise | ||
[ Pp.textf | ||
"Not in a dune project and %s doesn't appear to be installed." | ||
exe_name | ||
]) | ||
;; | ||
end | ||
|
||
let term = | ||
let+ builder = Common.Builder.term | ||
and+ args = Arg.(value & pos_all string [] (info [] ~docv:"ARGS")) in | ||
match is_in_dune_project builder with | ||
| false -> Fallback.run args Env.initial | ||
| true -> | ||
let common, config = Common.init builder in | ||
Scheduler.go ~common ~config (fun () -> | ||
let open Fiber.O in | ||
let* () = Lock_dev_tool.lock_ocamlformat () in | ||
let+ () = build_dev_tool common in | ||
run_dev_tool common ~args) | ||
;; | ||
|
||
let info = | ||
let doc = | ||
{|Wrapper for running ocamlformat intended to be run automatically | ||
by a text editor. All positional arguments will be passed to the | ||
ocamlformat executable (pass flags to ocamlformat after the '--' | ||
argument, such as 'dune ocamlformat -- --help'). If this command | ||
is run from inside a dune project, dune will download and build | ||
the ocamlformat opam package and run the ocamlformat executable | ||
from there rather. Otherwise, dune will attempt to run the | ||
ocamlformat executable from your current opam switch. If opam is | ||
not installed, dune will attempt to run ocamlformat from your | ||
PATH.|} | ||
in | ||
Cmd.info "ocamlformat" ~doc | ||
;; | ||
|
||
let command = Cmd.v info term |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
open! Import | ||
|
||
val command : unit Cmd.t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
open! Import | ||
|
||
module Exec = struct | ||
let doc = "Command group for running wrapped tools." | ||
let info = Cmd.info ~doc "exec" | ||
let group = Cmd.group info [ Ocamlformat.command ] | ||
end | ||
|
||
let doc = "Command group for wrapped tools." | ||
let info = Cmd.info ~doc "tools" | ||
let group = Cmd.group info [ Exec.group ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
open Import | ||
|
||
val group : unit Cmd.t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-wrapper-fallback.t
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Exercise running the ocamlformat wrapper command outside of a dune | ||
project. | ||
|
||
Make a fake ocamlformat executable and add it to PATH. | ||
$ mkdir -p bin | ||
$ cat > bin/ocamlformat << EOF | ||
> #!/bin/sh | ||
> echo "Hello, World!" | ||
> EOF | ||
$ chmod a+x bin/ocamlformat | ||
$ export PATH=$PWD/bin:$PATH | ||
|
||
This is necessary for dune to act as it normally would outside of a | ||
dune workspace. | ||
$ unset INSIDE_DUNE | ||
|
||
Run the wrapper command from a temporary directory. With INSIDE_DUNE | ||
unset dune would otherwise pick up the dune project itself as the | ||
current workspace. | ||
$ cd $(mktemp -d) | ||
$ dune tools exec ocamlformat 2> /dev/null | ||
Hello, World! |
14 changes: 14 additions & 0 deletions
14
test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-wrapper.t
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Exercise running the ocamlformat wrapper command. | ||
|
||
$ . ./helpers.sh | ||
$ mkrepo | ||
|
||
$ make_fake_ocamlformat "0.26.2" | ||
$ make_ocamlformat_opam_pkg "0.26.2" | ||
$ make_project_with_dev_tool_lockdir | ||
|
||
$ dune tools exec ocamlformat | ||
Solution for dev-tools.locks/ocamlformat: | ||
- ocamlformat.0.26.2 | ||
Running 'ocamlformat' | ||
formatted with version 0.26.2 |