From a0cb94a4094430d9de99d3ca207478434500c9d8 Mon Sep 17 00:00:00 2001 From: David Barri Date: Sat, 7 Feb 2026 14:26:43 +1100 Subject: [PATCH 1/2] Add `getEnvironment` Fixes #6165 --- parser-typechecker/src/Unison/Builtin.hs | 1 + unison-runtime/src/Unison/Runtime/Builtin.hs | 2 ++ .../src/Unison/Runtime/Foreign/Function.hs | 3 +++ .../src/Unison/Runtime/Foreign/Function/Type.hs | 2 ++ .../all-base-hashes.output.md | 4 ++++ .../transcripts/pretty-print-libraries.output.md | 14 ++++++++++++++ 6 files changed, 26 insertions(+) diff --git a/parser-typechecker/src/Unison/Builtin.hs b/parser-typechecker/src/Unison/Builtin.hs index 26ce23948bb..af2ba88767f 100644 --- a/parser-typechecker/src/Unison/Builtin.hs +++ b/parser-typechecker/src/Unison/Builtin.hs @@ -1014,6 +1014,7 @@ ioBuiltins = ("IO.seekHandle.impl.v3", handle --> smode --> int --> iof unit), ("IO.handlePosition.impl.v3", handle --> iof nat), ("IO.getEnv.impl.v1", text --> iof text), + ("IO.getEnvironment.impl.v1", unit --> iof (list (tuple [text, text]))), ("IO.getArgs.impl.v1", unit --> iof (list text)), ("IO.getBuffering.impl.v3", handle --> iof bmode), ("IO.setBuffering.impl.v3", handle --> bmode --> iof unit), diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index d3e46872b0d..7f1d90cfeae 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -1083,6 +1083,8 @@ declareForeigns = do declareForeign Tracked 1 IO_getEnv_impl_v1 + declareForeign Tracked 0 IO_getEnvironment_impl_v1 + declareForeign Tracked 0 IO_getArgs_impl_v1 declareForeign Tracked 1 IO_isDirectory_impl_v3 diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index f9d40906621..71d23e23b01 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -136,6 +136,7 @@ import System.Directory as SYS import System.Environment as SYS ( getArgs, getEnv, + getEnvironment, ) import System.Exit as SYS (ExitCode (..)) import System.FilePath (isPathSeparator) @@ -335,6 +336,8 @@ foreignCallHelper = \case IO_setCurrentDirectory_impl_v3 -> mkForeignIOF setCurrentDirectory IO_fileExists_impl_v3 -> mkForeignIOF doesPathExist IO_getEnv_impl_v1 -> mkForeignIOF getEnv + IO_getEnvironment_impl_v1 -> mkForeignIOF $ + \() -> getEnvironment IO_getArgs_impl_v1 -> mkForeignIOF $ \() -> fmap Util.Text.pack <$> SYS.getArgs IO_isDirectory_impl_v3 -> mkForeignIOF doesDirectoryExist diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function/Type.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function/Type.hs index 25c45c1c51d..d1c232f8061 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function/Type.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function/Type.hs @@ -54,6 +54,7 @@ data ForeignFunc | IO_setCurrentDirectory_impl_v3 | IO_fileExists_impl_v3 | IO_getEnv_impl_v1 + | IO_getEnvironment_impl_v1 | IO_getArgs_impl_v1 | IO_isDirectory_impl_v3 | IO_createDirectory_impl_v3 @@ -501,6 +502,7 @@ foreignFuncBuiltinName = \case IO_setCurrentDirectory_impl_v3 -> "IO.setCurrentDirectory.impl.v3" IO_fileExists_impl_v3 -> "IO.fileExists.impl.v3" IO_getEnv_impl_v1 -> "IO.getEnv.impl.v1" + IO_getEnvironment_impl_v1 -> "IO.getEnvironment.impl.v1" IO_getArgs_impl_v1 -> "IO.getArgs.impl.v1" IO_isDirectory_impl_v3 -> "IO.isDirectory.impl.v3" IO_createDirectory_impl_v3 -> "IO.createDirectory.impl.v3" diff --git a/unison-src/transcripts-using-base/all-base-hashes.output.md b/unison-src/transcripts-using-base/all-base-hashes.output.md index 1101dc70b61..b5ecf455af9 100644 --- a/unison-src/transcripts-using-base/all-base-hashes.output.md +++ b/unison-src/transcripts-using-base/all-base-hashes.output.md @@ -4275,4 +4275,8 @@ This transcript is intended to make visible accidental changes to the hashing al 1185. -- #lcmj2envm11lrflvvcl290lplhvbccv82utoej0lg0eomhmsf2vrv8af17k6if7ff98fp1b13rkseng3fng4stlr495c8dn3gn4k400 |> : a -> (a ->{g} t) ->{g} t + 1186. -- ##IO.getEnvironment.impl.v1 + builtin.io2.IO.getEnvironment.impl : '{IO} Either + Failure [(Text, Text)] + ``` diff --git a/unison-src/transcripts/pretty-print-libraries.output.md b/unison-src/transcripts/pretty-print-libraries.output.md index 079512b9717..17a1cbbb80b 100644 --- a/unison-src/transcripts/pretty-print-libraries.output.md +++ b/unison-src/transcripts/pretty-print-libraries.output.md @@ -57108,6 +57108,9 @@ IO.doc = arguments. `` getEnv var `` gets the value of the environment variable named `var`. + + `` getEnvironment `` gets the list of all environment variables and + their values. # System clocks @@ -57807,6 +57810,17 @@ IO.getEnv.doc = -- builtin IO.getEnv.impl : Text ->{IO} Either Failure Text +IO.getEnvironment : '{IO, Exception} [(Text, Text)] +IO.getEnvironment _ = Either.toException getEnvironment.impl() + +IO.getEnvironment.doc : Doc +IO.getEnvironment.doc = + {{ + Get a list of all environment variables and their values. + }} + +-- builtin IO.getEnvironment.impl : '{IO} Either Failure [(Text, Text)] + IO.Handle.BufferMode.doc : Doc IO.Handle.BufferMode.doc = {{ From c149f91726abd6fbead4d9e496f8210de960f079 Mon Sep 17 00:00:00 2001 From: David Barri Date: Tue, 10 Feb 2026 11:29:29 +1100 Subject: [PATCH 2/2] Update io transcript --- unison-src/transcripts/idempotent/io.md | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/unison-src/transcripts/idempotent/io.md b/unison-src/transcripts/idempotent/io.md index fc057edddbc..93f36ff2280 100644 --- a/unison-src/transcripts/idempotent/io.md +++ b/unison-src/transcripts/idempotent/io.md @@ -640,6 +640,39 @@ testGetEnv _ = Tip: Use view 1 to view the source of a test. ``` +### Read all environment variables + +``` unison :hide +testGetEnvironment : '{io2.IO} [Result] +testGetEnvironment _ = + find k kvs = List.filter (cases (x,y) -> x == k) kvs |> List.head + test = 'let + env = reraise (getEnvironment.impl ()) + check "PATH environent variable should be set" (find "PATH" env |> isSome) + check "DOESNTEXIST didn't exist" (find "DOESNTEXIST" env |> isNone) + runTest test +``` + +``` ucm +> add + + Okay, I'm searching the branch for code that needs to be + updated... + + Done. + +> io.test testGetEnvironment + + New test results: + + 1. testGetEnvironment ◉ PATH environent variable should be set + ◉ DOESNTEXIST didn't exist + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. +``` + ### Read command line args `runMeWithNoArgs`, `runMeWithOneArg`, and `runMeWithTwoArgs` raise exceptions