{-# LANGUAGE BangPatterns  #-}
{-# LANGUAGE TupleSections #-}

-- |
-- Module    : Aura.Packages.Repository
-- Copyright : (c) Colin Woodbury, 2012 - 2020
-- License   : GPL3
-- Maintainer: Colin Woodbury <colin@fosskers.ca>
--
-- Handle the testing and dependency solving of official repository packages.

module Aura.Packages.Repository
  ( pacmanRepo
  , extractVersion
  ) where

import           Aura.Core
import           Aura.IO
import           Aura.Languages (provides_1)
import           Aura.Pacman (pacmanLines, pacmanOutput)
import           Aura.Settings (CommonSwitch(..), Settings(..), shared)
import           Aura.Types
import           Aura.Utils
import           Control.Scheduler (Comp(..), traverseConcurrently)
import           Data.Versions
import           RIO hiding (try)
import qualified RIO.Map as M
import qualified RIO.Set as S
import qualified RIO.Text as T
import           Text.Megaparsec
import           Text.Megaparsec.Char

---

-- | Repository package source.
-- We expect no matches to be found when the package is actually an AUR package.
pacmanRepo :: IO Repository
pacmanRepo :: IO Repository
pacmanRepo = do
  TVar (Map PkgName Package)
tv <- Map PkgName Package -> IO (TVar (Map PkgName Package))
forall (m :: * -> *) a. MonadIO m => a -> m (TVar a)
newTVarIO Map PkgName Package
forall a. Monoid a => a
mempty
  -- A mutex to ensure that the user will only be prompted for one input at a
  -- time.
  MVar ()
mv <- () -> IO (MVar ())
forall (m :: * -> *) a. MonadIO m => a -> m (MVar a)
newMVar ()

  let g :: Settings -> NonEmpty PkgName -> IO (Maybe (Set PkgName, Set Package))
      g :: Settings
-> NonEmpty PkgName -> IO (Maybe (Set PkgName, Set Package))
g Settings
ss NonEmpty PkgName
names = do
        --- Retrieve cached Packages ---
        Map PkgName Package
cache <- TVar (Map PkgName Package) -> IO (Map PkgName Package)
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar (Map PkgName Package)
tv
        let ([PkgName]
uncached, [Package]
cached) = (PkgName -> Either PkgName Package)
-> [PkgName] -> ([PkgName], [Package])
forall a b c. (a -> Either b c) -> [a] -> ([b], [c])
fmapEither (\PkgName
p -> PkgName -> Maybe Package -> Either PkgName Package
forall a b. a -> Maybe b -> Either a b
note PkgName
p (Maybe Package -> Either PkgName Package)
-> Maybe Package -> Either PkgName Package
forall a b. (a -> b) -> a -> b
$ PkgName -> Map PkgName Package -> Maybe Package
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup PkgName
p Map PkgName Package
cache) ([PkgName] -> ([PkgName], [Package]))
-> [PkgName] -> ([PkgName], [Package])
forall a b. (a -> b) -> a -> b
$ NonEmpty PkgName -> [PkgName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty PkgName
names
        --- Lookup uncached Packages ---
        [Either PkgName (PkgName, Provides)]
bgs <- Comp
-> (PkgName -> IO (Either PkgName (PkgName, Provides)))
-> [PkgName]
-> IO [Either PkgName (PkgName, Provides)]
forall (m :: * -> *) (t :: * -> *) a b.
(MonadUnliftIO m, Traversable t) =>
Comp -> (a -> m b) -> t a -> m (t b)
traverseConcurrently Comp
Par' (MVar ()
-> Settings -> PkgName -> IO (Either PkgName (PkgName, Provides))
resolveName MVar ()
mv Settings
ss) [PkgName]
uncached
        let ([PkgName]
bads, [(PkgName, Provides)]
goods) = [Either PkgName (PkgName, Provides)]
-> ([PkgName], [(PkgName, Provides)])
forall a b. [Either a b] -> ([a], [b])
partitionEithers [Either PkgName (PkgName, Provides)]
bgs
        let !env :: Environment
env = Settings -> Environment
envOf Settings
ss
        ([PkgName]
bads', [Package]
goods') <- ((PkgName, Provides) -> IO (Either PkgName Package))
-> [(PkgName, Provides)] -> IO ([PkgName], [Package])
forall (f :: * -> *) a b c.
Applicative f =>
(a -> f (Either b c)) -> [a] -> f ([b], [c])
traverseEither (Environment -> (PkgName, Provides) -> IO (Either PkgName Package)
f Environment
env) [(PkgName, Provides)]
goods  -- TODO Also make concurrent?
        --- Update Cache ---
        let m :: Map PkgName Package
m = [(PkgName, Package)] -> Map PkgName Package
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(PkgName, Package)] -> Map PkgName Package)
-> [(PkgName, Package)] -> Map PkgName Package
forall a b. (a -> b) -> a -> b
$ (Package -> (PkgName, Package))
-> [Package] -> [(PkgName, Package)]
forall a b. (a -> b) -> [a] -> [b]
map (Package -> PkgName
pname (Package -> PkgName)
-> (Package -> Package) -> Package -> (PkgName, Package)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Package -> Package
forall a. a -> a
id) [Package]
goods'
        STM () -> IO ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar (Map PkgName Package)
-> (Map PkgName Package -> Map PkgName Package) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar (Map PkgName Package)
tv (Map PkgName Package -> Map PkgName Package -> Map PkgName Package
forall a. Semigroup a => a -> a -> a
<> Map PkgName Package
m)
        Maybe (Set PkgName, Set Package)
-> IO (Maybe (Set PkgName, Set Package))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (Set PkgName, Set Package)
 -> IO (Maybe (Set PkgName, Set Package)))
