-- |
-- Module      : Debian.Package.Data.Hackage
-- Copyright   : 2014-2015 Kei Hibino
-- License     : BSD3
--
-- Maintainer  : ex8k.hibino@gmail.com
-- Stability   : experimental
-- Portability : portable
--
-- This module provides data types of hackage meta information.
module Debian.Package.Data.Hackage
       ( HackageVersion, mkHackageVersion, mkHackageVersion', hackageVersionNumbers

       , Hackage, mkHackage, hackageName, hackageVersion
       , debianShortName, mkHackageDefault

       , NameRule (..), debianNamesFromSourceName

       , hackageLongName

       , hackageArchiveName, hackageArchive

       , ghcLibraryBinPackages, ghcLibraryDocPackage, ghcLibraryPackages
       ) where

import Data.List (stripPrefix)
import Data.Char (toLower)
import Data.Version (Version (Version), showVersion, parseVersion)
import Text.ParserCombinators.ReadP (readP_to_S)
import System.FilePath ((</>), (<.>))


-- | Hackage version type
newtype HackageVersion = HackageVersion (Version)

-- | Make 'HackageVersion'
mkHackageVersion' :: [Int] -> HackageVersion
mkHackageVersion' :: [Int] -> HackageVersion
mkHackageVersion' =  Version -> HackageVersion
HackageVersion (Version -> HackageVersion)
-> ([Int] -> Version) -> [Int] -> HackageVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Int] -> [String] -> Version
`Version` [])

-- | Make 'HackageVersion'
mkHackageVersion :: Int -> Int -> Int -> Int -> HackageVersion
mkHackageVersion :: Int -> Int -> Int -> Int -> HackageVersion
mkHackageVersion Int
v0 Int
v1 Int
v2 Int
v3 = [Int] -> HackageVersion
mkHackageVersion' [Int
v0, Int
v1, Int
v2, Int
v3]

-- | Extract hackage version numbers.
hackageVersionNumbers :: HackageVersion -> [Int]
hackageVersionNumbers :: HackageVersion -> [Int]
hackageVersionNumbers (HackageVersion (Version [Int]
ns [String]
_)) = [Int]
ns

instance Show HackageVersion where
  show :: HackageVersion -> String
show (HackageVersion Version
v) = Version -> String
showVersion Version
v

instance Read HackageVersion where
  readsPrec :: Int -> ReadS HackageVersion
