First, we go through every environment variable key and record all cases
where there are reference to other variables / dependencies.
We track two sets of variables - resolved and yet-to-be-resolved.
We pass over a list of variables over and over again and when all
variable's dependencies were resolved during previous passes we perform
a replacement for that variable, too.
Over time the size of `toResolve` set should go down to zero, however
circular dependencies may prevent that. We track the size of `toResolve`
between iterations to avoid infinite looping.
At the end we produce an object of the same size and shape as
the original, but with the values replace with resolved versions.
As per matklad, we now pass the responsibility for finding the binary to the frontend.
Also, added caching for finding the binary path to reduce
the amount of filesystem interactions.