-- |
-- Module      : Debian.Package.Data.Packages
-- Copyright   : 2014-2015 Kei Hibino
-- License     : BSD3
--
-- Maintainer  : ex8k.hibino@gmail.com
-- Stability   : experimental
-- Portability : portable
--
-- This module provides data types of debian packages meta information.
module Debian.Package.Data.Packages
       ( DebianVersion, versionFromHackageVersion, readDebianVersion, origVersion', isNative'

       , Source, mkSource, sourceName, version, origVersion, isNative

       , origArchiveName, nativeArchiveName, sourceDirName, deriveHackageVersion

       , parseChangeLog

       , PackageType (..), takeChangesType, isSourcePackage, isBinaryPackage

       , Control (..), parseControlEntry, parseControl

       , HaskellPackage, hackage, package
       , haskellPackageDefault, haskellPackageFromPackage
       ) where

import Control.Applicative ((<$>), pure, (<*>), (*>), (<*), empty, (<|>), many, some, optional)
import Control.Monad.Trans.State (StateT, runStateT, get, put)
import Data.Maybe (listToMaybe, maybeToList, mapMaybe)
import Data.Char (isSpace, isDigit)
import Data.Version (Version (Version, versionBranch), showVersion)
import Data.List.Split (splitOn)
import System.FilePath ((<.>), takeFileName, splitExtension)

import Debian.Package.Data.Hackage
  (HackageVersion, mkHackageVersion', hackageVersionNumbers,
   Hackage, mkHackageDefault, NameRule (Simple), debianNamesFromSourceName)


type Parser = StateT String Maybe

satisfy :: (Char -> Bool) -> Parser Char
satisfy :: (Char -> Bool) -> Parser Char
satisfy Char -> Bool
p = do
  String
s <- StateT String Maybe String
forall (m :: * -> *) s. Monad m => StateT s m s
get
  case String
s of
    Char
c:String
cs -> if Char -> Bool
p Char
c
            then  String -> StateT String Maybe ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put String
cs StateT String Maybe () -> Parser Char -> Parser Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Char -> Parser Char
forall (f :: * -> *) a. Applicative f => a -> f a
pure Char
c
            else  Parser Char
forall (f :: * -> *) a. Alternative f => f a
empty
    []   ->       Parser Char
forall (f :: * -> *) a. Alternative f => f a
empty

_look :: Parser String
_look :: StateT String Maybe String
_look =  StateT String Maybe String
forall (m :: * -> *) s. Monad m => StateT s m s
get

eof :: Parser ()
eof :: StateT String Maybe ()
eof =  do
  String
s <- StateT String Maybe String
forall (m :: * -> *) s. Monad m => StateT s m s
get
  case String
s of
    []   -> () -> StateT String Maybe ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    Char
_:String
_  -> StateT String Maybe ()
forall (f :: * -> *) a. Alternative f => f a
empty

runParser :: Parser a -> String -> Maybe (a, String)
runParser :: Parser a -> String -> Maybe (a, String)
runParser =  Parser a -> String -> Maybe (a, String)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT

anyChar :: Parser Char
anyChar :: Parser Char
anyChar =  (Char -> Bool) -> Parser Char
satisfy (Bool -> Char -> Bool
forall a b. a -> b -> a
const Bool
True)

char :: Char -> Parser Char
char :: Char -> Parser Char
char Char
x = (Char -> Bool) -> Parser Char
satisfy (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
x)

notChar :: Char -> Parser Char
notChar :: Char -> Parser Char
notChar Char
x = (Char -> Bool) -> Parser Char
satisfy (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
x)

space :: Parser Char
space :: Parser Char
space =  Char -> Parser Char
char Char
' '

digit :: Parser Char
digit :: Parser Char
digit =  (Char -> Bool) -> Parser Char
satisfy Char -> Bool
isDigit

int :: Parser Int
int :: Parser Int
int =  String -> Int
forall a. Read a => String -> a
read (String -> Int) -> StateT String Maybe String -> Parser Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Char -> StateT String Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some Parser Char
digit

