{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module System.Nix.Path
( FilePathPart(..)
, PathHashAlgo
, Path(..)
, pathToText
, PathSet
, SubstitutablePathInfo(..)
, ValidPathInfo(..)
, PathName(..)
, filePathPart
, pathName
, Roots
) where
import System.Nix.Hash (Digest(..),
HashAlgorithm(Truncated, SHA256))
import System.Nix.Internal.Hash
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import Data.Hashable (Hashable (..), hashPtrWithSalt)
import Data.HashMap.Strict (HashMap)
import Data.HashSet (HashSet)
import Data.Map.Strict (Map)
import Data.Monoid
import Data.Text (Text)
import qualified Data.Text as T
import System.IO.Unsafe (unsafeDupablePerformIO)
import Text.Regex.Base.RegexLike (makeRegex, matchTest)
import Text.Regex.TDFA.Text (Regex)
type PathHashAlgo = Truncated 20 SHA256
newtype PathName = PathName
{ pathNameContents :: Text
} deriving (Eq, Ord, Show, Hashable)
nameRegex :: Regex
nameRegex =
makeRegex ("[a-zA-Z0-9\\+\\-\\_\\?\\=][a-zA-Z0-9\\+\\-\\.\\_\\?\\=]*" :: String)
pathName :: Text -> Maybe PathName
pathName n = case matchTest nameRegex n of
True -> Just $ PathName n
False -> Nothing
data Path = Path !(Digest PathHashAlgo) !PathName
deriving (Eq, Ord, Show)
pathToText :: Text -> Path -> Text
pathToText storeDir (Path h nm) = storeDir <> "/" <> encodeBase32 h <> "-" <> pathNameContents nm
type PathSet = HashSet Path
data SubstitutablePathInfo = SubstitutablePathInfo
{
deriver :: !(Maybe Path)
,
references :: !PathSet
,
downloadSize :: !Integer
,
narSize :: !Integer
} deriving (Eq, Ord, Show)
data ValidPathInfo = ValidPathInfo
{
path :: !Path
,
deriverVP :: !(Maybe Path)
,
narHash :: !Text
,
referencesVP :: !PathSet
,
registrationTime :: !Integer
,
narSizeVP :: !Integer
,
ultimate :: !Bool
,
sigs :: ![Text]
,
ca :: !Text
} deriving (Eq, Ord, Show)
newtype FilePathPart = FilePathPart { unFilePathPart :: BSC.ByteString }
deriving (Eq, Ord, Show)
filePathPart :: BSC.ByteString -> Maybe FilePathPart
filePathPart p = case BSC.any (`elem` ['/', '\NUL']) p of
False -> Just $ FilePathPart p
True -> Nothing
type Roots = Map Path Path
instance Hashable Path where
hashWithSalt s (Path hash name) = s `hashWithSalt` hash `hashWithSalt` name