-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathStackDescription.hs
More file actions
54 lines (45 loc) · 1.81 KB
/
Copy pathStackDescription.hs
File metadata and controls
54 lines (45 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
module Stackctl.StackDescription
( StackDescription (..)
, addStackDescription
) where
import Stackctl.Prelude
import Control.Lens ((?~))
import Data.Aeson (FromJSON, Value (..))
import qualified Data.Aeson as JSON
import Data.Aeson.Lens
import Data.ByteString.Char8 as BS8
import qualified Data.Yaml as Yaml
newtype StackDescription = StackDescription
{ unStackDescription :: Text
}
deriving newtype (Eq, Ord, Show, FromJSON, ToJSON)
data BodyContent
= BodyContentJSON Value
| BodyContentYaml Value
addStackDescription :: Maybe StackDescription -> Text -> Text
addStackDescription mStackDescription body = fromMaybe body $ do
StackDescription d <- mStackDescription
bc <- getBodyContent bs
decodeUtf8 <$> case bc of
BodyContentJSON v -> updateJSON d bs <$ guard (not $ hasDescription v)
BodyContentYaml v -> updateYaml d bs <$ guard (not $ hasDescription v)
where
bs = encodeUtf8 body
getBodyContent :: ByteString -> Maybe BodyContent
getBodyContent body =
asum
[ BodyContentJSON . Object <$> JSON.decodeStrict body
, hush $ BodyContentYaml . Object <$> Yaml.decodeEither' body
]
-- Inserting a key is easy to do in Yaml without the parsing round-trip that
-- would strip formatting and comments. But updating a key is hard. To avoid
-- this, we just say that we never clobber existing keys.
hasDescription :: Value -> Bool
hasDescription = isJust . (^? key "Description" . _String)
-- For JSON, don't worry about preserving formatting; do a proper update.
updateJSON :: Text -> ByteString -> ByteString
updateJSON d = atKey "Description" ?~ String d
-- For Yaml, insert textually to avoid a round-trip dropping comments or
-- changing whitespace. We rely on 'Show' as a naive escape.
updateYaml :: Text -> ByteString -> ByteString
updateYaml d bs = "Description: " <> BS8.pack (show d) <> "\n" <> bs