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

Add actions-stdxxx-on-success options #4515

Merged
4 commits merged into from Apr 27, 2021
Merged
Show file tree
Hide file tree
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: 5 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ Unreleased
- Fields allowed in the config file are now also allowed in the
workspace file (#4426, @jeremiedimino)

- Add an option to swallow the output of actions when they succeed, to
reduce noise of large builds (#4422, @jeremiedimino)
- Add options to control how Dune should handle stdout and stderr of
actions when then succeed. It is now possible to ask Dune to ignore
the stdout of actions when they succeed or to request that the
stderr of actions must be empty. This allows to reduce the noise of
large builds (#4422, #4515, @jeremiedimino)

- Add the possibility to use `locks` with the cram tests stanza (#4397, @voodoos)

Expand Down
31 changes: 26 additions & 5 deletions bin/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -612,12 +612,32 @@ let shared_with_config_file =
~docs
~env:(Arg.env_var ~doc "DUNE_CACHE_CHECK_PROBABILITY")
~doc)
and+ swallow_stdout_on_success =
and+ action_stdout_on_success =
Arg.(
value & flag
value
& opt (some (enum Dune_config.Action_output_on_success.all)) None
& info
[ "swallow-stdout-on-success" ]
~doc:"Swallow the output of an action when it succeeds.")
[ "action-stdout-on-success" ]
~doc:
"Specify how to deal with the standard output of actions when they \
succeed. Possible values are: $(b,print) to just print it to \
Dune's output, $(b,swallow) to completely ignore it and \
$(b,must-be-empty) to enforce that the action printed nothing. \
With $(b,must-be-empty), Dune will consider that the action \
failed if it printed something to its standard output. The \
default is $(b,print).")
and+ action_stderr_on_success =
Arg.(
value
& opt (some (enum Dune_config.Action_output_on_success.all)) None
& info
[ "action-stderr-on-success" ]
~doc:
"Same as $(b,--action-stdout-on-success) but for the standard \
output for error messages. A good default for large \
mono-repositories is $(b,--action-stdout-on-success=swallow \
--action-stderr-on-success=must-be-empty). This ensures that a \
successful build has a \"clean\" empty output.")
in
{ Dune_config.Partial.display
; concurrency
Expand All @@ -628,7 +648,8 @@ let shared_with_config_file =
Option.map cache_check_probability
~f:Dune_cache.Config.Reproducibility_check.check_with_probability
; cache_storage_mode
; swallow_stdout_on_success = Option.some_if swallow_stdout_on_success true
; action_stdout_on_success
; action_stderr_on_success
}

let term =
Expand Down
40 changes: 28 additions & 12 deletions src/dune_config/dune_config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ module Cache = struct
end
end

module Action_output_on_success = struct
include Dune_engine.Execution_parameters.Action_output_on_success

let decode = enum all
end

module type S = sig
type 'a field

Expand All @@ -144,7 +150,8 @@ module type S = sig
; cache_reproducibility_check :
Dune_cache.Config.Reproducibility_check.t field
; cache_storage_mode : Cache.Storage_mode.t field
; swallow_stdout_on_success : bool field
; action_stdout_on_success : Action_output_on_success.t field
; action_stderr_on_success : Action_output_on_success.t field
}
end

Expand All @@ -167,8 +174,10 @@ struct
; cache_reproducibility_check =
field a.cache_reproducibility_check b.cache_reproducibility_check
; cache_storage_mode = field a.cache_storage_mode b.cache_storage_mode
; swallow_stdout_on_success =
field a.swallow_stdout_on_success b.swallow_stdout_on_success
; action_stdout_on_success =
field a.action_stdout_on_success b.action_stdout_on_success
; action_stderr_on_success =
field a.action_stderr_on_success b.action_stderr_on_success
}
end

Expand All @@ -187,7 +196,8 @@ struct
; cache_enabled
; cache_reproducibility_check
; cache_storage_mode
; swallow_stdout_on_success
; action_stdout_on_success
; action_stderr_on_success
} =
Dyn.Encoder.record
[ ("display", field Scheduler.Config.Display.to_dyn display)
Expand All @@ -202,8 +212,10 @@ struct
cache_reproducibility_check )
; ( "cache_storage_mode"
, field Cache.Storage_mode.to_dyn cache_storage_mode )
; ( "swallow_stdout_on_success"
, field Dyn.Encoder.bool swallow_stdout_on_success )
; ( "action_stdout_on_success"
, field Action_output_on_success.to_dyn action_stdout_on_success )
; ( "action_stderr_on_success"
, field Action_output_on_success.to_dyn action_stderr_on_success )
]
end