-> Maybe (Set PkgName, Set Package)
-> IO (Maybe (Set PkgName, Set Package))
forall a b. (a -> b) -> a -> b
$ (Set PkgName, Set Package) -> Maybe (Set PkgName, Set Package)
forall a. a -> Maybe a
Just ([PkgName] -> Set PkgName
forall a. Ord a => [a] -> Set a
S.fromList ([PkgName] -> Set PkgName) -> [PkgName] -> Set PkgName
forall a b. (a -> b) -> a -> b
$ [PkgName]
bads [PkgName] -> [PkgName] -> [PkgName]
forall a. Semigroup a => a -> a -> a
<> [PkgName]
bads', [Package] -> Set Package
forall a. Ord a => [a] -> Set a
S.fromList ([Package] -> Set Package) -> [Package] -> Set Package
forall a b. (a -> b) -> a -> b
$ [Package]
cached [Package] -> [Package] -> [Package]
forall a. Semigroup a => a -> a -> a
<> [Package]
goods')

  Repository -> IO Repository
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Repository -> IO Repository) -> Repository -> IO Repository
forall a b. (a -> b) -> a -> b
$ TVar (Map PkgName Package)
-> (Settings
    -> NonEmpty PkgName -> IO (Maybe (Set PkgName, Set Package)))
-> Repository
Repository TVar (Map PkgName Package)
tv Settings
-> NonEmpty PkgName -> IO (Maybe (Set PkgName, Set Package))
g
  where
    f :: Environment -> (PkgName, Provides) -> IO (Either PkgName Package)
f Environment
env (PkgName
r, Provides
p) = (Versioning -> Package)
-> Either PkgName Versioning -> Either PkgName Package
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Prebuilt -> Package
FromRepo (Prebuilt -> Package)
-> (Versioning -> Prebuilt) -> Versioning -> Package
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PkgName -> Provides -> Versioning -> Prebuilt
packageRepo PkgName
r Provides
p) (Either PkgName Versioning -> Either PkgName Package)
-> IO (Either PkgName Versioning) -> IO (Either PkgName Package)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Environment -> PkgName -> IO (Either PkgName Versioning)
mostRecent Environment
env PkgName
r