string :: String -> Parser String
string :: String -> StateT String Maybe String
string =  (Char -> Parser Char) -> String -> StateT String Maybe String
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Char -> Parser Char
char


-- | Version type for Debian
data DebianVersion
  = DebianNative    Version (Maybe Int)
  | DebianNonNative Version String

debianNativeVersion :: [Int] -> Maybe Int -> DebianVersion
debianNativeVersion :: [Int] -> Maybe Int -> DebianVersion
debianNativeVersion [Int]
v =  Version -> Maybe Int -> DebianVersion
DebianNative ([Int] -> [String] -> Version
Version [Int]
v [])

debianNonNativeVersion :: [Int] -> String -> DebianVersion
debianNonNativeVersion :: [Int] -> String -> DebianVersion
debianNonNativeVersion [Int]
v = Version -> String -> DebianVersion
DebianNonNative ([Int] -> [String] -> Version
Version [Int]
v [])

-- | Make deebian version from hackage version
versionFromHackageVersion :: HackageVersion -> Maybe String -> DebianVersion
versionFromHackageVersion :: HackageVersion -> Maybe String -> DebianVersion
versionFromHackageVersion HackageVersion
hv = Maybe String -> DebianVersion
d where
  d :: Maybe String -> DebianVersion
d (Just String
rev) = [Int] -> String -> DebianVersion
debianNonNativeVersion [Int]
ns String
rev
  d Maybe String
Nothing    = [Int] -> Maybe Int -> DebianVersion
debianNativeVersion    [Int]
ns Maybe Int
forall a. Maybe a
Nothing
  ns :: [Int]
ns = HackageVersion -> [Int]
hackageVersionNumbers HackageVersion
hv

-- | Version without debian revision
origVersion' :: DebianVersion -> Version
origVersion' :: DebianVersion -> Version
origVersion' =  DebianVersion -> Version
d  where
  d :: DebianVersion -> Version
d (DebianNative    Version
v Maybe Int
_) = Version
v
  d (DebianNonNative Version
v String
_) = Version
v

-- | Is debian-native or not
isNative' :: DebianVersion -> Bool
isNative' :: DebianVersion -> Bool
isNative' = DebianVersion -> Bool
d where
  d :: DebianVersion -> Bool
d (DebianNative    Version
_ Maybe Int
_) = Bool
True
  d (DebianNonNative Version
_ String
_) = Bool
False

parseVersion' :: Parser Version
parseVersion' :: Parser Version
parseVersion' =
  [Int] -> [String] -> Version
Version
  ([Int] -> [String] -> Version)
-> StateT String Maybe [Int]
-> StateT String Maybe ([String] -> Version)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((:) (Int -> [Int] -> [Int])
-> Parser Int -> StateT String Maybe ([Int] -> [Int])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Int
int StateT String Maybe ([Int] -> [Int])
-> StateT String Maybe [Int] -> StateT String Maybe [Int]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Int -> StateT String Maybe [Int]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Char -> Parser Char
char Char
'.' Parser Char -> Parser Int -> Parser Int
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Int
int))
  StateT String Maybe ([String] -> Version)
-> StateT String Maybe [String] -> Parser Version
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [String] -> StateT String Maybe [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []

parseDebianVersion :: Parser DebianVersion
parseDebianVersion :: Parser DebianVersion
parseDebianVersion = do
  Version
v <- Parser Version
parseVersion'
  (Version -> String -> DebianVersion
DebianNonNative Version
v (String -> DebianVersion)
-> StateT String Maybe String -> Parser DebianVersion
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Parser Char
char Char
'-' Parser Char
-> StateT String Maybe String -> StateT String Maybe String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Char -> StateT String Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some ((Char -> Bool) -> Parser Char
satisfy (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace)))
   Parser DebianVersion
-> Parser DebianVersion -> Parser DebianVersion
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
   Version -> Maybe Int -> DebianVersion
DebianNative    Version
v (Maybe Int -> DebianVersion)
-> StateT String Maybe (Maybe Int) -> Parser DebianVersion
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Int -> StateT String Maybe (Maybe Int)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (String -> StateT String Maybe String
string String
"+nmu" StateT String Maybe String -> Parser Int -> Parser Int
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Int
int))