Expand All @@ -224,7 +236,8 @@ module Partial = struct
; cache_enabled = None
; cache_reproducibility_check = None
; cache_storage_mode = None
; swallow_stdout_on_success = None
; action_stdout_on_success = None
; action_stderr_on_success = None
}

include
Expand Down Expand Up @@ -277,7 +290,8 @@ let default =
; cache_enabled = Disabled
; cache_reproducibility_check = Skip
; cache_storage_mode = None
; swallow_stdout_on_success = false
; action_stdout_on_success = Print
; action_stderr_on_success = Print
}

let decode_generic ~min_dune_version =
Expand Down Expand Up @@ -320,9 +334,10 @@ let decode_generic ~min_dune_version =
(Dune_lang.Syntax.deleted_in Stanza.syntax (3, 0)
~extra_info:"To trim the cache, use the 'dune cache trim' command."
>>> Dune_lang.Decoder.bytes_unit)
and+ swallow_stdout_on_success =
field_o_b "swallow-stdout-on-success"
~check:(Dune_lang.Syntax.since Stanza.syntax (3, 0))
and+ action_stdout_on_success =
field_o "action_stdout_on_success" (3, 0) Action_output_on_success.decode
and+ action_stderr_on_success =
field_o "action_stderr_on_success" (3, 0) Action_output_on_success.decode
in
let cache_storage_mode =
Option.merge cache_duplication cache_storage_mode ~f:(fun _ _ ->
Expand All @@ -340,7 +355,8 @@ let decode_generic ~min_dune_version =
; cache_enabled
; cache_reproducibility_check
; cache_storage_mode
; swallow_stdout_on_success
; action_stdout_on_success
; action_stderr_on_success
}

let decode =
Expand Down
9 changes: 8 additions & 1 deletion src/dune_config/dune_config.mli
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ module Terminal_persistence : sig
val all : (string * t) list
end

module Action_output_on_success : sig
include module type of struct
include Dune_engine.Execution_parameters.Action_output_on_success
end
end

module type S = sig
type 'a field

Expand All @@ -60,7 +66,8 @@ module type S = sig
; cache_reproducibility_check :
Dune_cache.Config.Reproducibility_check.t field
; cache_storage_mode : Cache.Storage_mode.t field
; swallow_stdout_on_success : bool field
; action_stdout_on_success : Action_output_on_success.t field
; action_stderr_on_success : Action_output_on_success.t field
}
end

Expand Down
11 changes: 5 additions & 6 deletions src/dune_engine/action_exec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -544,12 +544,11 @@ let exec ~targets ~root ~context ~env ~rule_loc ~build_deps
{ working_dir = Path.root
; env
; stdout_to =
(if Execution_parameters.swallow_stdout_on_success execution_parameters
then
Process.Io.stdout_swallow_on_success
else
Process.Io.stdout)
; stderr_to = Process.Io.stderr
Process.Io.make_stdout
(Execution_parameters.action_stdout_on_success execution_parameters)
; stderr_to =
Process.Io.make_stderr
(Execution_parameters.action_stderr_on_success execution_parameters)
; stdin_from = Process.Io.null In
; prepared_dependencies = DAP.Dependency.Set.empty
; exit_codes = Predicate_lang.Element 0
Expand Down
14 changes: 10 additions & 4 deletions src/dune_engine/build_system.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1381,9 +1381,10 @@ end = struct

(* The current version of the rule digest scheme. We should increment it when
making any changes to the scheme, to avoid collisions. *)
let rule_digest_version = 5
let rule_digest_version = 6

let compute_rule_digest (rule : Rule.t) ~deps ~action ~sandbox_mode =
let compute_rule_digest (rule : Rule.t) ~deps ~action ~sandbox_mode
~execution_parameters =
let { Action.Full.action; env; locks; can_go_in_shared_cache } = action in
let trace =
( rule_digest_version (* Update when changing the rule digest scheme. *)
Expand All @@ -1392,7 +1393,9 @@ end = struct
, Option.map rule.context ~f:(fun c -> c.name)
, Action.for_shell action
, can_go_in_shared_cache
, List.map locks ~f:Path.to_string )
, List.map locks ~f:Path.to_string
, Execution_parameters.action_stdout_on_success execution_parameters
, Execution_parameters.action_stderr_on_success execution_parameters )
in
Digest.generic trace

Expand Down Expand Up @@ -1618,7 +1621,10 @@ end = struct
let force_rerun = !Clflags.force && is_test in
force_rerun || Dep.Map.has_universe deps
in
let rule_digest = compute_rule_digest rule ~deps ~action ~sandbox_mode in
let rule_digest =
compute_rule_digest rule ~deps ~action ~sandbox_mode
~execution_parameters
in
let can_go_in_shared_cache =
action.can_go_in_shared_cache
&& not
Expand Down
58 changes: 48 additions & 10 deletions src/dune_engine/execution_parameters.ml
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
open Stdune