packageRepo :: PkgName -> Provides -> Versioning -> Prebuilt
packageRepo :: PkgName -> Provides -> Versioning -> Prebuilt
packageRepo PkgName
pn Provides
pro Versioning
ver = Prebuilt :: PkgName -> Versioning -> PkgName -> Provides -> Prebuilt
Prebuilt { pName :: PkgName
pName     = PkgName
pn
                                  , pVersion :: Versioning
pVersion  = Versioning
ver
                                  , pBase :: PkgName
pBase     = PkgName
pn
                                  , pProvides :: Provides
pProvides = Provides
pro }

-- TODO Bind to libalpm /just/ for the @-Ssq@ functionality. These shell
-- calls are one of the remaining bottlenecks.
-- | If given a virtual package, try to find a real package to install.
resolveName :: MVar () -> Settings -> PkgName -> IO (Either PkgName (PkgName, Provides))
resolveName :: MVar ()
-> Settings -> PkgName -> IO (Either PkgName (PkgName, Provides))
resolveName MVar ()
mv Settings
ss PkgName
pn = do
  [PkgName]
provs <- (Text -> PkgName) -> [Text] -> [PkgName]
forall a b. (a -> b) -> [a] -> [b]
map Text -> PkgName
PkgName ([Text] -> [PkgName]) -> IO [Text] -> IO [PkgName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Environment -> [Text] -> IO [Text]
pacmanLines (Settings -> Environment
envOf Settings
ss) [Text
"-Ssq", Text
"^" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
escape (PkgName -> Text
pnName PkgName
pn) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"$"]
  case [PkgName]
provs of
    [] -> Either PkgName (PkgName, Provides)
-> IO (Either PkgName (PkgName, Provides))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either PkgName (PkgName, Provides)
 -> IO (Either PkgName (PkgName, Provides)))
-> Either PkgName (PkgName, Provides)
-> IO (Either PkgName (PkgName, Provides))
forall a b. (a -> b) -> a -> b
$ PkgName -> Either PkgName (PkgName, Provides)
forall a b. a -> Either a b
Left PkgName
pn
    [PkgName]
_  -> (PkgName, Provides) -> Either PkgName (PkgName, Provides)
forall a b. b -> Either a b
Right ((PkgName, Provides) -> Either PkgName (PkgName, Provides))
-> (PkgName -> (PkgName, Provides))
-> PkgName
-> Either PkgName (PkgName, Provides)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (, PkgName -> Provides
Provides PkgName
pn) (PkgName -> Either PkgName (PkgName, Provides))
-> IO PkgName -> IO (Either PkgName (PkgName, Provides))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar () -> Settings -> PkgName -> [PkgName] -> IO PkgName
chooseProvider MVar ()
mv Settings
ss PkgName
pn [PkgName]
provs
  where
    escape :: Text -> Text
    escape :: Text -> Text
escape = (Text -> Char -> Text) -> Text -> Text -> Text
forall a. (a -> Char -> a) -> a -> Text -> a
T.foldl' Text -> Char -> Text
f Text
""

    f :: Text -> Char -> Text
    f :: Text -> Char -> Text
f Text
acc Char
'+' = Text
acc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\\+"
    f Text
acc Char
c   = Text -> Char -> Text
T.snoc Text
acc Char
c

-- | Choose a providing package, favouring installed packages.
-- If `--noconfirm` is provided, it will try to automatically select the provider
-- with the same name as the dependency. If that doesn't exist, it will select
-- the first available provider.
chooseProvider :: MVar () -> Settings -> PkgName -> [PkgName] -> IO PkgName
chooseProvider :: MVar () -> Settings -> PkgName -> [PkgName] -> IO PkgName
chooseProvider MVar ()
_ Settings
_ PkgName
pn []          = PkgName -> IO PkgName
forall (f :: * -> *) a. Applicative f => a -> f a
pure PkgName
pn
chooseProvider MVar ()
_ Settings
_ PkgName
_ [PkgName
p]          = PkgName -> IO PkgName
forall (f :: * -> *) a. Applicative f => a -> f a
pure PkgName
p
chooseProvider MVar ()
mv Settings
ss PkgName
pn ps :: [PkgName]
ps@(PkgName
a:[PkgName]
as) =
  Comp
