{-# LANGUAGE FlexibleInstances, OverloadedStrings, ScopedTypeVariables, TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-name-shadowing -fno-warn-unused-do-bind #-}
module Debian.Control.Builder
(
Control'(..)
, Paragraph'(..)
, Field'(..)
, Control
, Paragraph
, Field
, ControlFunctions(..)
, mergeControls
, fieldValue
, removeField
, prependFields
, appendFields
, renameField
, modifyField
, raiseFields
, decodeControl
, decodeParagraph
, decodeField
) where
import qualified Data.ByteString.Char8 as B
import Data.Char (toLower, chr)
import Data.List (find)
import qualified Data.ListLike as LL
import Data.ListLike.Text.Builder ()
import Data.Text.Lazy (toStrict)
import Data.Text.Lazy.Builder (Builder, fromText, toLazyText)
import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
import qualified Debian.Control.ByteString as B
import Debian.Control.Common (ControlFunctions(parseControlFromFile, parseControlFromHandle, parseControl, lookupP, stripWS, asString),
Control'(Control), Paragraph'(Paragraph), Field'(Field, Comment),
mergeControls, fieldValue, removeField, prependFields, appendFields,
renameField, modifyField, raiseFields, protectFieldText')
type Field = Field' Builder
type Control = Control' Builder
type Paragraph = Paragraph' Builder
decodeControl :: B.Control -> Control
decodeControl :: Control -> Control
decodeControl (B.Control paragraphs :: [Paragraph' ByteString]
paragraphs) = [Paragraph' Builder] -> Control
forall a. [Paragraph' a] -> Control' a
Control ((Paragraph' ByteString -> Paragraph' Builder)
-> [Paragraph' ByteString] -> [Paragraph' Builder]
forall a b. (a -> b) -> [a] -> [b]
map Paragraph' ByteString -> Paragraph' Builder
decodeParagraph [Paragraph' ByteString]
paragraphs)
decodeParagraph :: B.Paragraph -> Paragraph
decodeParagraph :: Paragraph' ByteString -> Paragraph' Builder
decodeParagraph (B.Paragraph s :: [Field' ByteString]
s) = [Field' Builder] -> Paragraph' Builder
forall a. [Field' a] -> Paragraph' a
B.Paragraph ((Field' ByteString -> Field' Builder)
-> [Field' ByteString] -> [Field' Builder]
forall a b. (a -> b) -> [a] -> [b]
map Field' ByteString -> Field' Builder
decodeField [Field' ByteString]
s)
decodeField :: Field' B.ByteString -> Field' Builder
decodeField :: Field' ByteString -> Field' Builder
decodeField (B.Field (name :: ByteString
name, value :: ByteString
value)) = (Builder, Builder) -> Field' Builder
forall a. (a, a) -> Field' a
Field (ByteString -> Builder
decode ByteString
name, ByteString -> Builder
decode ByteString
value)
decodeField (B.Comment s :: ByteString
s) = Builder -> Field' Builder
forall a. a -> Field' a
Comment (ByteString -> Builder
decode ByteString
s)
decode :: B.ByteString -> Builder
decode :: ByteString -> Builder
decode = Text -> Builder
fromText (Text -> Builder) -> (ByteString -> Text) -> ByteString -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OnDecodeError -> ByteString -> Text
decodeUtf8With (\ _ w :: Maybe Word8
w -> (Word8 -> Char) -> Maybe Word8 -> Maybe Char
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Char
chr (Int -> Char) -> (Word8 -> Int) -> Word8 -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Maybe Word8
w)
instance ControlFunctions Builder where
parseControlFromFile :: FilePath -> IO (Either ParseError Control)
parseControlFromFile filepath :: FilePath
filepath =
FilePath -> IO (Either ParseError Control)
forall a.
ControlFunctions a =>
FilePath -> IO (Either ParseError (Control' a))
parseControlFromFile FilePath
filepath IO (Either ParseError Control)
-> (Either ParseError Control -> IO (Either ParseError Control))
-> IO (Either ParseError Control)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either ParseError Control -> IO (Either ParseError Control)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ParseError Control -> IO (Either ParseError Control))
-> (Either ParseError Control -> Either ParseError Control)
-> Either ParseError Control
-> IO (Either ParseError Control)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ParseError -> Either ParseError Control)
-> (Control -> Either ParseError Control)
-> Either ParseError Control
-> Either ParseError Control
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ParseError -> Either ParseError Control
forall a b. a -> Either a b
Left (Control -> Either ParseError Control
forall a b. b -> Either a b
Right (Control -> Either ParseError Control)
-> (Control -> Control) -> Control -> Either ParseError Control
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Control
decodeControl)
parseControlFromHandle :: FilePath -> Handle -> IO (Either ParseError Control)
parseControlFromHandle sourceName :: FilePath
sourceName handle :: Handle
handle =
FilePath -> Handle -> IO (Either ParseError Control)
forall a.
ControlFunctions a =>
FilePath -> Handle -> IO (Either ParseError (Control' a))
parseControlFromHandle FilePath
sourceName Handle
handle IO (Either ParseError Control)
-> (Either ParseError Control -> IO (Either ParseError Control))
-> IO (Either ParseError Control)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either ParseError Control -> IO (Either ParseError Control)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ParseError Control -> IO (Either ParseError Control))
-> (Either ParseError Control -> Either ParseError Control)
-> Either ParseError Control
-> IO (Either ParseError Control)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ParseError -> Either ParseError Control)
-> (Control -> Either ParseError Control)
-> Either ParseError Control
-> Either ParseError Control
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ParseError -> Either ParseError Control
forall a b. a -> Either a b
Left (Control -> Either ParseError Control
forall a b. b -> Either a b
Right (Control -> Either ParseError Control)
-> (Control -> Control) -> Control -> Either ParseError Control
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Control
decodeControl)
parseControl :: FilePath -> Builder -> Either ParseError Control
parseControl sourceName :: FilePath
sourceName c :: Builder
c =
(ParseError -> Either ParseError Control)
-> (Control -> Either ParseError Control)
-> Either ParseError Control
-> Either ParseError Control
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ParseError -> Either ParseError Control
forall a b. a -> Either a b
Left (Control -> Either ParseError Control
forall a b. b -> Either a b
Right (Control -> Either ParseError Control)
-> (Control -> Control) -> Control -> Either ParseError Control
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Control
decodeControl) (FilePath -> ByteString -> Either ParseError Control
forall a.
ControlFunctions a =>
FilePath -> a -> Either ParseError (Control' a)
parseControl FilePath
sourceName (Text -> ByteString
encodeUtf8 (Text -> Text
toStrict (Builder -> Text
toLazyText Builder
c))))
lookupP :: FilePath -> Paragraph' Builder -> Maybe (Field' Builder)
lookupP fieldName :: FilePath
fieldName (Paragraph paragraph :: [Field' Builder]
paragraph) =
(Field' Builder -> Bool)
-> [Field' Builder] -> Maybe (Field' Builder)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (FilePath -> Field' Builder -> Bool
hasFieldName ((Char -> Char) -> FilePath -> FilePath
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower FilePath
fieldName)) [Field' Builder]
paragraph
where hasFieldName :: String -> Field' Builder -> Bool
hasFieldName :: FilePath -> Field' Builder -> Bool
hasFieldName name :: FilePath
name (Field (fieldName' :: Builder
fieldName',_)) = FilePath
name FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== (Char -> Char) -> FilePath -> FilePath
forall full item full' item'.
(ListLike full item, ListLike full' item') =>
(item -> item') -> full -> full'
LL.map Char -> Char
toLower (Builder -> FilePath
forall s. StringLike s => s -> FilePath
LL.toString Builder
fieldName')
hasFieldName _ _ = Bool
False
stripWS :: Builder -> Builder
stripWS = (Char -> Bool) -> Builder -> Builder
forall c item. ListLike c item => (item -> Bool) -> c -> c
dropAround (Char -> FilePath -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (" \t" :: String))
protectFieldText :: Builder -> Builder
protectFieldText = Builder -> Builder
forall a.
(StringLike a, ListLike a Char, ControlFunctions a) =>
a -> a
protectFieldText'
asString :: Builder -> FilePath
asString = Builder -> FilePath
forall s. StringLike s => s -> FilePath
LL.toString
dropAround :: LL.ListLike c item => (item -> Bool) -> c -> c
dropAround :: (item -> Bool) -> c -> c
dropAround p :: item -> Bool
p = (item -> Bool) -> c -> c
forall c item. ListLike c item => (item -> Bool) -> c -> c
LL.dropWhile item -> Bool
p (c -> c) -> (c -> c) -> c -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (item -> Bool) -> c -> c
forall c item. ListLike c item => (item -> Bool) -> c -> c
LL.dropWhileEnd item -> Bool
p