_testParseDebianVersion :: [Maybe (DebianVersion, String)]
_testParseDebianVersion :: [Maybe (DebianVersion, String)]
_testParseDebianVersion =
  [ Parser DebianVersion -> String -> Maybe (DebianVersion, String)
forall a. Parser a -> String -> Maybe (a, String)
runParser Parser DebianVersion
parseDebianVersion String
s | String
s <- [ String
"1.23.3-4", String
"1.23", String
"12.3+nmu2" ] ]

instance Show DebianVersion where
  show :: DebianVersion -> String
show = DebianVersion -> String
d  where
    d :: DebianVersion -> String
d (DebianNative    Version
v Maybe Int
nr) = Version -> String
showVersion Version
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> (Int -> String) -> Maybe Int -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" ((String
"+nmu" String -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> (Int -> String) -> Int -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show) Maybe Int
nr
    d (DebianNonNative Version
v String
r)  = Version -> String
showVersion Version
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'-'Char -> ShowS
forall a. a -> [a] -> [a]
: String
r

instance Read DebianVersion where
  readsPrec :: Int -> ReadS DebianVersion
readsPrec Int
_ = Maybe (DebianVersion, String) -> [(DebianVersion, String)]
forall a. Maybe a -> [a]
maybeToList (Maybe (DebianVersion, String) -> [(DebianVersion, String)])
-> (String -> Maybe (DebianVersion, String)) -> ReadS DebianVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser DebianVersion -> String -> Maybe (DebianVersion, String)
forall a. Parser a -> String -> Maybe (a, String)
runParser Parser DebianVersion
parseDebianVersion

