Skip to content

Add a (env var) dependency#1186

Merged
emillon merged 2 commits intomasterfrom
env-as-dependency
Sep 5, 2018
Merged

Add a (env var) dependency#1186
emillon merged 2 commits intomasterfrom
env-as-dependency

Conversation

@emillon
Copy link
Copy Markdown
Collaborator

@emillon emillon commented Aug 28, 2018

This adds a new (env) dependency that tracks the contents of the environment.

I have a couple questions before going further in tests:

  • is it OK to keep this opt-in rather than always tracking the environment?
  • the environment is tracked per context. Does it make sense to use the current context, or is "default" (as in the current patch) enough?

Thanks!

@emillon emillon requested review from a user and rgrinberg August 28, 2018 12:57
@ghost
Copy link
Copy Markdown

ghost commented Aug 28, 2018

Shouldn't we declare dependencies on specific variables rather than the whole environment? Depending on the whole environment seems safer, but then Dune should probably cleanup a bit the environment and assume that basically everything depend on it.

the environment is tracked per context. Does it make sense to use the current context, or is "default" (as in the current patch) enough?

It should be per context. There are many variables that might influence the build that are per-contexts, such as OCAMLPATH.

@emillon emillon force-pushed the env-as-dependency branch from f8d37fe to dc67728 Compare August 29, 2018 09:28
@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Aug 29, 2018

Shouldn't we declare dependencies on specific variables rather than the whole environment?

I saw that as a possible improvement, but you're right, in most cases a list will be enough. I'll change that.

It should be per context

👍 fixed this

@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Aug 31, 2018

I'm having trouble doing this per environment variable.

What I'm trying to implement is having a per-context, per-var file that consists of the variable content (say, "unset" or a hash of the value). I'd like to store that in _build/.env/$CONTEXT/$VAR.

The problem is how to populate these files: it's not possible to do it in Build_system.do_build because we don't know the set of relevant variables at this point. How would it be possible to do this lazily, one a target requires it?

Thanks!

@ghost
Copy link
Copy Markdown

ghost commented Aug 31, 2018

The most straightforward way is to allow rules to have other kind of dependencies than just files. This is a bit more work, however that would help for other cases. Knowing precisely what the dependencies of a rules are is better than encoding special dependencies via files.

