module Cabal2Spec ( cabal2spec, createSpecFile, ForceBinary, RunTests, CopyrightYear ) where

import Control.Monad
import Data.Char
import Data.List ( delete, nub, sort, (\\), inits, intersect, isPrefixOf, groupBy )
import Data.Time.Clock
import Data.Time.Format
import Distribution.Compiler
import Distribution.License
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Configuration
import Distribution.Pretty
import Distribution.Simple.PackageDescription
import Distribution.System
import Distribution.Text
import Distribution.Types.ComponentRequestedSpec
import Distribution.Utils.Path ( getSymbolicPath )
import Distribution.Utils.ShortText ( fromShortText )
import Distribution.Verbosity
import Distribution.Version
import System.FilePath
import System.IO

type ForceBinary = Bool
type RunTests = Bool
type CopyrightYear = Int

cabal2spec :: Platform -> CompilerId -> FlagAssignment -> ForceBinary -> RunTests -> Maybe CopyrightYear
           -> FilePath -> FilePath -> IO ()
cabal2spec :: Platform
-> CompilerId
-> FlagAssignment
-> ForceBinary
-> ForceBinary
-> Maybe CopyrightYear
-> String
-> String
-> IO ()
cabal2spec Platform
platform CompilerId
compilerId FlagAssignment
flags ForceBinary
forceBinary ForceBinary
runTests Maybe CopyrightYear
copyrightYear String
cabalFile String
specFile = do
  gpd <- Verbosity -> String -> IO GenericPackageDescription
readGenericPackageDescription Verbosity
silent String
cabalFile
  case finalizePD flags requestedComponents (const True) platform (unknownCompilerInfo compilerId NoAbiTag) [] gpd of
    Left [Dependency]
missing -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"finalizePD: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Dependency] -> String
forall a. Show a => a -> String
show [Dependency]
missing)
    Right (PackageDescription
pd,FlagAssignment
_) -> String
-> PackageDescription
-> ForceBinary
-> ForceBinary
-> FlagAssignment
-> Maybe CopyrightYear
-> IO ()
createSpecFile String
specFile PackageDescription
pd ForceBinary
forceBinary ForceBinary
runTests FlagAssignment
flags Maybe CopyrightYear
copyrightYear

requestedComponents :: ComponentRequestedSpec
requestedComponents :: ComponentRequestedSpec
requestedComponents = ComponentRequestedSpec
defaultComponentRequestedSpec

showPkgCfg :: String -> String
showPkgCfg :: String -> String
showPkgCfg String
p = String
"pkgconfig(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
p String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"

mkTools :: [String] -> [String]
mkTools :: [String] -> [String]
mkTools [String]
tools' = (String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter String -> ForceBinary
excludedTools ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
mapTools [String]
tools'
  where
    excludedTools :: String -> ForceBinary
excludedTools String
n = String
n String -> [String] -> ForceBinary
forall (t :: * -> *) a.
(Foldable t, Eq a) =>
a -> t a -> ForceBinary
`notElem` [String
"ghc", String
"hsc2hs", String
"perl"]
    mapTools :: String -> String
mapTools String
"gtk2hsC2hs" = String
"gtk2hs-buildtools"
    mapTools String
"gtk2hsHookGenerator" = String
"gtk2hs-buildtools"
    mapTools String
"gtk2hsTypeGen" = String
"gtk2hs-buildtools"
    mapTools String
tool = String
tool

createSpecFile :: FilePath -> PackageDescription -> ForceBinary -> RunTests -> FlagAssignment -> Maybe CopyrightYear -> IO ()
createSpecFile :: String
-> PackageDescription
-> ForceBinary
-> ForceBinary
-> FlagAssignment
-> Maybe CopyrightYear
-> IO ()
createSpecFile String
specFile PackageDescription
pkgDesc ForceBinary
forceBinary ForceBinary
runTests FlagAssignment
flagAssignment Maybe CopyrightYear
copyrightYear = do
  let deps :: [String]
      deps :: [String]
deps = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
showDevelDep [String]
deps' [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
showProfDep [String]
deps'
      deps' :: [String]
      selfdep :: Bool
      ([String]
deps', ForceBinary
selfdep) = PackageDescription -> String -> ([String], ForceBinary)
buildDependencies PackageDescription
pkgDesc String
name
      pkgcfgs :: [String]
      pkgcfgs :: [String]
