packages feed

encapsule-0.5: src/Expand.hs

-- SPDX-License-Identifier: Apache-2.0

module Expand (
  expandPath,
  expandContainerPath,
  )
where

import System.Directory (canonicalizePath)
import System.FilePath ((</>))
import System.Posix.Env (getEnvDefault)

-- | Expand ~ and $VARS; canonicalize (host paths).
expandPath :: FilePath -- homedir
           -> String -- path string
           -> IO FilePath
expandPath = expandHome canonicalizePath

-- | Expand ~ and $VARS without canonicalize (container paths need not exist on the host).
expandContainerPath :: FilePath -- homedir
                    -> String -- path string
                    -> IO FilePath
expandContainerPath = expandHome return

expandHome :: (FilePath -> IO FilePath) -> FilePath -> String -> IO FilePath
expandHome finish homedir ('~':'/':rest) = do
  rest' <- expandEnvVars rest
  finish $ homedir </> rest'
expandHome finish homedir "~" = finish homedir
expandHome _ _ s = expandEnvVars s

expandEnvVars :: String -> IO String
expandEnvVars [] = return []
expandEnvVars ('$':'{':rest) =
  case break (== '}') rest of
    (var, '}':after) -> do
      val <- getEnvDefault var ""
      rest' <- expandEnvVars after
      return (val ++ rest')
    _ -> do
      rest' <- expandEnvVars rest
      return ("${" ++ rest')
expandEnvVars ('$':rest) =
  let (var, after) = span isVarChar rest
  in if null var
     then do
       rest' <- expandEnvVars rest
       return ('$' : rest')
     else do
       val <- getEnvDefault var ""
       rest' <- expandEnvVars after
       return (val ++ rest')
  where
    isVarChar c = c `elem` (['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_")
expandEnvVars (c:rest) = do
  rest' <- expandEnvVars rest
  return (c : rest')