-> (PkgName -> IO (Maybe PkgName))
-> [PkgName]
-> IO [Maybe PkgName]
forall (m :: * -> *) (t :: * -> *) a b.
(MonadUnliftIO m, Traversable t) =>
Comp -> (a -> m b) -> t a -> m (t b)
traverseConcurrently Comp
Par' (Environment -> PkgName -> IO (Maybe PkgName)
isInstalled Environment
env) [PkgName]
ps IO [Maybe PkgName] -> ([Maybe PkgName] -> IO PkgName) -> IO PkgName
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO PkgName
-> (PkgName -> IO PkgName) -> Maybe PkgName -> IO PkgName
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO PkgName
f PkgName -> IO PkgName
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe PkgName -> IO PkgName)
-> ([Maybe PkgName] -> Maybe PkgName)
-> [Maybe PkgName]
-> IO PkgName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [PkgName] -> Maybe PkgName
forall a. [a] -> Maybe a
listToMaybe ([PkgName] -> Maybe PkgName)
-> ([Maybe PkgName] -> [PkgName])
-> [Maybe PkgName]
-> Maybe PkgName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe PkgName] -> [PkgName]
forall a. [Maybe a] -> [a]
catMaybes
  where
    env :: Environment
env = Settings -> Environment
envOf Settings
ss

    f :: IO PkgName
    f :: IO PkgName
f | Settings -> CommonSwitch -> Bool
shared Settings
ss CommonSwitch
NoConfirm = PkgName -> IO PkgName
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PkgName -> IO PkgName) -> (Bool -> PkgName) -> Bool -> IO PkgName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PkgName -> PkgName -> Bool -> PkgName
forall a. a -> a -> Bool -> a
bool PkgName
a PkgName
pn (Bool -> IO PkgName) -> Bool -> IO PkgName
forall a b. (a -> b) -> a -> b
$ PkgName
pn PkgName -> [PkgName] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PkgName]
ps
      | Bool
otherwise = do
          IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> IO ()
forall (m :: * -> *) a. MonadIO m => MVar a -> m a
takeMVar MVar ()
mv
          Settings -> (Language -> Doc AnsiStyle) -> IO ()
forall (m :: * -> *).
MonadIO m =>
Settings -> (Language -> Doc AnsiStyle) -> m ()
warn Settings
ss ((Language -> Doc AnsiStyle) -> IO ())
-> (Language -> Doc AnsiStyle) -> IO ()
forall a b. (a -> b) -> a -> b
$ PkgName -> Language -> Doc AnsiStyle
provides_1 PkgName
pn
          PkgName
r <- (PkgName -> Text) -> NonEmpty PkgName -> IO PkgName
forall (f :: * -> *) a. Foldable f => (a -> Text) -> f a -> IO a
getSelection PkgName -> Text
pnName (PkgName
a PkgName -> [PkgName] -> NonEmpty PkgName
forall a. a -> [a] -> NonEmpty a
:| [PkgName]
as)
          MVar () -> () -> IO ()
forall (m :: * -> *) a. MonadIO m => MVar a -> a -> m ()
putMVar MVar ()
mv ()
          PkgName -> IO PkgName
forall (f :: * -> *) a. Applicative f => a -> f a
pure PkgName
r

-- | The most recent version of a package, if it exists in the respositories.
mostRecent :: Environment -> PkgName -> IO (Either PkgName Versioning)
mostRecent :: Environment -> PkgName -> IO (Either PkgName Versioning)
mostRecent Environment
env p :: PkgName
p@(PkgName Text
s) = PkgName -> Maybe Versioning -> Either PkgName Versioning
forall a b. a -> Maybe b -> Either a b
note PkgName
p (Maybe Versioning -> Either PkgName Versioning)
-> (ByteString -> Maybe Versioning)
-> ByteString
-> Either PkgName Versioning
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Versioning
extractVersion (Text -> Maybe Versioning)
-> (ByteString -> Text) -> ByteString -> Maybe Versioning
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeUtf8Lenient (ByteString -> Either PkgName Versioning)
-> IO ByteString -> IO (Either PkgName Versioning)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Environment -> [Text] -> IO ByteString
pacmanOutput Environment
env [Text
"-Si", Text
s]

