Problem with ENV in a precompiled package

I have a problem understanding how to program evaluation of an ENV value into a package. I am kind of unhappy with the RainbowBrackets of OhMyREPL because of low contrast. I understand how I can get rid of them, but I thought about a useful workaround by modifying RainbowBrackets.jl adding the evaluation of an ENV variable:

add_pass!(PASS_HANDLER, "RainbowBrackets", RAINBOWBRACKETS_SETTINGS, false)
# If NO_RAINBOWBRACKETS is set to "true", disable them in the pass handle
# if not set or set to something else, keep the state from the above add_pass()
(get(ENV, "NO_RAINBOWBRACKETS", "false") == "true") && enable_pass!(PASS_HANDLER, "RainbowBrackets", false)
#

But it seems to be, that the get() is evaluated at compile time of the now modified OhMyREPL package, so I end up with the situation that the pass is enabled, but if I re-run the same code in the REPL session, the code line does what it was supposed to do.

(@v1.4) julia> OhMyREPL.showpasses()
──────────────────────────────────
 #   Pass name             Enabled  
──────────────────────────────────
 1   RainbowBrackets       true     
 2   BracketHighlighter    true     
 3   SyntaxHighlighter     true     
──────────────────────────────────
(@v1.4) julia> (get(ENV, "NO_RAINBOWBRACKETS", "false") == "true") && OhMyREPL.enable_pass!("RainbowBrackets", false)
──────────────────────────────────
 #   Pass name             Enabled  
──────────────────────────────────
 1   RainbowBrackets       false    
 2   BracketHighlighter    true     
 3   SyntaxHighlighter     true     
──────────────────────────────────

If I force a re-compilation of my OhMyREPL version in a Julia REPL session with the environment variable set, the RainbowBrackets pass is disabled after startup, so I am asuming that the precompilation of the package leads to an evaluation of the conditional code at compilation time.
Obviously that is not the dynamic startup behaviour I would like to achieve, so my question is how to get around that.

Thanks for any help!

You can/should probably do that initialization in the __init__ function, which runs every time the package loads:

help?> __init__
search:

  __init__

  __init__() function in your module would executes immediately after the module is loaded at runtime for the first time (i.e., it is only called once and only after all
  statements in the module have been executed). Because it is called after fully importing the module, __init__ functions of submodules will be executed first. Two typical uses
  of init are calling runtime initialization functions of external C libraries and initializing global constants that involve pointers returned by external libraries. See the
  manual section about modules for more details.

  Examples
  ≑≑≑≑≑≑≑≑≑≑

  const foo_data_ptr = Ref{Ptr{Cvoid}}(0)
  function __init__()
      ccall((:foo_init, :libfoo), Cvoid, ())
      foo_data_ptr[] = ccall((:foo_data, :libfoo), Ptr{Cvoid}, ())
      nothing
  end
1 Like

There is indeed a difference in the handling of the content of the init function and some code somewhere in a package. If I add a println() call in the init and the code file one can see, that the println() in the code file is only hit once, namely at precompile time, whereas the println() in the init function is hit at every startup:

thundercan% julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.4.0-rc1.0 (2020-01-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

[ Info: Precompiling OhMyREPL [5fb14364-9ced-5910-84b2-373655c76a03]
RainbowBrackets pass with true
OhmyREPL init with true
(@v1.4) julia> OhMyREPL.showpasses()
──────────────────────────────────
 #   Pass name             Enabled  
──────────────────────────────────
 1   RainbowBrackets       false    
 2   BracketHighlighter    true     
 3   SyntaxHighlighter     true     
──────────────────────────────────
(@v1.4) julia> 
thundercan% julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.4.0-rc1.0 (2020-01-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

OhmyREPL init with true
(@v1.4) julia> OhMyREPL.showpasses()
──────────────────────────────────
 #   Pass name             Enabled  
──────────────────────────────────
 1   RainbowBrackets       false    
 2   BracketHighlighter    true     
 3   SyntaxHighlighter     true     
──────────────────────────────────
(@v1.4) julia>

This proofs what I already observed, the code in the source file is evaluated at compile time, which means that the access to ENV is done at compile time but never again at runtime.
Since the content of the ENV dict is a runtime thing, I would need a β€œvolatile” declaration since the idea is not to evaluate the compile time value, but the run time value. In the absence of Base.getenv().