pkgcfgs = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
showPkgCfg ([String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (PkgconfigDependency -> String)
-> [PkgconfigDependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map PkgconfigDependency -> String
forall a. IsDependency a => a -> String
depName ([PkgconfigDependency] -> [String])
-> [PkgconfigDependency] -> [String]
forall a b. (a -> b) -> a -> b
$ (BuildInfo -> [PkgconfigDependency])
-> [BuildInfo] -> [PkgconfigDependency]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [PkgconfigDependency]
pkgconfigDepends [BuildInfo]
buildinfo)
      buildinfo :: [BuildInfo]
      buildinfo :: [BuildInfo]
buildinfo = PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkgDesc ComponentRequestedSpec
requestedComponents
      tools :: [String]
      tools :: [String]
tools = [String] -> [String]
mkTools ([String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (LegacyExeDependency -> String)
-> [LegacyExeDependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map LegacyExeDependency -> String
forall a. IsDependency a => a -> String
depName ((BuildInfo -> [LegacyExeDependency])
-> [BuildInfo] -> [LegacyExeDependency]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [LegacyExeDependency]
buildTools [BuildInfo]
buildinfo)) [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
chrpath
      clibs :: [String]
      clibs :: [String]
clibs = [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
resolveLib ((BuildInfo -> [String]) -> [BuildInfo] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [String]
extraLibs [BuildInfo]
buildinfo))
      chrpath :: [String]
      chrpath :: [String]
chrpath = [String
"chrpath" | ForceBinary
selfdep]

      pkg :: PackageIdentifier
pkg = PackageDescription -> PackageIdentifier
package PackageDescription
pkgDesc
      name :: String
name = PackageName -> String
unPackageName (PackageIdentifier -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageIdentifier
pkg)
      hasExec :: ForceBinary
hasExec = PackageDescription -> ForceBinary
hasExes PackageDescription
pkgDesc
      hasLib :: ForceBinary
hasLib = PackageDescription -> ForceBinary
hasLibs PackageDescription
pkgDesc
  (pkgname, binlib) <- Maybe String
-> PackageDescription -> ForceBinary -> IO (String, ForceBinary)
getPkgName (String -> Maybe String
forall a. a -> Maybe a
Just String
specFile) PackageDescription
pkgDesc ForceBinary
forceBinary

  let pkg_name = if String
pkgname String -> String -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== String
name then String
"%{name}" else String
"%{pkg_name}"
      basename | ForceBinary
binlib = String
"%{pkg_name}"
               | ForceBinary
hasExecPkg = String
name
               | ForceBinary
otherwise = String
"ghc-%{pkg_name}"

      hasExecPkg = ForceBinary
binlib ForceBinary -> ForceBinary -> ForceBinary
|| (ForceBinary
hasExec ForceBinary -> ForceBinary -> ForceBinary
&& ForceBinary -> ForceBinary
not ForceBinary
hasLib)
  -- run commands before opening file to prevent empty file on error
  -- maybe shell commands should be in a monad or something

      testsuiteDeps = PackageDescription -> String -> [String]
testsuiteDependencies PackageDescription
pkgDesc String
name

  h <- openFile specFile WriteMode
  let putHdr String
hdr String
val = Handle -> String -> IO ()
hPutStrLn Handle
h (String
hdr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall {t :: * -> *} {a}. Foldable t => t a -> String
padding String
hdr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
val)
      padding t a
hdr = CopyrightYear -> Char -> String
forall a. CopyrightYear -> a -> [a]
replicate (CopyrightYear
14 CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
- t a -> CopyrightYear
forall a. t a -> CopyrightYear
forall (t :: * -> *) a. Foldable t => t a -> CopyrightYear
length t a
hdr) Char
' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
      putNewline = Handle -> String -> IO ()
hPutStrLn Handle
h String
""
      put = Handle -> String -> IO ()
hPutStrLn Handle
h
      putDef String
v String
s = String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [ String
"%global" String -> String -> String
+-+ String
v String -> String -> String
+-+ String
s
                                 , String
"%global pkgver %{pkg_name}-%{version}"
                                 ]
      ghcPkg = if ForceBinary
binlib then String
"-n ghc-%{name}" else String
""
      ghcPkgDevel = if ForceBinary
binlib then String
"-n ghc-%{name}-devel" else String
"devel"

  do
    year <- case copyrightYear of
              Just CopyrightYear
y -> String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CopyrightYear -> String
forall a. Show a => a -> String
show CopyrightYear
y)
              Maybe CopyrightYear
Nothing -> TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%Y" (UTCTime -> String) -> IO UTCTime -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO UTCTime
getCurrentTime
    put "#"
    put $ "# spec file for package " ++ pkgname
    put "#"
    put $ "# Copyright (c) " ++ year ++ " SUSE LLC"
    put "#"
    put "# All modifications and additions to the file contributed by third parties"
    put "# remain the property of their copyright owners, unless otherwise agreed"
    put "# upon. The license for this file, and modifications and additions to the"
    put "# file, is the same license as for the pristine package itself (unless the"
    put "# license for the pristine package is not an Open Source License, in which"
    put "# case the license is the MIT License). An \"Open Source License\" is a"
    put "# license that conforms to the Open Source Definition (Version 1.9)"
    put "# published by the Open Source Initiative."
    putNewline
    put "# Please submit bugfixes or comments via https://bugs.opensuse.org/"
    put "#"
  putNewline
  putNewline

  -- Some packages conflate the synopsis and description fields.  Ugh.
  let syn = ShortText -> String
fromShortText (PackageDescription -> ShortText
synopsis PackageDescription
pkgDesc)
  let initialCapital (Char
c:String
cs) = Char -> Char
toUpper Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs
      initialCapital [] = []
  let syn' = if String -> ForceBinary
badDescription String
syn then String
"FIXME" else ([String] -> String
unwords ([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 b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
initialCapital) String
syn
  let summary = (Char -> ForceBinary) -> String -> String
rstrip (Char -> Char -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== Char
'.') (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> ForceBinary) -> String -> String
rstrip Char -> ForceBinary
isSpace (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
syn'
  let descr = (Char -> ForceBinary) -> String -> String
rstrip Char -> ForceBinary
isSpace (ShortText -> String
fromShortText (PackageDescription -> ShortText
description PackageDescription
pkgDesc))
  let descLines = (String -> [String]
formatParagraphs (String -> [String]) -> (String -> String) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
initialCapital (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
filterSymbols (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
finalPeriod) (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ if String -> ForceBinary
badDescription String
descr then String
syn' else String
descr
      finalPeriod String
cs = if String -> Char
forall a. HasCallStack => [a] -> a
last String
cs Char -> Char -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== Char
'.' then String
cs else String
cs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
      filterSymbols (Char
'@':String
cs)    = Char
'\'' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
filterSymbols String
cs
      filterSymbols (Char
'\\':Char
c:String
cs) = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
filterSymbols String
cs
      filterSymbols (Char
c:String
cs)      = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
filterSymbols String
cs
      filterSymbols []          = []
  when hasLib $
    putDef "pkg_name" name

  unless (null testsuiteDeps) $
    if runTests
       then put "%bcond_without tests"
       else put "%bcond_with tests"

  let version = PackageIdentifier -> Version
forall pkg. Package pkg => pkg -> Version
packageVersion PackageIdentifier
pkg
      revision = CopyrightYear -> String
forall a. Show a => a -> String
show (CopyrightYear -> String) -> CopyrightYear -> String
forall a b. (a -> b) -> a -> b
$ CopyrightYear
-> (String -> CopyrightYear) -> Maybe String -> CopyrightYear
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (CopyrightYear
0::Int) String -> CopyrightYear
forall a. Read a => String -> a
read (String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
"x-revision" (PackageDescription -> [(String, String)]
customFieldsPD PackageDescription
pkgDesc))
  putHdr "Name" (if binlib then "%{pkg_name}" else basename)
  putHdr "Version" (display version)
  putHdr "Release" "0"
  putHdr "Summary" summary
  putHdr "License" $ either (show . pretty) showLicense (licenseRaw pkgDesc)
  putHdr "URL" $ "https://hackage.haskell.org/package/" ++ pkg_name
  putHdr "Source0" $ "https://hackage.haskell.org/package/" ++ pkg_name ++ "-%{version}/" ++ pkg_name ++ "-%{version}.tar.gz"
  when (revision /= "0") $
    putHdr "Source1" $ "https://hackage.haskell.org/package/" ++ pkg_name ++ "-%{version}/revision/" ++ revision ++ ".cabal#/" ++ pkg_name ++ ".cabal"
  putHdr "ExcludeArch" "%{ix86}"

  let fixedDeps = [String
"ghc-Cabal-devel", String
"ghc-rpm-macros"]
  let alldeps = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
fixedDeps [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
deps [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
tools [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
clibs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
pkgcfgs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"pkgconfig" | ForceBinary -> ForceBinary
not ([String] -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null [String]
pkgcfgs)]
  let extraTestDeps = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
testsuiteDeps [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String]
deps
  unless (null $ alldeps ++ extraTestDeps) $ do
    mapM_ (putHdr "BuildRequires") alldeps
    unless (null extraTestDeps) $ do
      put "%if %{with tests}"
      mapM_ (putHdr "BuildRequires") extraTestDeps
      put "%endif"

  putNewline

  put "%description"
  mapM_ put descLines

  let wrapGenDesc = CopyrightYear -> String -> String
wordwrap (CopyrightYear
79 CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
- CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Ord a => a -> a -> a
max CopyrightYear
0 (String -> CopyrightYear
forall a. [a] -> CopyrightYear
forall (t :: * -> *) a. Foldable t => t a -> CopyrightYear
length String
pkgname CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
- String -> CopyrightYear
forall a. [a] -> CopyrightYear
forall (t :: * -> *) a. Foldable t => t a -> CopyrightYear
length String
pkg_name))

  when hasLib $ do
    when binlib $ do
      put $ "%package" +-+ ghcPkg
      putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library"
      putNewline
      put $ "%description" +-+ ghcPkg
      put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "shared library."
    put $ "%package" +-+ ghcPkgDevel
    putHdr "Summary" $ "Haskell" +-+ pkg_name +-+ "library development files"
    putHdr "Requires" $ (if binlib then "ghc-%{name}" else "%{name}") +-+ "= %{version}-%{release}"
    putHdr "Requires" "ghc-compiler = %{ghc_version}"
    unless (null $ clibs ++ pkgcfgs) $
      mapM_ (putHdr "Requires") $ sort (clibs ++ pkgcfgs ++ ["pkgconfig" | not (null pkgcfgs)])
    putHdr "Requires(post)" "ghc-compiler = %{ghc_version}"
    putHdr "Requires(postun)" "ghc-compiler = %{ghc_version}"
    putNewline
    put $ "%description" +-+ ghcPkgDevel
    put $ wrapGenDesc $ "This package provides the Haskell" +-+ pkg_name +-+ "library development files."
    put $ unlines
        [ "%package -n ghc-%{pkg_name}-doc"
        , "Summary:        Haskell %{pkg_name} library documentation"
        , "BuildArch:      noarch"
        , "Requires:       ghc-filesystem"
        , ""
        , "%description -n ghc-%{pkg_name}-doc"
        , "This package provides the Haskell %{pkg_name} library documentation."
        , ""
        , ""
        , "%package -n ghc-%{pkg_name}-prof"
        , "Summary:        Haskell %{pkg_name} profiling library"
        , "Requires:       ghc-%{pkg_name}-devel = %{version}-%{release}"
        , "Supplements:    (ghc-%{pkg_name}-devel and ghc-prof)"
        , ""
        , "%description -n ghc-%{pkg_name}-prof"
        , "This package provides the Haskell %{pkg_name} profiling library."
        , ""
        ]

  put "%prep"
  put $ "%autosetup" ++ (if pkgname /= name then " -n %{pkg_name}-%{version}" else "")
  when (revision /= "0") $
    put $ "cp -p %{SOURCE1}" +-+ pkg_name ++ ".cabal"
  putNewline

  put "%build"
  when (flagAssignment /= mempty) $ do
    let cabalFlags = [ String
"-f" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (if ForceBinary
b then String
"" else String
"-") String -> String -> String
forall a. [a] -> [a] -> [a]
++ FlagName -> String
unFlagName FlagName
n | (FlagName
n, ForceBinary
b) <- FlagAssignment -> [(FlagName, ForceBinary)]
unFlagAssignment FlagAssignment
flagAssignment ]
    put $ "%define cabal_configure_options " ++ unwords (sort cabalFlags)
  let pkgType = if ForceBinary
hasLib then String
"lib" else String
"bin"
  put $ "%ghc_" ++ pkgType ++ "_build"
  putNewline

  put "%install"
  put $ "%ghc_" ++ pkgType ++ "_install"

  when selfdep $
    put $ "%ghc_fix_rpath" +-+ "%{pkg_name}-%{version}"

  -- TODO: getSymbolicPath should not be used like this
  let licensefiles = (SymbolicPath PackageDir LicenseFile -> String)
-> [SymbolicPath PackageDir LicenseFile] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map SymbolicPath PackageDir LicenseFile -> String
forall from to. SymbolicPath from to -> String
getSymbolicPath (PackageDescription -> [SymbolicPath PackageDir LicenseFile]
licenseFiles PackageDescription
pkgDesc)

  -- remove docs from datafiles (#38)
  docsUnfiltered <- fmap sort (findDocs (extraSrcFiles pkgDesc ++ extraDocFiles pkgDesc) licensefiles)
  let datafiles = PackageDescription -> [String]
dataFiles PackageDescription
pkgDesc
      dupdocs   = [String]
docsUnfiltered [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
`intersect` [String]
datafiles
      docs      = [String]
docsUnfiltered [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String]
datafiles
  unless (null dupdocs) $
    -- TODO: What does this warning accomplish?
    putStrLn $ "*** " ++ pkgname ++ ": doc files found in datadir:" +-+ unwords (sort dupdocs)
  putNewline

  unless (null testsuiteDeps) $ do
    put "%check"
    put "%cabal_test"
    putNewline

  when hasLib $ do
    let putInstallScript = do
          String -> IO ()
put String
"%ghc_pkg_recache"
          IO ()
putNewline
    put $ "%post" +-+ ghcPkgDevel
    putInstallScript
    put $ "%postun" +-+ ghcPkgDevel
    putInstallScript

  let license_macro = String
"%license"
  let execs :: [String]
      execs = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (Executable -> String) -> [Executable] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String)
-> (Executable -> UnqualComponentName) -> Executable -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Executable -> UnqualComponentName
exeName) ([Executable] -> [String]) -> [Executable] -> [String]
forall a b. (a -> b) -> a -> b
$ (Executable -> ForceBinary) -> [Executable] -> [Executable]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter Executable -> ForceBinary
isBuildable ([Executable] -> [Executable]) -> [Executable] -> [Executable]
forall a b. (a -> b) -> a -> b
$ PackageDescription -> [Executable]
executables PackageDescription
pkgDesc

  let listDataFiles = ForceBinary -> IO () -> IO ()
forall (f :: * -> *). Applicative f => ForceBinary -> f () -> f ()
unless ([String] -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null (PackageDescription -> [String]
dataFiles PackageDescription
pkgDesc)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                        String -> IO ()
put (String
"%dir %{_datadir}/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pkg_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-%{version}")
                        (String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (String -> IO ()
put (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String
"%dir %{_datadir}/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pkg_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-%{version}/")String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
avoidSquareBrackets) ([String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]
listDirs (PackageDescription -> [String]
dataFiles PackageDescription
pkgDesc)))
                        (String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (String -> IO ()
put (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String
"%{_datadir}/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pkg_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-%{version}/")String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
avoidSquareBrackets) ([String] -> [String]
forall a. Ord a => [a] -> [a]
sort (PackageDescription -> [String]
dataFiles PackageDescription
pkgDesc))

      listDirs :: [FilePath] -> [FilePath]
      listDirs = [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> [String]) -> [[String]] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> String
joinPath ([[String]] -> [String])
-> ([String] -> [[String]]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CopyrightYear -> [[String]] -> [[String]]
forall a. CopyrightYear -> [a] -> [a]
drop CopyrightYear
1 ([[String]] -> [[String]])
-> ([String] -> [[String]]) -> [String] -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [[String]]
forall a. [a] -> [[a]]
inits) ([[String]] -> [String])
-> ([String] -> [[String]]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[String]] -> [[String]]
forall a. Eq a => [a] -> [a]
nub ([[String]] -> [[String]])
-> ([String] -> [[String]]) -> [String] -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> [String]) -> [[String]] -> [[String]]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> [String]
forall a. HasCallStack => [a] -> [a]
init ([[String]] -> [[String]])
-> ([String] -> [[String]]) -> [String] -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> ForceBinary) -> [[String]] -> [[String]]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter (\[String]
p -> [String] -> CopyrightYear
forall a. [a] -> CopyrightYear
forall (t :: * -> *) a. Foldable t => t a -> CopyrightYear
length [String]
p CopyrightYear -> CopyrightYear -> ForceBinary
forall a. Ord a => a -> a -> ForceBinary
> CopyrightYear
1) ([[String]] -> [[String]])
-> ([String] -> [[String]]) -> [String] -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> [String]) -> [String] -> [[String]]
forall a b. (a -> b) -> [a] -> [b]
map String -> [String]
splitDirectories

  when hasExecPkg $ do
    put "%files"
    -- Add the license file to the main package only if it wouldn't
    -- otherwise be empty.
    mapM_ (\ String
l -> String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
license_macro String -> String -> String
+-+ String
l) (sort licensefiles)
    unless (null docs) $
      put $ "%doc" +-+ unwords (sort docs)
    mapM_ (\ String
p -> String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"%{_bindir}/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (if String
p String -> String -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== String
name then String
"%{name}" else String
p)) (sort execs)
    listDataFiles
    putNewline

  when hasLib $ do
    let baseFiles = if ForceBinary
binlib then String
"-f ghc-%{name}.files" else String
"-f %{name}.files"
        develFiles = if ForceBinary
binlib then String
"-f ghc-%{name}-devel.files" else String
"-f %{name}-devel.files"
    put $ "%files" +-+ ghcPkg +-+ baseFiles
    mapM_ (\ String
l -> String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
license_macro String -> String -> String
+-+ String
l) licensefiles
    unless binlib $
      mapM_ (\ String
p -> String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"%{_bindir}/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (if String
p String -> String -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== String
name then String
"%{pkg_name}" else String
p)) (sort execs)
    unless hasExecPkg listDataFiles
    putNewline
    put $ "%files" +-+ ghcPkgDevel +-+ develFiles
    unless (null docs) $
      put $ "%doc" +-+ unwords (sort docs)
    putNewline
    put "%files -n ghc-%{pkg_name}-doc -f ghc-%{pkg_name}-doc.files"
    mapM_ (\ String
l -> String -> IO ()
put (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
license_macro String -> String -> String
+-+ String
l) licensefiles
    putNewline
    put "%files -n ghc-%{pkg_name}-prof -f ghc-%{pkg_name}-prof.files"
    putNewline

  put "%changelog"
  hClose h


isBuildable :: Executable -> Bool
isBuildable :: Executable -> ForceBinary
isBuildable Executable
exe = BuildInfo -> ForceBinary
buildable (BuildInfo -> ForceBinary) -> BuildInfo -> ForceBinary
forall a b. (a -> b) -> a -> b
$ Executable -> BuildInfo
buildInfo Executable
exe

findDocs :: [FilePath] -> [FilePath] -> IO [FilePath]
findDocs :: [String] -> [String] -> IO [String]
findDocs [String]
contents [String]
licensefiles = do
  let docs :: [String]
docs = (String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter String -> ForceBinary
likely ([String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]
forall a. Eq a => [a] -> [a]
nub ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ([String] -> String
forall a. HasCallStack => [a] -> a
head ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitDirectories) [String]
contents)))
  [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ if [String] -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null [String]
licensefiles
           then [String]
docs
           else (String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter (String -> [String] -> ForceBinary
forall (t :: * -> *) a.
(Foldable t, Eq a) =>
a -> t a -> ForceBinary
`notElem` [String]
licensefiles) [String]
docs
  where names :: [String]
names = [String
"author", String
"changelog", String
"changes", String
"contributors", String
"copying", String
"doc",
                 String
"example", String
"licence", String
"license", String
"news", String
"readme", String
"todo"]
        likely :: String -> ForceBinary
likely String
name = let lowerName :: String
lowerName = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
name
                      in (String -> ForceBinary) -> [String] -> ForceBinary
forall (t :: * -> *) a.
Foldable t =>
(a -> ForceBinary) -> t a -> ForceBinary
any (String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` String
lowerName) [String]
names

normalizeVersion :: Version -> Version
normalizeVersion :: Version -> Version
normalizeVersion Version
v = case Version -> [CopyrightYear]
versionNumbers Version
v of
                       [CopyrightYear
i] -> [CopyrightYear] -> Version
mkVersion [CopyrightYear
i,CopyrightYear
0]
                       [CopyrightYear]
_   -> Version
v

showLicense :: License -> String
showLicense :: License -> String
showLicense (GPL Maybe Version
Nothing) = String
"GPL-1.0-or-later"
showLicense (GPL (Just Version
ver)) = String
"GPL-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
display (Version -> Version
normalizeVersion Version
ver) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-or-later"
showLicense (LGPL Maybe Version
Nothing) = String
"LGPL-2.0-or-later"
showLicense (LGPL (Just Version
ver)) = String
"LGPL-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
display (Version -> Version
normalizeVersion Version
ver) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-or-later"
showLicense License
BSD3 = String
"BSD-3-Clause"
showLicense License
BSD4 = String
"BSD-4-Clause"
showLicense License
MIT = String
"MIT"
showLicense License
PublicDomain = String
"SUSE-Public-Domain"
showLicense License
AllRightsReserved = String
"SUSE-NonFree"
showLicense License
OtherLicense = String
"Unknown"
showLicense (UnknownLicense String
l) = String
"Unknown" String -> String -> String
+-+ String
l
showLicense (Apache Maybe Version
Nothing) = String
"Apache-2.0"
showLicense (Apache (Just Version
ver)) = String
"Apache-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
display (Version -> Version
normalizeVersion Version
ver)
showLicense (AGPL Maybe Version
Nothing) = String
"AGPL-1.0-or-later"
showLicense (AGPL (Just Version
ver)) = String
"AGPL-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
display (Version -> Version
normalizeVersion Version
ver) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-or-later"
showLicense License
BSD2 = String
"BSD-2-Clause"
showLicense (MPL Version
ver) = String
"MPL-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
display (Version -> Version
normalizeVersion Version
ver)
showLicense License
ISC = String
"ISC"
showLicense License
UnspecifiedLicense = String
"Unspecified license!"

-- http://rosettacode.org/wiki/Word_wrap#Haskell
wordwrap :: Int -> String -> String
wordwrap :: CopyrightYear -> String -> String
wordwrap CopyrightYear
maxlen = CopyrightYear -> ForceBinary -> [String] -> String
wrap_ CopyrightYear
0 ForceBinary
False ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
words
  where
    wrap_ :: CopyrightYear -> ForceBinary -> [String] -> String
wrap_ CopyrightYear
_ ForceBinary
_ [] = String
"\n"
    wrap_ CopyrightYear
pos ForceBinary
eos (String
w:[String]
ws)
      -- at line start: put down the word no matter what
      | CopyrightYear
pos CopyrightYear -> CopyrightYear -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== CopyrightYear
0 = String
w String -> String -> String
forall a. [a] -> [a] -> [a]
++ CopyrightYear -> ForceBinary -> [String] -> String
wrap_ (CopyrightYear
pos CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
lw) ForceBinary
endp [String]
ws
      | CopyrightYear
pos CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
lw CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
1 CopyrightYear -> CopyrightYear -> ForceBinary
forall a. Ord a => a -> a -> ForceBinary
> CopyrightYear
maxlen CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
- CopyrightYear
9 ForceBinary -> ForceBinary -> ForceBinary
&& ForceBinary
eos = Char
'\n'Char -> String -> String
forall a. a -> [a] -> [a]
:CopyrightYear -> ForceBinary -> [String] -> String
wrap_ CopyrightYear
0 ForceBinary
endp (String
wString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
ws)
      | CopyrightYear
pos CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
lw CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
1 CopyrightYear -> CopyrightYear -> ForceBinary
forall a. Ord a => a -> a -> ForceBinary
> CopyrightYear
maxlen = Char
'\n'Char -> String -> String
forall a. a -> [a] -> [a]
:CopyrightYear -> ForceBinary -> [String] -> String
wrap_ CopyrightYear
0 ForceBinary
endp (String
wString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
ws)
      | ForceBinary
otherwise = String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
w String -> String -> String
forall a. [a] -> [a] -> [a]
++ CopyrightYear -> ForceBinary -> [String] -> String
wrap_ (CopyrightYear
pos CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
lw CopyrightYear -> CopyrightYear -> CopyrightYear
forall a. Num a => a -> a -> a
+ CopyrightYear
1) ForceBinary
endp [String]
ws
      where
        lw :: CopyrightYear
lw = String -> CopyrightYear
forall a. [a] -> CopyrightYear
forall (t :: * -> *) a. Foldable t => t a -> CopyrightYear
length String
w
        endp :: ForceBinary
endp = String -> Char
forall a. HasCallStack => [a] -> a
last String
w Char -> Char -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== Char
'.'

formatParagraphs :: String -> [String]
formatParagraphs :: String -> [String]
formatParagraphs = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (CopyrightYear -> String -> String
wordwrap CopyrightYear
79) ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
paragraphs ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
  where
    -- from http://stackoverflow.com/questions/930675/functional-paragraphs
    -- using split would be: map unlines . (Data.List.Split.splitWhen null)
    paragraphs :: [String] -> [String]
    paragraphs :: [String] -> [String]
paragraphs = ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ([String] -> String
unlines ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter (ForceBinary -> ForceBinary
not (ForceBinary -> ForceBinary)
-> (String -> ForceBinary) -> String -> ForceBinary
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null)) ([[String]] -> [String])
-> ([String] -> [[String]]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String -> ForceBinary) -> [String] -> [[String]]
forall a. (a -> a -> ForceBinary) -> [a] -> [[a]]
groupBy ((String -> ForceBinary) -> String -> String -> ForceBinary
forall a b. a -> b -> a
const ((String -> ForceBinary) -> String -> String -> ForceBinary)
-> (String -> ForceBinary) -> String -> String -> ForceBinary
forall a b. (a -> b) -> a -> b
$ ForceBinary -> ForceBinary
not (ForceBinary -> ForceBinary)
-> (String -> ForceBinary) -> String -> ForceBinary
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null)

rstrip :: (Char -> Bool) -> String -> String
rstrip :: (Char -> ForceBinary) -> String -> String
rstrip Char -> ForceBinary
p = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> ForceBinary) -> String -> String
forall a. (a -> ForceBinary) -> [a] -> [a]
dropWhile Char -> ForceBinary
p (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
reverse

getPkgName :: Maybe FilePath -> PackageDescription -> Bool -> IO (String, Bool)
getPkgName :: Maybe String
-> PackageDescription -> ForceBinary -> IO (String, ForceBinary)
getPkgName (Just String
spec) PackageDescription
pkgDesc ForceBinary
binary = do
  let name :: String
name = PackageName -> String
unPackageName (PackageIdentifier -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName (PackageDescription -> PackageIdentifier
package PackageDescription
pkgDesc))
      pkgname :: String
pkgname = String -> String
takeBaseName String
spec
      hasLib :: ForceBinary
hasLib = PackageDescription -> ForceBinary
hasLibs PackageDescription
pkgDesc
  (String, ForceBinary) -> IO (String, ForceBinary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, ForceBinary) -> IO (String, ForceBinary))
-> (String, ForceBinary) -> IO (String, ForceBinary)
forall a b. (a -> b) -> a -> b
$ if String
name String -> String -> ForceBinary
forall a. Eq a => a -> a -> ForceBinary
== String
pkgname ForceBinary -> ForceBinary -> ForceBinary
|| ForceBinary
binary then (String
name, ForceBinary
hasLib) else (String
pkgname, ForceBinary
False)
getPkgName Maybe String
Nothing PackageDescription
pkgDesc ForceBinary
binary = do
  let name :: String
name = PackageName -> String
unPackageName (PackageIdentifier -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName (PackageDescription -> PackageIdentifier
package PackageDescription
pkgDesc))
      hasExec :: ForceBinary
hasExec = PackageDescription -> ForceBinary
hasExes PackageDescription
pkgDesc
      hasLib :: ForceBinary
hasLib = PackageDescription -> ForceBinary
hasLibs PackageDescription
pkgDesc
  (String, ForceBinary) -> IO (String, ForceBinary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, ForceBinary) -> IO (String, ForceBinary))
-> (String, ForceBinary) -> IO (String, ForceBinary)
forall a b. (a -> b) -> a -> b
$ if ForceBinary
binary ForceBinary -> ForceBinary -> ForceBinary
|| ForceBinary
hasExec ForceBinary -> ForceBinary -> ForceBinary
&& ForceBinary -> ForceBinary
not ForceBinary
hasLib then (String
name, ForceBinary
hasLib) else (String
"ghc-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name, ForceBinary
False)

infixr 4 +-+
(+-+) :: String -> String -> String
String
"" +-+ :: String -> String -> String
+-+ String
s = String
s
String
s +-+ String
"" = String
s
String
s +-+ String
t = String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
t

excludedPkgs :: PackageDescription -> String -> Bool
excludedPkgs :: PackageDescription -> String -> ForceBinary
excludedPkgs PackageDescription
pkgDesc = (String -> [String] -> ForceBinary)
-> [String] -> String -> ForceBinary
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> [String] -> ForceBinary
forall (t :: * -> *) a.
(Foldable t, Eq a) =>
a -> t a -> ForceBinary
notElem ([String]
subLibs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"ghc-prim", String
"integer-gmp", String
"ghc-bignum"])
  where
    subLibs :: [String]
    subLibs :: [String]
subLibs = [ UnqualComponentName -> String
unUnqualComponentName UnqualComponentName
ln | Library
l <- PackageDescription -> [Library]
subLibraries PackageDescription
pkgDesc, LSubLibName UnqualComponentName
ln <- [Library -> LibraryName
libName Library
l] ]

-- returns list of deps and whether package is self-dependent
buildDependencies :: PackageDescription -> String -> ([String], Bool)
buildDependencies :: PackageDescription -> String -> ([String], ForceBinary)
buildDependencies PackageDescription
pkgDesc String
self =
  let bis :: [BuildInfo]
bis   = (Library -> BuildInfo) -> [Library] -> [BuildInfo]
forall a b. (a -> b) -> [a] -> [b]
map Library -> BuildInfo
libBuildInfo (PackageDescription -> [Library]
allLibraries PackageDescription
pkgDesc) [BuildInfo] -> [BuildInfo] -> [BuildInfo]
forall a. [a] -> [a] -> [a]
++ (Executable -> BuildInfo) -> [Executable] -> [BuildInfo]
forall a b. (a -> b) -> [a] -> [b]
map Executable -> BuildInfo
buildInfo (PackageDescription -> [Executable]
executables PackageDescription
pkgDesc)
      bdeps :: [String]
bdeps = (Dependency -> String) -> [Dependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Dependency -> String
forall a. IsDependency a => a -> String
depName ((BuildInfo -> [Dependency]) -> [BuildInfo] -> [Dependency]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [Dependency]
targetBuildDepends ((BuildInfo -> ForceBinary) -> [BuildInfo] -> [BuildInfo]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter BuildInfo -> ForceBinary
buildable [BuildInfo]
bis))
      sdeps :: [String]
sdeps = [String]
-> (SetupBuildInfo -> [String]) -> Maybe SetupBuildInfo -> [String]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ((Dependency -> String) -> [Dependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Dependency -> String
forall a. IsDependency a => a -> String
depName ([Dependency] -> [String])
-> (SetupBuildInfo -> [Dependency]) -> SetupBuildInfo -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SetupBuildInfo -> [Dependency]
setupDepends) (PackageDescription -> Maybe SetupBuildInfo
setupBuildInfo PackageDescription
pkgDesc)
      deps :: [String]
deps  = [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
bdeps [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
sdeps
  in
    ((String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter (PackageDescription -> String -> ForceBinary
excludedPkgs PackageDescription
pkgDesc) (String -> [String] -> [String]
forall a. Eq a => a -> [a] -> [a]
delete String
self [String]
deps), String
self String -> [String] -> ForceBinary
forall a. Eq a => a -> [a] -> ForceBinary
forall (t :: * -> *) a.
(Foldable t, Eq a) =>
a -> t a -> ForceBinary
`elem` [String]
deps ForceBinary -> ForceBinary -> ForceBinary
&& PackageDescription -> ForceBinary
hasExes PackageDescription
pkgDesc)

class IsDependency a where
  depName :: a -> String

instance IsDependency Dependency where
  depName :: Dependency -> String
depName (Dependency PackageName
n VersionRange
_ NonEmptySet LibraryName
_) = PackageName -> String
unPackageName PackageName
n

instance IsDependency PkgconfigDependency where
  depName :: PkgconfigDependency -> String
depName (PkgconfigDependency PkgconfigName
n PkgconfigVersionRange
_) = PkgconfigName -> String
unPkgconfigName PkgconfigName
n

instance IsDependency LegacyExeDependency where
  depName :: LegacyExeDependency -> String
depName (LegacyExeDependency String
n VersionRange
_) = String
n

showDevelDep :: String -> String
showDevelDep :: String -> String
showDevelDep String
p = String
"ghc-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
p String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-devel"

showProfDep :: String -> String
showProfDep :: String -> String
showProfDep String
p = String
"ghc-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
p String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-prof"

resolveLib :: String -> String
resolveLib :: String -> String
resolveLib String
"alut" = String
"freealut-devel"
resolveLib String
"asound" = String
"alsa-devel"
resolveLib String
"blas" = String
"blas-devel"
resolveLib String
"bluetooth" = String
"bluez-devel"
resolveLib String
"clang" = String
"clang-devel"
resolveLib String
"crypt" = String
"glibc-devel"
resolveLib String
"crypto" = String
"libopenssl-devel"
resolveLib String
"fftw3" = String
"fftw3-devel"
resolveLib String
"FLAC" = String
"flac-devel"
resolveLib String
"fontconfig" = String
"fontconfig-devel"
resolveLib String
"freetype" = String
"freetype2-devel"
resolveLib String
"gd" = String
"gd-devel"
resolveLib String
"GL" = String
"Mesa-libGL-devel"
resolveLib String
"glib-2.0" = String
"glib2-devel"
resolveLib String
"GLU" = String
"glu-devel"
resolveLib String
"gmp" = String
"gmp-devel"
resolveLib String
"gsl" = String
"gsl-devel"
resolveLib String
"icudata" = String
"libicu-devel"
resolveLib String
"icui18n" = String
"libicu-devel"
resolveLib String
"icuuc" = String
"libicu-devel"
resolveLib String
"IL" = String
"DevIL-devel"
resolveLib String
"Imlib2" = String
"imlib2-devel"
resolveLib String
"lapack" = String
"lapack-devel"
resolveLib String
"leveldb" = String
"leveldb-devel"
resolveLib String
"lmdb" = String
"lmdb-devel"
resolveLib String
"lua" = String
"lua-devel"
resolveLib String
"luajit" = String
"luajit-devel"
resolveLib String
"lzma" = String
"xz-devel"
resolveLib String
"m" = String
"glibc-devel"
resolveLib String
"magic" = String
"file-devel"
resolveLib String
"mpfr" = String
"mpfr-devel"
resolveLib String
"odbc" = String
"unixODBC-devel"
resolveLib String
"openal" = String
"openal-soft-devel"
resolveLib String
"pcre" = String
"pcre-devel"
resolveLib String
"png" = String
"libpng16-compat-devel"
resolveLib String
"pq" = String
"postgresql-server-devel"
resolveLib String
"pthread" = String
"glibc-devel"
resolveLib String
"re2" = String
"re2-devel"
resolveLib String
"resolv" = String
"glibc-devel"
resolveLib String
"ruby" = String
"ruby-devel"
resolveLib String
"snappy" = String
"snappy-devel"
resolveLib String
"sqlite3" = String
"sqlite3-devel"
resolveLib String
"ssl" = String
"libopenssl-devel"
resolveLib String
"tag_c" = String
"libtag-devel"
resolveLib String
"z" = String
"zlib-devel"
resolveLib String
name | String
"lib" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` String
name = String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-devel"
                | ForceBinary
otherwise               = String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-devel"

testsuiteDependencies :: PackageDescription -- ^pkg description
                      -> String             -- ^self
                      -> [String]           -- ^depends
testsuiteDependencies :: PackageDescription -> String -> [String]
testsuiteDependencies PackageDescription
pkgDesc String
self = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
showDevelDep [String]
deps [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
showProfDep [String]
deps
  where deps :: [String]
deps = String -> [String] -> [String]
forall a. Eq a => a -> [a] -> [a]
delete String
self ([String] -> [String])
-> ([Dependency] -> [String]) -> [Dependency] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> ForceBinary) -> [String] -> [String]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter (PackageDescription -> String -> ForceBinary
excludedPkgs PackageDescription
pkgDesc) ([String] -> [String])
-> ([Dependency] -> [String]) -> [Dependency] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. Eq a => [a] -> [a]
nub ([String] -> [String])
-> ([Dependency] -> [String]) -> [Dependency] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Dependency -> String) -> [Dependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Dependency -> String
forall a. IsDependency a => a -> String
depName ([Dependency] -> [String]) -> [Dependency] -> [String]
forall a b. (a -> b) -> a -> b
$
                 (BuildInfo -> [Dependency]) -> [BuildInfo] -> [Dependency]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [Dependency]
targetBuildDepends ((BuildInfo -> ForceBinary) -> [BuildInfo] -> [BuildInfo]
forall a. (a -> ForceBinary) -> [a] -> [a]
filter BuildInfo -> ForceBinary
buildable ((TestSuite -> BuildInfo) -> [TestSuite] -> [BuildInfo]
forall a b. (a -> b) -> [a] -> [b]
map TestSuite -> BuildInfo
testBuildInfo (PackageDescription -> [TestSuite]
testSuites PackageDescription
pkgDesc)))

badDescription :: String -> Bool
badDescription :: String -> ForceBinary
badDescription String
s = String -> ForceBinary
forall a. [a] -> ForceBinary
forall (t :: * -> *) a. Foldable t => t a -> ForceBinary
null String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"please see readme" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"please see the readme" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"see readme" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"cf readme" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"please refer to readme" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s
                ForceBinary -> ForceBinary -> ForceBinary
|| String
"initial project template" String -> String -> ForceBinary
forall a. Eq a => [a] -> [a] -> ForceBinary
`isPrefixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
s

-- | @pandoc-2.2.1@ installs a file with square brackets in its name, and that
-- confuses RPM because it thinks those are shell specials.
--
-- TODO: Figure out how this code is supposed to interact with legitimate shell
-- globs, like '*'.

avoidSquareBrackets :: String -> String
avoidSquareBrackets :: String -> String
avoidSquareBrackets []     = []
avoidSquareBrackets (Char
x:String
xs)
  | Char
x Char -> String -> ForceBinary
forall a. Eq a => a -> [a] -> ForceBinary
forall (t :: * -> *) a.
(Foldable t, Eq a) =>
a -> t a -> ForceBinary
`elem` String
"[]"       = Char
'?' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
avoidSquareBrackets String
xs
  | ForceBinary
otherwise           = Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
avoidSquareBrackets String
xs