readMaybe' :: Read a => String -> Maybe a
readMaybe' :: String -> Maybe a
readMaybe' =  ((a, String) -> a) -> Maybe (a, String) -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, String) -> a
forall a b. (a, b) -> a
fst (Maybe (a, String) -> Maybe a)
-> (String -> Maybe (a, String)) -> String -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(a, String)] -> Maybe (a, String)
forall a. [a] -> Maybe a
listToMaybe ([(a, String)] -> Maybe (a, String))
-> (String -> [(a, String)]) -> String -> Maybe (a, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, String) -> Bool) -> [(a, String)] -> [(a, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"") (String -> Bool) -> ((a, String) -> String) -> (a, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, String) -> String
forall a b. (a, b) -> b
snd) ([(a, String)] -> [(a, String)])
-> (String -> [(a, String)]) -> String -> [(a, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [(a, String)]
forall a. Read a => ReadS a
reads

-- | Try to read debian package version
readDebianVersion :: String -> Maybe DebianVersion
readDebianVersion :: String -> Maybe DebianVersion
readDebianVersion =  String -> Maybe DebianVersion
forall a. Read a => String -> Maybe a
readMaybe'

-- | Debian source package type, name with version
data Source = Source String DebianVersion  deriving Int -> Source -> ShowS
[Source] -> ShowS
Source -> String
(Int -> Source -> ShowS)
-> (Source -> String) -> ([Source] -> ShowS) -> Show Source
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Source] -> ShowS
$cshowList :: [Source] -> ShowS
show :: Source -> String
$cshow :: Source -> String
showsPrec :: Int -> Source -> ShowS
$cshowsPrec :: Int -> Source -> ShowS
Show

-- | Make 'Source'
mkSource :: String -> DebianVersion -> Source
mkSource :: String -> DebianVersion -> Source
mkSource =  String -> DebianVersion -> Source
Source

-- | Source package name of 'Source'
sourceName :: Source -> String
sourceName :: Source -> String
sourceName (Source String
n DebianVersion
_) = String
n

-- | Debian version of 'Source'
version :: Source -> DebianVersion
version :: Source -> DebianVersion
version (Source String
_ DebianVersion
v) = DebianVersion
v

-- | Version without debian revision
origVersion :: Source -> Version
origVersion :: Source -> Version
origVersion =  DebianVersion -> Version
origVersion' (DebianVersion -> Version)
-> (Source -> DebianVersion) -> Source -> Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Source -> DebianVersion
version

-- | Is debian-native or not
isNative :: Source -> Bool
isNative :: Source -> Bool
isNative =  DebianVersion -> Bool
isNative' (DebianVersion -> Bool)
-> (Source -> DebianVersion) -> Source -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Source -> DebianVersion
version

-- | Original source archive basename
origArchiveName :: Source -> FilePath
origArchiveName :: Source -> String
origArchiveName Source
pkg = Source -> String
sourceName Source
pkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'_' Char -> ShowS
forall a. a -> [a] -> [a]
: Version -> String
showVersion (Source -> Version
origVersion Source
pkg) String -> ShowS
<.> String
"orig" String -> ShowS
<.> String
"tar" String -> ShowS
<.> String
"gz"

-- | Debian native archive basename
nativeArchiveName :: Source -> String
nativeArchiveName :: Source -> String
nativeArchiveName Source
pkg = Source -> String
sourceName Source
pkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'_' Char -> ShowS
forall a. a -> [a] -> [a]
: DebianVersion -> String
forall a. Show a => a -> String
show (Source -> DebianVersion
version Source
pkg) String -> ShowS
<.> String
"tar" String -> ShowS
<.> String
"gz"

-- | Source directory basename
sourceDirName :: Source -> FilePath
sourceDirName :: Source -> String
sourceDirName Source
pkg = Source -> String
sourceName Source
pkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'-' Char -> ShowS
forall a. a -> [a] -> [a]
: Version -> String
showVersion (Source -> Version
origVersion Source
pkg)

-- | Try to make 'HackageVersion' from 'Source'
deriveHackageVersion :: Source -> HackageVersion
deriveHackageVersion :: Source -> HackageVersion
deriveHackageVersion =  [Int] -> HackageVersion
mkHackageVersion' ([Int] -> HackageVersion)
-> (Source -> [Int]) -> Source -> HackageVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> [Int]
versionBranch (Version -> [Int]) -> (Source -> Version) -> Source -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Source -> Version
origVersion where

parseColonLine :: String -> Maybe (String, String)
parseColonLine :: String -> Maybe (String, String)
parseColonLine =
  ((((String, String), String) -> (String, String))
-> Maybe ((String, String), String) -> Maybe (String, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((String, String), String) -> (String, String)
forall a b. (a, b) -> a
fst (Maybe ((String, String), String) -> Maybe (String, String))
-> (String -> Maybe ((String, String), String))
-> String
-> Maybe (String, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((String -> Maybe ((String, String), String))
 -> String -> Maybe (String, String))
-> (Parser (String, String)
    -> String -> Maybe ((String, String), String))
-> Parser (String, String)
-> String
-> Maybe (String, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser (String, String)
-> String -> Maybe ((String, String), String)
forall a. Parser a -> String -> Maybe (a, String)
runParser (Parser (String, String) -> String -> Maybe (String, String))
-> Parser (String, String) -> String -> Maybe (String, String)
forall a b. (a -> b) -> a -> b
$
  (,) (String -> String -> (String, String))
-> StateT String Maybe String
-> StateT String Maybe (String -> (String, String))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Char -> StateT String Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some (Char -> Parser Char
notChar Char
':') StateT String Maybe (String -> (String, String))
-> StateT String Maybe String -> Parser (String, String)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Char -> Parser Char
char Char
':' Parser Char
-> StateT String Maybe String -> StateT String Maybe String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Char -> StateT String Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Char
space StateT String Maybe String
-> StateT String Maybe String -> StateT String Maybe String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Char -> StateT String Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Char
anyChar StateT String Maybe String
-> StateT String Maybe () -> StateT String Maybe String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* StateT String Maybe ()
eof)

-- | Try to generate 'Source' from debian changelog string
parseChangeLog :: String       -- ^ dpkg-parsechangelog result string
               -> Maybe Source -- ^ Source structure
parseChangeLog :: String -> Maybe Source
parseChangeLog String
log' = do
  String
deb  <- Maybe String
mayDebSrc
  DebianVersion
dver <- Maybe DebianVersion
mayDebVer
  Source -> Maybe Source
forall (m :: * -> *) a. Monad m => a -> m a
return (Source -> Maybe Source) -> Source -> Maybe Source
forall a b. (a -> b) -> a -> b
$ String -> DebianVersion -> Source
mkSource String
deb DebianVersion
dver
  where
    pairs :: [(String, String)]
pairs = (String -> Maybe (String, String))
-> [String] -> [(String, String)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe String -> Maybe (String, String)
parseColonLine ([String] -> [(String, String)])
-> (String -> [String]) -> String -> [(String, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines (String -> [(String, String)]) -> String -> [(String, String)]
forall a b. (a -> b) -> a -> b
$ String
log'
    lookup' :: String -> Maybe String
lookup' = (String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` [(String, String)]
pairs)
    mayDebSrc :: Maybe String
mayDebSrc = String -> Maybe String
lookup' String
"Source"
    mayDebVer :: Maybe DebianVersion
mayDebVer = do
      String
dverS <- String -> Maybe String
lookup' String
"Version"
      String -> Maybe DebianVersion
readDebianVersion String
dverS

-- | Debian package types
data PackageType
  = PackageArch (Maybe String)
  | PackageAll
  | PackageSource
  deriving (PackageType -> PackageType -> Bool
(PackageType -> PackageType -> Bool)
-> (PackageType -> PackageType -> Bool) -> Eq PackageType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PackageType -> PackageType -> Bool
$c/= :: PackageType -> PackageType -> Bool
== :: PackageType -> PackageType -> Bool
$c== :: PackageType -> PackageType -> Bool
Eq, Int -> PackageType -> ShowS
[PackageType] -> ShowS
PackageType -> String
(Int -> PackageType -> ShowS)
-> (PackageType -> String)
-> ([PackageType] -> ShowS)
-> Show PackageType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PackageType] -> ShowS
$cshowList :: [PackageType] -> ShowS
show :: PackageType -> String
$cshow :: PackageType -> String
showsPrec :: Int -> PackageType -> ShowS
$cshowsPrec :: Int -> PackageType -> ShowS
Show)

-- | Take 'PackageType' from debian .changes file path
takeChangesType :: FilePath -> Maybe PackageType
takeChangesType :: String -> Maybe PackageType
takeChangesType String
path = (String, String) -> Maybe PackageType
d ((String, String) -> Maybe PackageType)
-> (String -> (String, String)) -> String -> Maybe PackageType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> (String, String)
splitExtension (String -> Maybe PackageType) -> String -> Maybe PackageType
forall a b. (a -> b) -> a -> b
$ ShowS
takeFileName String
path  where
  d :: (String, String) -> Maybe PackageType
d (String
n, String
".changes") = case [String]
xs of
    [String
_, String
_, String
a] -> case String
a of
      String
"all"    -> PackageType -> Maybe PackageType
forall a. a -> Maybe a
Just   PackageType
PackageAll
      String
"source" -> PackageType -> Maybe PackageType
forall a. a -> Maybe a
Just   PackageType
PackageSource
      String
_        -> PackageType -> Maybe PackageType
forall a. a -> Maybe a
Just (PackageType -> Maybe PackageType)
-> (Maybe String -> PackageType)
-> Maybe String
-> Maybe PackageType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe String -> PackageType
PackageArch (Maybe String -> Maybe PackageType)
-> Maybe String -> Maybe PackageType
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
a
    [String]
_          -> Maybe PackageType
forall a. Maybe a
Nothing
    where xs :: [String]
xs = String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn String
"_" String
n
  d (String
_, String
_)     =  Maybe PackageType
forall a. Maybe a
Nothing

-- | Test package type is source package.
isSourcePackage :: PackageType -> Bool
isSourcePackage :: PackageType -> Bool
isSourcePackage = PackageType -> Bool
d where
  d :: PackageType -> Bool
d (PackageArch Maybe String
_) = Bool
False
  d  PackageType
PackageAll     = Bool
False
  d  PackageType
PackageSource  = Bool
True

-- | Test package type is binary package.
isBinaryPackage :: PackageType -> Bool
isBinaryPackage :: PackageType -> Bool
isBinaryPackage = Bool -> Bool
not (Bool -> Bool) -> (PackageType -> Bool) -> PackageType -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageType -> Bool
isSourcePackage

-- | Type for debian control meta-data.
data Control =
  Control
  { Control -> String
controlSource :: String
  , Control -> [String]
controlArch   :: [String]
  , Control -> [String]
controlAll    :: [String]
  } deriving (Control -> Control -> Bool
(Control -> Control -> Bool)
-> (Control -> Control -> Bool) -> Eq Control
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Control -> Control -> Bool
$c/= :: Control -> Control -> Bool
== :: Control -> Control -> Bool
$c== :: Control -> Control -> Bool
Eq, Int -> Control -> ShowS
[Control] -> ShowS
Control -> String
(Int -> Control -> ShowS)
-> (Control -> String) -> ([Control] -> ShowS) -> Show Control
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Control] -> ShowS
$cshowList :: [Control] -> ShowS
show :: Control -> String
$cshow :: Control -> String
showsPrec :: Int -> Control -> ShowS
$cshowsPrec :: Int -> Control -> ShowS
Show)

-- | Parse an package entry in control file.
parseControlEntry :: [String] -> Maybe (PackageType, String)
parseControlEntry :: [String] -> Maybe (PackageType, String)
parseControlEntry [String]
b =
  do String
a <- String -> Maybe String
lookup' String
"Architecture"
     String
p <- String -> Maybe String
lookup' String
"Package"
     (PackageType, String) -> Maybe (PackageType, String)
forall a. a -> Maybe a
Just ((PackageType, String) -> Maybe (PackageType, String))
-> (PackageType, String) -> Maybe (PackageType, String)
forall a b. (a -> b) -> a -> b
$ if String
a String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"all"
            then (PackageType
PackageAll, String
p)
            else (Maybe String -> PackageType
PackageArch (Maybe String -> PackageType) -> Maybe String -> PackageType
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
a, String
p)
  Maybe (PackageType, String)
-> Maybe (PackageType, String) -> Maybe (PackageType, String)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
  do String
s <- String -> Maybe String
lookup' String
"Source"
     (PackageType, String) -> Maybe (PackageType, String)
forall a. a -> Maybe a
Just (PackageType
PackageSource, String
s)
  where ps :: [(String, String)]
ps = (String -> Maybe (String, String))
-> [String] -> [(String, String)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe String -> Maybe (String, String)
parseColonLine [String]
b
        lookup' :: String -> Maybe String
lookup' = (String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` [(String, String)]
ps)

packagesPartition :: [(PackageType, a)] -> ([a], [a], [a])
packagesPartition :: [(PackageType, a)] -> ([a], [a], [a])
packagesPartition = [(PackageType, a)] -> ([a], [a], [a])
forall a. [(PackageType, a)] -> ([a], [a], [a])
rec'  where
  rec' :: [(PackageType, a)] -> ([a], [a], [a])
rec' []      = ([], [], [])
  rec' ((PackageType, a)
x:[(PackageType, a)]
xs)  = case (PackageType, a)
x of
    (PackageType
PackageSource, a
a) -> (a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
p, [a]
q, [a]
r)
    (PackageArch Maybe String
_, a
a) -> ([a]
p, a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
q, [a]
r)
    (PackageType
PackageAll   , a
a) -> ([a]
p, [a]
q, a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
r)
    where ([a]
p, [a]
q, [a]
r) = [(PackageType, a)] -> ([a], [a], [a])
rec' [(PackageType, a)]
xs

-- | Parse debian control file into package list.
parseControl :: String -> Maybe Control
parseControl :: String -> Maybe Control
parseControl String
in' = do
  let ([String]
src, [String]
arch, [String]
all') =
        [(PackageType, String)] -> ([String], [String], [String])
forall a. [(PackageType, a)] -> ([a], [a], [a])
packagesPartition ([(PackageType, String)] -> ([String], [String], [String]))
-> (String -> [(PackageType, String)])
-> String
-> ([String], [String], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> Maybe (PackageType, String))
-> [[String]] -> [(PackageType, String)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe [String] -> Maybe (PackageType, String)
parseControlEntry
        ([[String]] -> [(PackageType, String)])
-> (String -> [[String]]) -> String -> [(PackageType, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> Bool) -> [[String]] -> [[String]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([String] -> Bool) -> [String] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) ([[String]] -> [[String]])
-> (String -> [[String]]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String] -> [[String]]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn [String
""] ([String] -> [[String]])
-> (String -> [String]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines (String -> ([String], [String], [String]))
-> String -> ([String], [String], [String])
forall a b. (a -> b) -> a -> b
$ String
in'
  String
s <- [String] -> Maybe String
forall a. [a] -> Maybe a
listToMaybe [String]
src
  Control -> Maybe Control
forall a. a -> Maybe a
Just (Control -> Maybe Control) -> Control -> Maybe Control
forall a b. (a -> b) -> a -> b
$ String -> [String] -> [String] -> Control
Control String
s [String]
arch [String]
all'


-- | Debian source package type for Haskell
data HaskellPackage = HaskellPackage Hackage Source deriving Int -> HaskellPackage -> ShowS
[HaskellPackage] -> ShowS
HaskellPackage -> String
(Int -> HaskellPackage -> ShowS)
-> (HaskellPackage -> String)
-> ([HaskellPackage] -> ShowS)
-> Show HaskellPackage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HaskellPackage] -> ShowS
$cshowList :: [HaskellPackage] -> ShowS
show :: HaskellPackage -> String
$cshow :: HaskellPackage -> String
showsPrec :: Int -> HaskellPackage -> ShowS
$cshowsPrec :: Int -> HaskellPackage -> ShowS
Show

-- | 'Hackage' meta-info of 'HaskellPackage'
hackage :: HaskellPackage -> Hackage
hackage :: HaskellPackage -> Hackage
hackage (HaskellPackage Hackage
h Source
_) = Hackage
h

-- | Debian source package meta-info of 'HaskellPackage'
package :: HaskellPackage -> Source
package :: HaskellPackage -> Source
package (HaskellPackage Hackage
_ Source
p) = Source
p

-- | Generate 'HaskellPackage' type from debian package name and version
--   using 'NameRule'
haskellPackageDefault :: NameRule
                      -> String         -- ^ Hackage name string
                      -> HackageVersion -- ^ Version of hackage
                      -> Maybe String   -- ^ Debian revision String
                      -> HaskellPackage -- ^ Result structure
haskellPackageDefault :: NameRule
-> String -> HackageVersion -> Maybe String -> HaskellPackage
haskellPackageDefault NameRule
rule String
hname HackageVersion
hver Maybe String
mayDevRev =
  Hackage -> Source -> HaskellPackage
HaskellPackage
  (NameRule -> String -> HackageVersion -> Hackage
mkHackageDefault NameRule
rule String
hname HackageVersion
hver)
  (String -> DebianVersion -> Source
mkSource String
sn (HackageVersion -> Maybe String -> DebianVersion
versionFromHackageVersion HackageVersion
hver Maybe String
mayDevRev))
  where
    (String
sn, String
_) = NameRule -> String -> (String, String)
debianNamesFromSourceName NameRule
rule String
hname

-- | Generate 'HaskellPackage' with hackage name and debian package meta-info
haskellPackageFromPackage :: String         -- ^ Hackage name string
                          -> Source         -- ^ Debian package meta info
                          -> HaskellPackage -- ^ Result
haskellPackageFromPackage :: String -> Source -> HaskellPackage
haskellPackageFromPackage String
hname Source
pkg = Hackage -> Source -> HaskellPackage
HaskellPackage Hackage
hkg Source
pkg  where
  hv :: HackageVersion
hv  = Source -> HackageVersion
deriveHackageVersion Source
pkg
  hkg :: Hackage
hkg = NameRule -> String -> HackageVersion -> Hackage
mkHackageDefault NameRule
Simple String
hname HackageVersion
hv