mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-10 22:06:17 +00:00
123 lines
5.7 KiB
Text
123 lines
5.7 KiB
Text
interface Env
|
||
exposes [cwd, dict, var, decode, exePath, setCwd]
|
||
imports [Task.{ Task }, Path.{ Path }, InternalPath, Effect, InternalTask, EnvDecoding]
|
||
|
||
## Reads the [current working directory](https://en.wikipedia.org/wiki/Working_directory)
|
||
## from the environment. File operations on relative [Path]s are relative to this directory.
|
||
cwd : Task Path [CwdUnavailable]
|
||
cwd =
|
||
effect = Effect.map Effect.cwd \bytes ->
|
||
if List.isEmpty bytes then
|
||
Err CwdUnavailable
|
||
else
|
||
Ok (InternalPath.fromArbitraryBytes bytes)
|
||
|
||
InternalTask.fromEffect effect
|
||
|
||
## Sets the [current working directory](https://en.wikipedia.org/wiki/Working_directory)
|
||
## in the environment. After changing it, file operations on relative [Path]s will be relative
|
||
## to this directory.
|
||
setCwd : Path -> Task {} [InvalidCwd]
|
||
setCwd = \path ->
|
||
Effect.setCwd (InternalPath.toBytes path)
|
||
|> Effect.map (\result -> Result.mapErr result \{} -> InvalidCwd)
|
||
|> InternalTask.fromEffect
|
||
|
||
## Gets the path to the currently-running executable.
|
||
exePath : Task Path [ExePathUnavailable]
|
||
exePath =
|
||
effect =
|
||
Effect.map Effect.exePath \result ->
|
||
when result is
|
||
Ok bytes -> Ok (InternalPath.fromOsBytes bytes)
|
||
Err {} -> Err ExePathUnavailable
|
||
|
||
InternalTask.fromEffect effect
|
||
|
||
## Reads the given environment variable.
|
||
##
|
||
## If the value is invalid Unicode, the invalid parts will be replaced with the
|
||
## [Unicode replacement character](https://unicode.org/glossary/#replacement_character)
|
||
## (`<60>`).
|
||
var : Str -> Task Str [VarNotFound]
|
||
var = \name ->
|
||
Effect.envVar name
|
||
|> Effect.map (\result -> Result.mapErr result \{} -> VarNotFound)
|
||
|> InternalTask.fromEffect
|
||
|
||
## Reads the given environment variable and attempts to decode it.
|
||
##
|
||
## The type being decoded into will be determined by type inference. For example,
|
||
## if this ends up being used like a `Task U16 …` then the environment variable
|
||
## will be decoded as a string representation of a `U16`.
|
||
##
|
||
## getU16Var : Str -> Task U16 [VarNotFound, DecodeErr DecodeError] [Read [Env]]
|
||
## getU16Var = \var -> Env.decode var
|
||
## # If the environment contains a variable NUM_THINGS=123, then calling
|
||
## # (getU16Var "NUM_THINGS") would return a task which succeeds with the U16 number 123.
|
||
## #
|
||
## # However, if the NUM_THINGS environment variable was set to 1234567, then
|
||
## # (getU16Var "NUM_THINGS") would fail because that number is too big to fit in a U16.
|
||
##
|
||
## Supported types:
|
||
## - strings
|
||
## - numbers, as long as they contain only numeric digits, up to one `.`, and an optional `-` at the front for negative numbers
|
||
## - comma-separated lists (of either strings or numbers), as long as there are no spaces after the commas
|
||
##
|
||
## Trying to decode into any other types will always fail with a `DecodeErr`.
|
||
decode : Str -> Task val [VarNotFound, DecodeErr DecodeError] | val has Decoding
|
||
decode = \name ->
|
||
Effect.envVar name
|
||
|> Effect.map
|
||
(
|
||
\result ->
|
||
result
|
||
|> Result.mapErr (\{} -> VarNotFound)
|
||
|> Result.try
|
||
(\varStr ->
|
||
Decode.fromBytes (Str.toUtf8 varStr) (EnvDecoding.format {})
|
||
|> Result.mapErr (\_ -> DecodeErr TooShort)))
|
||
|> InternalTask.fromEffect
|
||
|
||
## Reads all the process's environment variables into a [Dict].
|
||
##
|
||
## If any key or value contains invalid Unicode, the [Unicode replacement character](https://unicode.org/glossary/#replacement_character)
|
||
## (`<60>`) will be used in place of any parts of keys or values that are invalid Unicode.
|
||
dict : Task (Dict Str Str) *
|
||
dict =
|
||
Effect.envDict
|
||
|> Effect.map Ok
|
||
|> InternalTask.fromEffect
|
||
|
||
# ## Walks over the process's environment variables as key-value arguments to the walking function.
|
||
# ##
|
||
# ## Env.walk "Vars:\n" \state, key, value ->
|
||
# ## "- \(key): \(value)\n"
|
||
# ## # This might produce a string such as:
|
||
# ## #
|
||
# ## # """
|
||
# ## # Vars:
|
||
# ## # - FIRST_VAR: first value
|
||
# ## # - SECOND_VAR: second value
|
||
# ## # - THIRD_VAR: third value
|
||
# ## #
|
||
# ## # """
|
||
# ##
|
||
# ## If any key or value contains invalid Unicode, the [Unicode replacement character](https://unicode.org/glossary/#replacement_character)
|
||
# ## (`<60>`) will be used in place of any parts of keys or values that are invalid Unicode.
|
||
# walk : state, (state, Str, Str -> state) -> Task state [NonUnicodeEnv state] [Read [Env]]
|
||
# walk = \state, walker ->
|
||
# Effect.envWalk state walker
|
||
# |> InternalTask.fromEffect
|
||
# TODO could potentially offer something like walkNonUnicode which takes (state, Result Str Str, Result Str Str) so it
|
||
# tells you when there's invalid Unicode. This is both faster than (and would give you more accurate info than)
|
||
# using regular `walk` and searching for the presence of the replacement character in the resulting
|
||
# strings. However, it's unclear whether anyone would use it. What would the use case be? Reporting
|
||
# an error that the provided command-line args weren't valid Unicode? Does that still happen these days?
|
||
# TODO need to figure out clear rules for how to convert from camelCase to SCREAMING_SNAKE_CASE.
|
||
# Note that all the env vars decoded in this way become effectively *required* vars, since if any
|
||
# of them are missing, decoding will fail. For this reason, it might make sense to use this to
|
||
# decode all the required vars only, and then decode the optional ones separately some other way.
|
||
# Alternatively, it could make sense to have some sort of tag union convention here, e.g.
|
||
# if decoding into a tag union of [Present val, Missing], then it knows what to do.
|
||
# decodeAll : Task val [] [EnvDecodingFailed Str] [Env] | val has Decoding
|