module Action_output_on_success = struct
type t =
| Print
| Swallow
| Must_be_empty

let all =
[ ("print", Print); ("swallow", Swallow); ("must-be-empty", Must_be_empty) ]

let to_dyn = function
| Print -> Dyn.Variant ("Print", [])
| Swallow -> Variant ("Swallow", [])
| Must_be_empty -> Variant ("Must_be_empty", [])

let equal = Poly.equal

let hash = Poly.hash
end

module T = struct
type t =
{ dune_version : Dune_lang.Syntax.Version.t
; swallow_stdout_on_success : bool
; action_stdout_on_success : Action_output_on_success.t
; action_stderr_on_success : Action_output_on_success.t
}

let equal { dune_version; swallow_stdout_on_success } t =
let equal { dune_version; action_stdout_on_success; action_stderr_on_success }
t =
Dune_lang.Syntax.Version.equal dune_version t.dune_version
&& Bool.equal swallow_stdout_on_success t.swallow_stdout_on_success
&& Action_output_on_success.equal action_stdout_on_success
t.action_stdout_on_success
&& Action_output_on_success.equal action_stderr_on_success
t.action_stderr_on_success

let hash { dune_version; swallow_stdout_on_success } =
let hash { dune_version; action_stdout_on_success; action_stderr_on_success }
=
Hashtbl.hash
(Dune_lang.Syntax.Version.hash dune_version, swallow_stdout_on_success)
( Dune_lang.Syntax.Version.hash dune_version
, Action_output_on_success.hash action_stdout_on_success
, Action_output_on_success.hash action_stderr_on_success )

let to_dyn { dune_version; swallow_stdout_on_success } =
let to_dyn
{ dune_version; action_stdout_on_success; action_stderr_on_success } =
Dyn.Record
[ ("dune_version", Dune_lang.Syntax.Version.to_dyn dune_version)
; ("swallow_stdout_on_success", Bool swallow_stdout_on_success)
; ( "action_stdout_on_success"
, Action_output_on_success.to_dyn action_stdout_on_success )
; ( "action_stderr_on_success"
, Action_output_on_success.to_dyn action_stderr_on_success )
]
end

include T

let builtin_default =
{ dune_version = Stanza.latest_version; swallow_stdout_on_success = false }
{ dune_version = Stanza.latest_version
; action_stdout_on_success = Print
; action_stderr_on_success = Print
}

let set_dune_version x t = { t with dune_version = x }

let set_swallow_stdout_on_success x t = { t with swallow_stdout_on_success = x }
let set_action_stdout_on_success x t = { t with action_stdout_on_success = x }

let set_action_stderr_on_success x t = { t with action_stderr_on_success = x }

let dune_version t = t.dune_version

Expand All @@ -37,7 +73,9 @@ let should_remove_write_permissions_on_generated_files t =

let should_expand_aliases_when_sandboxing t = t.dune_version >= (3, 0)

let swallow_stdout_on_success t = t.swallow_stdout_on_success
let action_stdout_on_success t = t.action_stdout_on_success

let action_stderr_on_success t = t.action_stderr_on_success

let default = Fdecl.create Dyn.Encoder.opaque

Expand Down
27 changes: 25 additions & 2 deletions src/dune_engine/execution_parameters.mli
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,34 @@ val hash : t -> int

val to_dyn : t -> Dyn.t

module Action_output_on_success : sig
(** How to deal with the output (stdout/stderr) of actions when they succeed. *)
type t =
| Print (** Print it to the terminal. *)
| Swallow
(** Completely ignore it. There is no way for the user to access it but
the output of Dune is clean. *)
| Must_be_empty
(** Require it to be empty. Treat the action as failed if it is not. *)

val all : (string * t) list

val equal : t -> t -> bool

val hash : t -> int

val to_dyn : t -> Dyn.t
end

(** {1 Constructors} *)

val builtin_default : t

val set_dune_version : Dune_lang.Syntax.Version.t -> t -> t

val set_swallow_stdout_on_success : bool -> t -> t
val set_action_stdout_on_success : Action_output_on_success.t -> t -> t

val set_action_stderr_on_success : Action_output_on_success.t -> t -> t

(** As configured by [init] *)
val default : t Memo.Build.t
Expand All @@ -42,7 +63,9 @@ val should_remove_write_permissions_on_generated_files : t -> bool

val should_expand_aliases_when_sandboxing : t -> bool

val swallow_stdout_on_success : t -> bool
val action_stdout_on_success : t -> Action_output_on_success.t

val action_stderr_on_success : t -> Action_output_on_success.t

(** {1 Initialisation} *)

Expand Down
Loading