readsPrec Int
_ = ((Version, String) -> (HackageVersion, String))
-> [(Version, String)] -> [(HackageVersion, String)]
forall a b. (a -> b) -> [a] -> [b]
map (Version, String) -> (HackageVersion, String)
forall b. (Version, b) -> (HackageVersion, b)
toH ([(Version, String)] -> [(HackageVersion, String)])
-> (String -> [(Version, String)]) -> ReadS HackageVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Version, String) -> Bool)
-> [(Version, String)] -> [(Version, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Version, String) -> Bool
forall b. (Version, b) -> Bool
h ([(Version, String)] -> [(Version, String)])
-> (String -> [(Version, String)]) -> String -> [(Version, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReadP Version -> String -> [(Version, String)]
forall a. ReadP a -> ReadS a
readP_to_S ReadP Version
parseVersion  where
    h :: (Version, b) -> Bool
h (Version [Int]
b [String]
t, b
_) = [Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
b Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
4 Bool -> Bool -> Bool
&& [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
t
    toH :: (Version, b) -> (HackageVersion, b)
toH (Version
v, b
s) = (Version -> HackageVersion
HackageVersion Version
v, b
s)

-- | Hackage name and version type with debian short name. e.g. /src-ext/.
data Hackage = Hackage String HackageVersion String  deriving Int -> Hackage -> ShowS
[Hackage] -> ShowS
Hackage -> String
(Int -> Hackage -> ShowS)
-> (Hackage -> String) -> ([Hackage] -> ShowS) -> Show Hackage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Hackage] -> ShowS
$cshowList :: [Hackage] -> ShowS
show :: Hackage -> String
$cshow :: Hackage -> String
showsPrec :: Int -> Hackage -> ShowS
$cshowsPrec :: Int -> Hackage -> ShowS
Show

-- | Make 'Hackage'
mkHackage :: String -> HackageVersion -> String -> Hackage
mkHackage :: String -> HackageVersion -> String -> Hackage
mkHackage =  String -> HackageVersion -> String -> Hackage
Hackage

-- | Get package name of 'Hackage'
hackageName :: Hackage -> String
hackageName :: Hackage -> String
hackageName (Hackage String
n HackageVersion
_ String
_) = String
n

-- | Get version of 'Hackage'
hackageVersion :: Hackage -> HackageVersion
hackageVersion :: Hackage -> HackageVersion
hackageVersion (Hackage String
_ HackageVersion
v String
_) = HackageVersion
v

-- | Get debian short name of 'Hackage'
debianShortName :: Hackage -> String
debianShortName :: Hackage -> String
debianShortName (Hackage String
_ HackageVersion
_ String
sn) = String
sn

-- | Generate 'Hackage' type from package name and version
--   using 'NameRule'
mkHackageDefault :: NameRule       -- ^ Rule flag to generate names
                 -> String         -- ^ Hackage name string
                 -> HackageVersion -- ^ Version of hackage
                 -> Hackage        -- ^ Result hackage meta info
mkHackageDefault :: NameRule -> String -> HackageVersion -> Hackage
mkHackageDefault NameRule
rule String
hname HackageVersion
hver = String -> HackageVersion -> String -> Hackage
mkHackage String
hname HackageVersion
hver String
short  where
  (String
_ , String
short) = NameRule -> String -> (String, String)
debianNamesFromSourceName NameRule
rule String
hname

defaultHackageSrcPrefix :: String
defaultHackageSrcPrefix :: String
defaultHackageSrcPrefix =  String
"haskell-"

-- | Debian short name generate rule
data NameRule = Suggest | Simple deriving (NameRule -> NameRule -> Bool
(NameRule -> NameRule -> Bool)
-> (NameRule -> NameRule -> Bool) -> Eq NameRule
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NameRule -> NameRule -> Bool
$c/= :: NameRule -> NameRule -> Bool
== :: NameRule -> NameRule -> Bool
$c== :: NameRule -> NameRule -> Bool
Eq, Int -> NameRule -> ShowS
[NameRule] -> ShowS
NameRule -> String
(Int -> NameRule -> ShowS)
-> (NameRule -> String) -> ([NameRule] -> ShowS) -> Show NameRule
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NameRule] -> ShowS
$cshowList :: [NameRule] -> ShowS
show :: NameRule -> String
$cshow :: NameRule -> String
showsPrec :: Int -> NameRule -> ShowS
$cshowsPrec :: Int -> NameRule -> ShowS
Show)

-- | Make debian short name from package name using 'NameRule'
debianNamesFromSourceName :: NameRule          -- ^ Rule flag to generate name
                          -> String            -- ^ Debian source name or Hackage name string
                          -> (String, String)  -- ^ Debian source package name and short name like ("haskell-src-exts", "src-exts")
debianNamesFromSourceName :: NameRule -> String -> (String, String)
debianNamesFromSourceName NameRule
rule String
hname = NameRule -> (String, String)
d NameRule
rule  where
  lh :: String
lh = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
hname
  d :: NameRule -> (String, String)
d NameRule
Suggest  =  [String] -> (String, String)
rec' [String
"haskell-", String
"haskell"]
  d NameRule
Simple   =  (String
defaultHackageSrcPrefix String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lh, String
lh)
  rec' :: [String] -> (String, String)
rec' []     = (String
defaultHackageSrcPrefix String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lh, String
lh)
  rec' (String
p:[String]
ps) = case String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix String
p String
lh of
    Just String
s  -> (String
lh, String
s)
    Maybe String
Nothing -> [String] -> (String, String)
rec' [String]
ps

-- | Package name string with version
hackageLongName :: Hackage -> String
hackageLongName :: Hackage -> String
hackageLongName Hackage
hkg = Hackage -> String
hackageName Hackage
hkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'-' Char -> ShowS
forall a. a -> [a] -> [a]
: HackageVersion -> String
forall a. Show a => a -> String
show (Hackage -> HackageVersion
hackageVersion Hackage
hkg)

-- | Package archive basename
hackageArchiveName :: Hackage -> FilePath
hackageArchiveName :: Hackage -> String
hackageArchiveName Hackage
hkg = Hackage -> String
hackageLongName Hackage
hkg String -> ShowS
<.> String
"tar" String -> ShowS
<.> String
"gz"

distDir :: String
distDir :: String
distDir =  String
"dist"

-- | Package archive pathname
hackageArchive :: Hackage -> FilePath
hackageArchive :: Hackage -> String
hackageArchive =  (String
distDir String -> ShowS
</>) ShowS -> (Hackage -> String) -> Hackage -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hackage -> String
hackageArchiveName


-- | Debian library binary package names for GHC
ghcLibraryBinPackages :: Hackage -> [String]
ghcLibraryBinPackages :: Hackage -> [String]
ghcLibraryBinPackages Hackage
hkg =
  [ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"libghc-", Hackage -> String
debianShortName Hackage
hkg, Char
'-' Char -> ShowS
forall a. a -> [a] -> [a]
: String
suf]
  | String
suf <- [String
"dev", String
"prof"]
  ]

-- | Debian library document package name for GHC
ghcLibraryDocPackage :: Hackage -> String
ghcLibraryDocPackage :: Hackage -> String
ghcLibraryDocPackage Hackage
hkg = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"libghc-", Hackage -> String
debianShortName Hackage
hkg, String
"-doc"]

-- | Debian library package names for GHC
ghcLibraryPackages :: Hackage -> [String]
ghcLibraryPackages :: Hackage -> [String]
ghcLibraryPackages Hackage
hkg = Hackage -> String
ghcLibraryDocPackage Hackage
hkg String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Hackage -> [String]
ghcLibraryBinPackages Hackage
hkg