directory 1.3.9.0 → 1.3.10.0
raw patch · 7 files changed
+90/−39 lines, 7 filesdep ~Win32dep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: Win32, base
API changes (from Hackage documentation)
+ System.Directory: getExecSearchPath :: IO [FilePath]
+ System.Directory.OsPath: getExecSearchPath :: IO [OsPath]
- System.Directory.Internal: ListT :: m (Maybe (a, ListT m a)) -> ListT m a
+ System.Directory.Internal: ListT :: m (Maybe (a, ListT m a)) -> ListT (m :: Type -> Type) a
- System.Directory.Internal: [unListT] :: ListT m a -> m (Maybe (a, ListT m a))
+ System.Directory.Internal: [unListT] :: ListT (m :: Type -> Type) a -> m (Maybe (a, ListT m a))
- System.Directory.Internal: data () => OsString
+ System.Directory.Internal: data OsString
- System.Directory.Internal: emptyListT :: Applicative m => ListT m a
+ System.Directory.Internal: emptyListT :: forall (m :: Type -> Type) a. Applicative m => ListT m a
- System.Directory.Internal: listToListT :: Applicative m => [a] -> ListT m a
+ System.Directory.Internal: listToListT :: forall (m :: Type -> Type) a. Applicative m => [a] -> ListT m a
- System.Directory.Internal: newtype ListT m a
+ System.Directory.Internal: newtype ListT (m :: Type -> Type) a
Files
- System/Directory.hs +7/−0
- System/Directory/Internal/Posix.hsc +3/−4
- System/Directory/Internal/Windows.hsc +23/−19
- System/Directory/OsPath.hs +7/−0
- changelog.md +6/−0
- directory.cabal +4/−4
- tests/Util.hs +40/−12
System/Directory.hs view
@@ -40,6 +40,9 @@ , getUserDocumentsDirectory , getTemporaryDirectory + -- * PATH+ , getExecSearchPath+ -- * Actions on files , removeFile , renameFile@@ -1337,3 +1340,7 @@ -} getTemporaryDirectory :: IO FilePath getTemporaryDirectory = D.getTemporaryDirectory >>= decodeFS++-- | Get the contents of the @PATH@ environment variable.+getExecSearchPath :: IO [FilePath]+getExecSearchPath = D.getExecSearchPath >>= (`for` decodeFS)
System/Directory/Internal/Posix.hsc view
@@ -148,6 +148,9 @@ path <- getPath pure (findExecutablesInDirectoriesLazy path binary) +getPath :: IO [OsPath]+getPath = splitSearchPath <$> getEnvOs (os "PATH")+ exeExtensionInternal :: OsString exeExtensionInternal = exeExtension @@ -390,10 +393,6 @@ Nothing Nothing Just value -> pure value---- | Get the contents of the @PATH@ environment variable.-getPath :: IO [OsPath]-getPath = splitSearchPath <$> getEnvOs (os "PATH") -- | $HOME is preferred, because the user has control over it. However, POSIX -- doesn't define it as a mandatory variable, so fall back to `getpwuid_r`.
System/Directory/Internal/Windows.hsc view
@@ -4,7 +4,7 @@ #if defined(mingw32_HOST_OS) ##if defined(i386_HOST_ARCH) ## define WINAPI stdcall-##elif defined(x86_64_HOST_ARCH)+##elif defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) ## define WINAPI ccall ##else ## error unknown architecture@@ -29,6 +29,7 @@ , pack , pathSeparator , splitDirectories+ , splitSearchPath , takeExtension , toChar , unpack@@ -41,6 +42,7 @@ import qualified System.Win32.WindowsString.Shell as Win32 import qualified System.Win32.WindowsString.Time as Win32 import qualified System.Win32.WindowsString.Types as Win32+import qualified System.Win32.WindowsString.Console as Win32 type RawHandle = OsPath @@ -53,6 +55,26 @@ closeRaw :: RawHandle -> IO () closeRaw _ = pure () +lookupEnvOs :: OsString -> IO (Maybe OsString)+lookupEnvOs (OsString name) = (OsString <$>) <$> Win32.getEnv name++getEnvOs :: OsString -> IO OsString+getEnvOs name = do+ env <- lookupEnvOs name+ case env of+ Nothing ->+ throwIO $+ mkIOError+ doesNotExistErrorType+ ("env var " <> show name <> " not found")+ Nothing+ Nothing+ Just value -> pure value++-- | Get the contents of the @PATH@ environment variable.+getPath :: IO [OsPath]+getPath = splitSearchPath <$> getEnvOs (os "PATH")+ createDirectoryInternal :: OsPath -> IO () createDirectoryInternal path = (`ioeSetOsPath` path) `modifyIOError` do@@ -665,24 +687,6 @@ setAccessPermissions :: OsPath -> Permissions -> IO () setAccessPermissions path Permissions{writable = w} = do setFilePermissions path (setWriteMode w 0)--lookupEnvOs :: OsString -> IO (Maybe OsString)-lookupEnvOs (OsString name) = do- result <-- Win32.withTString name $ \ pName ->- peekTStringWith 256 $ \ pBuffer size ->- c_GetEnvironmentVariable pName pBuffer size- case result of- Left errCode | errCode == win32_eRROR_ENVVAR_NOT_FOUND -> pure Nothing- | otherwise -> Win32.failWith "GetEnvironmentVariable" errCode- Right value -> pure (Just (OsString value))--foreign import WINAPI unsafe "windows.h GetEnvironmentVariableW"- c_GetEnvironmentVariable- :: Win32.LPWSTR- -> Win32.LPWSTR- -> Win32.DWORD- -> IO Win32.DWORD getFolderPath :: Win32.CSIDL -> IO OsPath getFolderPath what = OsString <$> Win32.sHGetFolderPath nullPtr what nullPtr 0
System/Directory/OsPath.hs view
@@ -42,6 +42,9 @@ , getUserDocumentsDirectory , getTemporaryDirectory + -- * PATH+ , getExecSearchPath+ -- * Actions on files , removeFile , renameFile@@ -1653,3 +1656,7 @@ -} getTemporaryDirectory :: IO OsPath getTemporaryDirectory = getTemporaryDirectoryInternal++-- | Get the contents of the @PATH@ environment variable.+getExecSearchPath :: IO [OsPath]+getExecSearchPath = getPath
changelog.md view
@@ -1,6 +1,12 @@ Changelog for the [`directory`][1] package ========================================== +## 1.3.10.0 (Dec 2025)++ * Add `getExecSearchPath` as replacement for+ `System.FilePath.getSearchPath`.+ ([#198](https://github.com/haskell/directory/pull/198))+ ## 1.3.9.0 (Oct 2024) * Rely on `file-io` for file I/O.
directory.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: directory-version: 1.3.9.0+version: 1.3.10.0 license: BSD-3-Clause license-file: LICENSE maintainer: libraries@haskell.org@@ -59,11 +59,11 @@ include-dirs: . build-depends:- base >= 4.13.0 && < 4.21,+ base >= 4.13.0 && < 4.23, file-io >= 0.1.4 && < 0.2,- time >= 1.8.0 && < 1.15,+ time >= 1.8.0 && < 1.16, if os(windows)- build-depends: Win32 >= 2.13.3 && < 2.15+ build-depends: Win32 >= 2.14.1.0 && < 2.15 else build-depends: unix >= 2.8.0 && < 2.9
tests/Util.hs view
@@ -144,26 +144,54 @@ where cleanup dir' | keep = return () | otherwise = removePathForcibly dir' +diffAsc' :: (j -> k -> Ordering)+ -> (u -> v -> Bool)+ -> [(j, u)]+ -> [(k, v)]+ -> ([(j, u)], [(k, v)])+diffAsc' cmp eq = go id id+ where+ go a b [] [] = (a [], b [])+ go a b jus [] = go (a . (jus <>)) b [] []+ go a b [] kvs = go a (b . (kvs <>)) [] []+ go a b jus@((j, u) : jus') kvs@((k, v) : kvs') =+ case cmp j k of+ LT -> go (a . ((j, u) :)) b jus' kvs+ GT -> go a (b . ((k, v) :)) jus kvs'+ EQ | eq u v -> go a b jus' kvs'+ | otherwise -> go (a . ((j, u) :)) (b . ((k, v) :)) jus' kvs'++diffAsc :: (Ord k, Eq v) => [(k, v)] -> [(k, v)] -> ([(k, v)], [(k, v)])+diffAsc = diffAsc' compare (==)++-- Environment variables may be sensitive, so don't log their values.+scrubEnv :: (String, String) -> (String, String)+scrubEnv (k, v)+ -- Allowlist for nonsensitive variables.+ | k `elem` ["XDG_CONFIG_HOME"] = (k, v)+ | otherwise = (k, "<" <> show (length v) <> " chars>")+ isolateEnvironment :: IO a -> IO a isolateEnvironment = bracket getEnvs setEnvs . const where+ -- Duplicate environment variables will cause problems for this code.+ -- https://github.com/haskell/cabal/issues/10718 getEnvs = List.sort . filter (\(k, _) -> k /= "") <$> getEnvironment setEnvs target = do current <- getEnvs- updateEnvs current target+ let (deletions, insertions) = diffAsc current target+ updateEnvs deletions insertions new <- getEnvs when (target /= new) $ do- -- Environment variables may be sensitive, so don't log them.- throwIO (userError "isolateEnvironment.setEnvs failed")- updateEnvs kvs1@((k1, v1) : kvs1') kvs2@((k2, v2) : kvs2') =- case compare k1 k2 of- LT -> unsetEnv k1 *> updateEnvs kvs1' kvs2- EQ | v1 == v2 -> updateEnvs kvs1' kvs2'- | otherwise -> setEnv k1 v2 *> updateEnvs kvs1' kvs2'- GT -> setEnv k2 v2 *> updateEnvs kvs1 kvs2'- updateEnvs [] [] = pure ()- updateEnvs kvs1 [] = for_ kvs1 (unsetEnv . fst)- updateEnvs [] kvs2 = for_ kvs2 (uncurry setEnv)+ let (missing, extraneous) = diffAsc target new+ throwIO (userError ("isolateEnvironment.setEnvs failed:" <>+ " deletions=" <> show (scrubEnv <$> deletions) <>+ " insertions=" <> show (scrubEnv <$> insertions) <>+ " missing=" <> show (scrubEnv <$> missing) <>+ " extraneous=" <> show (scrubEnv <$> extraneous)))+ updateEnvs deletions insertions = do+ for_ deletions (unsetEnv . fst)+ for_ insertions (uncurry setEnv) isolateWorkingDirectory :: Bool -> OsPath -> IO a -> IO a isolateWorkingDirectory keep dir action = do