For instance, currently we represent dependencies on /some/externa/dir/*.cmi via a special target in _build/.misc. Such files might appears in dependency traces, in the output of dune rules, etc... This is also a problem for #1171.

We don't need to change everything in this PR, but we can discuss how to proceed in a way that will help with future changes. For instance we could replace the various Path.Set.t values that are used to represent dependencies by an abstract type Dependencies.t, and then allow Dependencies.t to encode environment variable dependencies.

@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Sep 3, 2018

Thanks for the suggestion. I just did that. I'm not sure that this covers all uses of Path.Set.t for dependencies, but at least my test case now passes.

@emillon emillon changed the title WIP: Add a (env) dependency Add a (env var) dependency Sep 3, 2018
@ghost
Copy link
Copy Markdown

ghost commented Sep 3, 2018

There seem to be quite a few cases where we call Dependencies.iter or Dependencies.fold with on_var:ignore or on_var:(fun _ acc -> acc), which means that we do unnecessary work. This is especially annoying for parallel_iter.

I suggest to either add specialized iter_paths functions, or simply one paths : t -> Path.Set.t function and operate on the result.

@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Sep 3, 2018

I added some specialized versions for paths (it turns out that variables are just used for trace). I think it's preferable to adding a paths functions, because otherwise it's easy to just store a path set when the full Dependencies.t value was necessary later.

@rgrinberg
Copy link
Copy Markdown
Member

I'm a bit surprised that we needed to modify the build arrow to support this feature. I would have thought that doing it via vfile's would have been enough.

Btw, one thing that I'm wondering about is that if we should be conservative with the env vars we expose to actions. This is a massively breaking change, but I think it would make more sense if actions did not see any environment unless they explicitly depended on it. This is nix inspired, and it makes it much easier to track all dependencies in builds correctly.

@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Sep 4, 2018

I would have thought that doing it via vfile's would have been enough.

That was my thought as well, but this has some drawbacks:

  • hashing the whole environment works, but you can't track an individual variable (that was my first implementation)
  • dumping the whole environment to individual files seems wasteful and is potentially a security issue.
  • it's possible to create the files when the environment is accessed, but this requires changing the build arrow, so then why touch the FS at all?

The Dependencies.t abstraction suggested by @diml seems to be the right one. If you're concerned with adding another constructor to Build.t, maybe we can consolidate the parts of the build arrow that touch paths and env vars so that they're expressed in terms of this abstraction instead?

Btw, one thing that I'm wondering about is that if we should be conservative with the env vars we expose to actions.

Yes, that's something we should consider for dune 2.0. It would make reproducibility easier as well.

@rgrinberg
Copy link
Copy Markdown
Member

Yeah, I was just wondering about what we'd have to do if we wanted to add yet another type of dependencies. Consider if we wanted to add a dependency type for keys in a configuration file. Would we have to extend the build arrow again? Anyway, this is more of abstract issue, it's definitely not a blocker for this PR.

Btw, what about renaming Dependencies to Deps? I know this is a matter of taste, but Deps is a name that we use in many other places already.

(fun () ->
Fiber.Future.wait rule_evaluation >>= fun (action, dyn_deps) ->
wait_for_deps ~loc t (Path.Set.diff dyn_deps static_deps)
wait_for_deps ~loc t (Dependencies.diff dyn_deps static_deps)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Here we compute the environment variable dependencies for nothing. Should we add wait_for_path_deps and only diff the path dependencies?

@ghost
Copy link
Copy Markdown

ghost commented Sep 4, 2018

Tightly controlling the environment would be ideal yes. Note that the same problem exist for files: we declare what files we think a given command is going to read, but we still give it the full view of the file system. However, for environment variables it's easier to restrict the view without loss of performances.

@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Sep 4, 2018

  • It turns out that a lot of diff/union operations were just passed to an iteration function, so I added some specialized functions
  • I renamed the module to Deps
  • I also extracted Static_deps into its own module, with an abstract type

src/deps.mli Outdated

val union : t -> t -> t

val trace : t -> Env.t -> (string * string) list
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This needs a comment as it's not obvious what it means. It is basically a value that is guaranteed to change if the set of dependencies denoted by t changes, modulo hash collisions.

Signed-off-by: Etienne Millon <me@emillon.org>
Signed-off-by: Etienne Millon <me@emillon.org>
@emillon
Copy link
Copy Markdown
Collaborator Author

emillon commented Sep 5, 2018

I added some documentation for the new modules. Let me know if that works for you.

About the "trace" functions: I think it would be possible to add an abstract type (that's just Obj.t in disguise) with a monoid operation like let mix a b = Obj.repr @@ Marshal.to_string (a, b) and replace the use of Marshal by this. Do you think it would be useful? I can try that in a separate PR.

@ghost
Copy link
Copy Markdown

ghost commented Sep 5, 2018

Looks good. For the trace that's seems good yes, however we should call Marshal.to_string only once when we want to compute the digest, for performance reasons.

@emillon emillon merged commit 86c1060 into master Sep 5, 2018
@emillon emillon deleted the env-as-dependency branch September 5, 2018 08:27
rgrinberg added a commit to rgrinberg/opam-repository that referenced this pull request Sep 14, 2018
CHANGES:

- Ignore stderr output when trying to find out the number of jobs
  available (ocaml/dune#1118, fix ocaml/dune#1116, @diml)

- Fix error message when the source directory of `copy_files` does not exist.
  (ocaml/dune#1120, fix ocaml/dune#1099, @emillon)

- Highlight error locations in error messages (ocaml/dune#1121, @emillon)

- Display actual stanza when package is ambiguous (ocaml/dune#1126, fix ocaml/dune#1123, @emillon)

- Add `dune unstable-fmt` to format `dune` files. The interface and syntax are
  still subject to change, so use with caution. (ocaml/dune#1130, fix ocaml/dune#940, @emillon)

- Improve error message for `dune utop` without a library name (ocaml/dune#1154, fix
  ocaml/dune#1149, @emillon)

- Fix parsing `ocamllex` stanza in jbuild files (ocaml/dune#1150, @rgrinberg)

- Highlight multi-line errors (ocaml/dune#1131, @anuragsoni)

- Do no try to generate shared libraries when this is not supported by
  the OS (ocaml/dune#1165, fix ocaml/dune#1051, @diml)

- Fix `Flags.write_{sexp,lines}` in configurator by avoiding the use of
  `Stdune.Path` (ocaml/dune#1175, fix ocaml/dune#1161, @rgrinberg)

- Add support for `findlib.dynload`: when linking an executable using
  `findlib.dynload`, automatically record linked in libraries and
  findlib predicates (ocaml/dune#1172, @bobot)

- Add support for promoting a selected list of files (ocaml/dune#1192, @diml)

- Add an emacs mode providing helpers to promote correction files
  (ocaml/dune#1192, @diml)

- Improve message suggesting to remove parentheses (ocaml/dune#1196, fix ocaml/dune#1173, @emillon)

- Add `(wrapped (transition "..message.."))` as an option that will generate
  wrapped modules but keep unwrapped modules with a deprecation message to
  preserve compatibility. (ocaml/dune#1188, fix ocaml/dune#985, @rgrinberg)

- Fix the flags passed to the ppx rewriter when using `staged_pps` (ocaml/dune#1218, @diml)

- Add `(env var)` to add a dependency to an environment variable.
  (ocaml/dune#1186, @emillon)

- Add a simple version of a polling mode: `dune build -w` keeps
  running and restarts the build when something change on the
  filesystem (ocaml/dune#1140, @kodek16)

- Cleanup the way we detect the library search path. We no longer call
  `opam config var lib` in the default build context (ocaml/dune#1226, @diml)

- Make test stanzas honor the -p flag. (ocaml/dune#1236, fix ocaml/dune#1231, @emillon)

- Test stanzas take an optional (action) field to customize how they run (ocaml/dune#1248,
  ocaml/dune#1195, @emillon)

- Add support for private modules via the `private_modules` field (ocaml/dune#1241, fix
  ocaml/dune#427, @rgrinberg)

- Add support for passing arguments to the OCaml compiler via a
  response file when the list of arguments is too long (ocaml/dune#1256, @diml)

- Do not print diffs by default when running inside dune (ocaml/dune#1260, @diml)

- Interpret `$ dune build dir` as building the default alias in `dir`. (ocaml/dune#1259,
  @rgrinberg)

- Make the `dynlink` library available without findlib installed (ocaml/dune#1270, fix
  ocaml/dune#1264, @rgrinberg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants