Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept correction files produced by ppx_driver #415

Merged
2 commits merged into from
Jan 16, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions doc/jbuild.rst
Original file line number Diff line number Diff line change
@@ -1017,9 +1017,10 @@ The following constructions are available:
- ``(promote <files-to-promote>)`` copy generated files to the source
tree. See `Promotion`_ for more details
- ``(promote-if <files-to-promote>)`` is the same as ``(promote
<files-to-promote>)`` except that it does nothing when the files to
copy don't exist. This can be used with command that only produce a
correction when differences are found
<files-to-promote>)`` except that a form ``(<a> as <b>)`` is ignored
when ``<a>`` doesn't exists. Additionally, ``<a>`` won't be copied
if ``<b>`` doesn't already exist. This can be used with command that
only produce a correction when differences are found

As mentioned ``copy#`` inserts a line directive at the beginning of
the destination file. More precisely, it inserts the following line:
13 changes: 8 additions & 5 deletions src/action.ml
Original file line number Diff line number Diff line change
@@ -137,7 +137,8 @@ struct
let remove_tree path = Remove_tree path
let mkdir path = Mkdir path
let digest_files files = Digest_files files
let promote mode files = Promote { mode; files }
let promote files = Promote { mode = Always; files }
let promote_if files = Promote { mode = If_corrected_file_exists; files }
end

module Make_mapper
@@ -758,10 +759,12 @@ let rec exec t ~ectx ~dir ~env_extra ~stdout_to ~stderr_to =
if promote_mode = Copy then
Future.Scheduler.at_exit_after_waiting_for_commands (fun () ->
List.iter not_ok ~f:(fun { Promote. src; dst } ->
Format.eprintf "Promoting %s to %s.@."
(Path.to_string_maybe_quoted src)
(Path.to_string_maybe_quoted dst);
Io.copy_file ~src:(Path.to_string src) ~dst:(Path.to_string dst)));
if mode = Always || Path.exists dst then begin
Format.eprintf "Promoting %s to %s.@."
(Path.to_string_maybe_quoted src)
(Path.to_string_maybe_quoted dst);
Io.copy_file ~src:(Path.to_string src) ~dst:(Path.to_string dst)
end));
Future.all_unit (List.map not_ok ~f:(fun { Promote. src; dst } ->
Diff.print dst src))
end
3 changes: 2 additions & 1 deletion src/action_intf.ml
Original file line number Diff line number Diff line change
@@ -76,5 +76,6 @@ module type Helpers = sig
val remove_tree : path -> t
val mkdir : path -> t
val digest_files : path list -> t
val promote : Promote_mode.t -> promote_file list -> t
val promote : promote_file list -> t
val promote_if : promote_file list -> t
end
119 changes: 73 additions & 46 deletions src/super_context.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
open Import
open Jbuild

module A = Action
module Pset = Path.Set

module Dir_with_jbuild = struct
@@ -901,6 +902,24 @@ module PP = struct
mli) in
{ m with impl ; intf }

let uses_ppx_driver ~pps =
match Option.map ~f:Pp.to_string (List.last pps) with
| Some "ppx_driver.runner" -> true
| Some _ | None -> false

let promote_correction ~uses_ppx_driver fn build =
if not uses_ppx_driver then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit: I find else clauses in if (not ...) confusing and prefer if not x then foo else bar to turn to if x then bar else foo.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I find if/match expressions easier to read when the simple choice is first. That's why I wrote it this way

build
else
Build.progn
[ build
; Build.return
(A.promote_if
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really worth introducing a module alias just for this one use?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just that super_context defines an Action module as well, so we get a name clash

[{ src = Path.extend_basename fn ~suffix:".ppx-corrected"
; dst = Path.drop_build_context fn
}])
]