-- | Parses the version number of a package from the result of a
-- @pacman -Si@ call.
extractVersion :: Text -> Maybe Versioning
extractVersion :: Text -> Maybe Versioning
extractVersion = Either (ParseErrorBundle Text Void) Versioning -> Maybe Versioning
forall a b. Either a b -> Maybe b
hush (Either (ParseErrorBundle Text Void) Versioning
 -> Maybe Versioning)
-> (Text -> Either (ParseErrorBundle Text Void) Versioning)
-> Text
-> Maybe Versioning
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parsec Void Text Versioning
-> String -> Text -> Either (ParseErrorBundle Text Void) Versioning
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
parse Parsec Void Text Versioning
p String
"extractVersion"
  where p :: Parsec Void Text Versioning
p = do
          ParsecT Void Text Identity Char -> ParsecT Void Text Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void Text Identity Char -> ParsecT Void Text Identity ())
-> ParsecT Void Text Identity Char -> ParsecT Void Text Identity ()
forall a b. (a -> b) -> a -> b
$ Maybe String
-> (Token Text -> Bool) -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Maybe String -> (Token s -> Bool) -> m (Tokens s)
takeWhile1P Maybe String
forall a. Maybe a
Nothing (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n') ParsecT Void Text Identity Text
-> ParsecT Void Text Identity Char
-> ParsecT Void Text Identity Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Void Text Identity Char
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
newline
          ParsecT Void Text Identity Char -> ParsecT Void Text Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void Text Identity Char -> ParsecT Void Text Identity ())
-> ParsecT Void Text Identity Char -> ParsecT Void Text Identity ()
forall a b. (a -> b) -> a -> b
$ Maybe String
-> (Token Text -> Bool) -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Maybe String -> (Token s -> Bool) -> m (Tokens s)
takeWhile1P Maybe String
forall a. Maybe a
Nothing (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n') ParsecT Void Text Identity Text
-> ParsecT Void Text Identity Char
-> ParsecT Void Text Identity Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Void Text Identity Char
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
newline
          Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"Version" ParsecT Void Text Identity Text
-> ParsecT Void Text Identity () -> ParsecT Void Text Identity ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Void Text Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
space1 ParsecT Void Text Identity ()
-> ParsecT Void Text Identity Char
-> ParsecT Void Text Identity Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token Text
':' ParsecT Void Text Identity Char
-> ParsecT Void Text Identity () -> ParsecT Void Text Identity ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Void Text Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
space1 ParsecT Void Text Identity ()
-> Parsec Void Text Versioning -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsec Void Text Versioning
v
        v :: Parsec Void Text Versioning
v = [Parsec Void Text Versioning] -> Parsec Void Text Versioning
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice [ Parsec Void Text Versioning -> Parsec Void Text Versioning
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ((SemVer -> Versioning)
-> ParsecT Void Text Identity SemVer -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SemVer -> Versioning
Ideal ParsecT Void Text Identity SemVer
semver'    Parsec Void Text Versioning
-> ParsecT Void Text Identity Text -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"Description")
                   , Parsec Void Text Versioning -> Parsec Void Text Versioning
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try ((Version -> Versioning)
-> ParsecT Void Text Identity Version
-> Parsec Void Text Versioning
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Version -> Versioning
General ParsecT Void Text Identity Version
version' Parsec Void Text Versioning
-> ParsecT Void Text Identity Text -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"Description")
                   , (Mess -> Versioning)
-> ParsecT Void Text Identity Mess -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Mess -> Versioning
Complex ParsecT Void Text Identity Mess
mess'         Parsec Void Text Versioning
-> ParsecT Void Text Identity Text -> Parsec Void Text Versioning
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens Text
"Description" ]