let lint_module sctx ~(source : Module.t) ~(ast : Module.t) ~dir
~dep_kind ~lint ~lib_name ~scope =
let alias = Alias.lint ~dir in
@@ -909,7 +928,8 @@ module PP = struct
(Alias.add_build (aliases sctx) alias build
~stamp:(List [ Atom "lint"
; Sexp.To_sexp.(option string) lib_name
; Atom fn]))
; Atom fn
]))
in
match Preprocess_map.find source.name lint with
| No_preprocessing -> ()
@@ -938,15 +958,19 @@ module PP = struct
; Dep src_path
]
in
let uses_ppx_driver = uses_ppx_driver ~pps in
let args =
(* This hack is needed until -null is standard:
https://github.com/ocaml-ppx/ocaml-migrate-parsetree/issues/35 *)
match Option.map ~f:Pp.to_string (List.last pps) with
| Some "ppx_driver.runner" -> args @ [A "-null"]
| Some _ | None -> args
if uses_ppx_driver then
args @ [ A "-null"; A "-diff-cmd"; A "-" ]
else
args
in
add_alias src.name
(Build.run ~context:sctx.context (Ok ppx_exe) args)
(promote_correction ~uses_ppx_driver
(Option.value_exn (Module.file ~dir source kind))
(Build.run ~context:sctx.context (Ok ppx_exe) args))
)

(* Generate rules to build the .pp files and return a new module map where all filenames
@@ -959,51 +983,54 @@ module PP = struct
in
let lint_module = lint_module sctx ~dir ~dep_kind ~lint ~lib_name ~scope in
String_map.map modules ~f:(fun (m : Module.t) ->
match Preprocess_map.find m.name preprocess with
| No_preprocessing ->
let ast = setup_reason_rules sctx ~dir m in
lint_module ~ast ~source:m;
ast
| Action action ->
let ast =
pped_module m ~dir ~f:(fun _kind src dst ->
add_rule sctx
(preprocessor_deps
>>>
Build.path src
>>^ (fun _ -> [src])
>>>
Action.run sctx
(Redirect
(Stdout,
target_var,
Chdir (root_var,
action)))
~dir
~dep_kind
~targets:(Static [dst])
~scope))
|> setup_reason_rules sctx ~dir in
lint_module ~ast ~source:m;
ast
| Pps { pps; flags } ->
let ppx_exe = get_ppx_driver sctx pps ~dir ~dep_kind in
let ast = setup_reason_rules sctx ~dir m in
lint_module ~ast ~source:m;
pped_module ast ~dir ~f:(fun kind src dst ->
match Preprocess_map.find m.name preprocess with
| No_preprocessing ->
let ast = setup_reason_rules sctx ~dir m in
lint_module ~ast ~source:m;
ast
| Action action ->
let ast =
pped_module m ~dir ~f:(fun _kind src dst ->
add_rule sctx
(preprocessor_deps
>>>
Build.run ~context:sctx.context
(Ok ppx_exe)
[ As flags
; A "--dump-ast"
; As (cookie_library_name lib_name)
; A "-o"; Target dst
; Ml_kind.ppx_driver_flag kind; Dep src
]))
Build.path src
>>^ (fun _ -> [src])
>>>
Action.run sctx
(Redirect
(Stdout,
target_var,
Chdir (root_var,
action)))
~dir
~dep_kind
~targets:(Static [dst])
~scope))
|> setup_reason_rules sctx ~dir in
lint_module ~ast ~source:m;
ast
| Pps { pps; flags } ->
let ppx_exe = get_ppx_driver sctx pps ~dir ~dep_kind in
let ast = setup_reason_rules sctx ~dir m in
lint_module ~ast ~source:m;
let uses_ppx_driver = uses_ppx_driver ~pps in
pped_module ast ~dir ~f:(fun kind src dst ->
add_rule sctx
(promote_correction ~uses_ppx_driver
(Option.value_exn (Module.file m ~dir kind))
(preprocessor_deps
>>>
Build.run ~context:sctx.context
(Ok ppx_exe)
[ As flags
; A "--dump-ast"
; As (cookie_library_name lib_name)
; As (if uses_ppx_driver then ["-diff-cmd"; "-"] else [])
; A "-o"; Target dst
; Ml_kind.ppx_driver_flag kind; Dep src
])))
)

end

let expand_and_eval_set t ~scope ~dir set ~standard =