{-|
Module      : Portage.EBuild
License     : GPL-3+
Maintainer  : haskell@gentoo.org

Functions and types related to interpreting and manipulating an ebuild,
as understood by the Portage package manager.
-}
{-# LANGUAGE CPP #-}
module Portage.EBuild
        ( EBuild(..)
        , ebuildTemplate
        , showEBuild
        , src_uri
        -- hspec exports
        , sort_iuse
        , drop_tdot
        , quote
        , toHttps
        ) where

import           Portage.Dependency
import           Portage.EBuild.CabalFeature
import           Portage.EBuild.Render
import qualified Portage.Dependency.Normalize as PN

import qualified Data.Time.Clock as TC
import qualified Data.Time.Format as TC
import qualified Data.Function as F
import qualified Data.List as L
import qualified Data.List.Split as LS
import           Data.Version(Version(..))

import           Network.URI
import qualified Paths_hackport(version)

#if ! MIN_VERSION_time(1,5,0)
import qualified System.Locale as TC
#endif

-- | Type representing the information contained in an @.ebuild@.
data EBuild = EBuild {
    EBuild -> String
name :: String,
    EBuild -> String
category :: String,
    EBuild -> String
hackage_name :: String, -- might differ a bit (we mangle case)
    EBuild -> String
version :: String,
    EBuild -> String
hackportVersion :: String,
    EBuild -> String
description :: String,
    EBuild -> String
homepage :: String,
    EBuild -> Either String String
license :: Either String String,
    EBuild -> String
slot :: String,
    EBuild -> [String]
keywords :: [String],
    EBuild -> [String]
iuse :: [String],
    EBuild -> Dependency
depend :: Dependency,
    EBuild -> [String]
depend_extra :: [String],
    EBuild -> Dependency
rdepend :: Dependency,
    EBuild -> [String]
rdepend_extra :: [String]
    , EBuild -> [CabalFeature]
features :: [CabalFeature]
    , EBuild -> Maybe String
my_pn :: Maybe String -- ^ Just 'myOldName' if the package name contains upper characters
    , EBuild -> [String]
src_prepare :: [String] -- ^ raw block for src_prepare() contents
    , EBuild -> [String]
src_configure :: [String] -- ^ raw block for src_configure() contents
    , EBuild -> [(String, String)]
used_options :: [(String, String)] -- ^ hints to ebuild writers/readers
                                         --   on what hackport options were used to produce an ebuild
  }

getHackportVersion :: Version -> String
getHackportVersion :: Version -> String
getHackportVersion Version {versionBranch :: Version -> [Int]
versionBranch=(Int
x:[Int]
s)} = (String -> Int -> String) -> String -> [Int] -> String
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\String
y Int
z -> String
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show Int
z)) (Int -> String
forall a. Show a => a -> String
show Int
x) [Int]
s
getHackportVersion Version {versionBranch :: Version -> [Int]
versionBranch=[]} = String
""

-- | Generate a minimal 'EBuild' template.
ebuildTemplate :: EBuild
ebuildTemplate :: EBuild
ebuildTemplate = EBuild :: String
-> String
-> String
-> String
-> String
-> String
-> String
-> Either String String
-> String
-> [String]
-> [String]
-> Dependency
-> [String]
-> Dependency
-> [String]
-> [CabalFeature]
-> Maybe String
-> [String]
-> [String]
-> [(String, String)]
-> EBuild
EBuild {
    name :: String
name = String
"foobar",
    category :: String
category = String
"dev-haskell",
    hackage_name :: String
hackage_name = String
"FooBar",
    version :: String
version = String
"0.1",
    hackportVersion :: String
hackportVersion = Version -> String
getHackportVersion Version
Paths_hackport.version,
    description :: String
description = String
"",
    homepage :: String
homepage = String
"https://hackage.haskell.org/package/${HACKAGE_N}",
    license :: Either String String
license = String -> Either String String
forall a b. a -> Either a b
Left String
"unassigned license?",
    slot :: String
slot = String
"0",
    keywords :: [String]
keywords = [String
"~amd64",String
"~x86"],
    iuse :: [String]
iuse = [],
    depend :: Dependency
depend = Dependency
empty_dependency,
    depend_extra :: [String]
depend_extra = [],
    rdepend :: Dependency
rdepend = Dependency
empty_dependency,
    rdepend_extra :: [String]
rdepend_extra = [],
    features :: [CabalFeature]
features = [],
    my_pn :: Maybe String
my_pn = Maybe String
forall a. Maybe a
Nothing
    , src_prepare :: [String]
src_prepare = []
    , src_configure :: [String]
src_configure = []
    , used_options :: [(String, String)]
used_options = []
  }

-- | Given an EBuild, give the URI to the tarball of the source code.
-- Assumes that the server is always hackage.haskell.org.
-- 
-- >>> src_uri ebuildTemplate
-- "https://hackage.haskell.org/package/${P}/${P}.tar.gz"
src_uri :: EBuild -> String
src_uri :: EBuild -> String
src_uri EBuild
e =
  case EBuild -> Maybe String
my_pn EBuild
e of
    -- use standard address given that the package name has no upper
    -- characters
    Maybe String
Nothing -> String
"https://hackage.haskell.org/package/${P}/${P}.tar.gz"
    -- use MY_X variables (defined in showEBuild) as we've renamed the
    -- package
    Just String
_  -> String
"https://hackage.haskell.org/package/${MY_P}/${MY_P}.tar.gz"

-- | Pretty-print an 'EBuild' as a 'String'.
showEBuild :: TC.UTCTime -> EBuild -> String
showEBuild :: UTCTime -> EBuild -> String
showEBuild UTCTime
now EBuild
ebuild =
  String -> String -> String
ss (String
"# Copyright 1999-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
this_year String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" Gentoo Authors")(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"# Distributed under the terms of the GNU General Public License v2"(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"EAPI=8"(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss (String
"# ebuild generated by hackport " String -> String -> String
forall a. [a] -> [a] -> [a]
++ EBuild -> String
hackportVersion EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  [String -> String] -> String -> String
sconcat (((String, String) -> String -> String)
-> [(String, String)] -> [String -> String]
forall a b. (a -> b) -> [a] -> [b]
map (\(String
k, String
v) -> String -> String -> String
ss String
"#hackport: " (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
k (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
": " (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
v (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl) ([(String, String)] -> [String -> String])
-> [(String, String)] -> [String -> String]
forall a b. (a -> b) -> a -> b
$ EBuild -> [(String, String)]
used_options EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"CABAL_FEATURES="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> String -> String
quote' (String -> [String] -> String -> String
sepBy String
" " ([String] -> String -> String) -> [String] -> String -> String
forall a b. (a -> b) -> a -> b
$ (CabalFeature -> String) -> [CabalFeature] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map CabalFeature -> String
forall a. Render a => a -> String
render (EBuild -> [CabalFeature]
features EBuild
ebuild))(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"inherit haskell-cabal"(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (case EBuild -> Maybe String
my_pn EBuild
ebuild of
     Maybe String
Nothing -> String -> String
forall a. a -> a
id
     Just String
pn -> String -> String -> String
ss String
"MY_PN="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote String
pn(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                String -> String -> String
ss String
"MY_P="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote String
"${MY_PN}-${PV}"(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                String -> String -> String
ss String
"S="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote (String
"${WORKDIR}/${MY_P}")(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"DESCRIPTION="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote (String -> String
drop_tdot (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ EBuild -> String
description EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"HOMEPAGE="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote (String -> String
toHttps (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
expandVars (EBuild -> String
homepage EBuild
ebuild))(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"SRC_URI="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote (EBuild -> String
src_uri EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"LICENSE="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String -> String -> String)
-> (String -> String -> String)
-> Either String String
-> String
-> String
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\String
err -> String -> String -> String
quote String
"" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss (String
"\t# FIXME: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
err))
                         String -> String -> String
quote
                         (EBuild -> Either String String
license EBuild
ebuild))(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"SLOT="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
quote (EBuild -> String
slot EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> String -> String
ss String
"KEYWORDS="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> String -> String
quote' (String -> [String] -> String -> String
sepBy String
" " ([String] -> String -> String) -> [String] -> String -> String
forall a b. (a -> b) -> a -> b
$ EBuild -> [String]
keywords EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (if [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (EBuild -> [String]
iuse EBuild
ebuild)
    then String -> String
nl
    else String -> String -> String
ss String
"IUSE="(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> String -> String
quote' (String -> [String] -> String -> String
sepBy String
" " ([String] -> String -> String)
-> ([String] -> [String]) -> [String] -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
sort_iuse ([String] -> String -> String) -> [String] -> String -> String
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. Eq a => [a] -> [a]
L.nub ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ EBuild -> [String]
iuse EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl
    ) (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> [String] -> Dependency -> String -> String
dep_str String
"RDEPEND" (EBuild -> [String]
rdepend_extra EBuild
ebuild) (EBuild -> Dependency
rdepend EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  String -> [String] -> Dependency -> String -> String
dep_str String
"DEPEND"  ( EBuild -> [String]
depend_extra EBuild
ebuild) ( EBuild -> Dependency
depend EBuild
ebuild)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.

  (String -> String)
-> [String] -> (String -> String) -> String -> String
verbatim (String -> String
nl (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
"src_prepare() {" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl)
               (EBuild -> [String]
src_prepare EBuild
ebuild)
           (String -> String -> String
ss String
"}" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.

  (String -> String)
-> [String] -> (String -> String) -> String -> String
verbatim (String -> String
nl(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
"src_configure() {" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl)
               (EBuild -> [String]
src_configure EBuild
ebuild)
           (String -> String -> String
ss String
"}" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.

  String -> String
forall a. a -> a
id (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ []
  where
        expandVars :: String -> String
expandVars = [(String, String)] -> String -> String
replaceMultiVars [ (        EBuild -> String
name EBuild
ebuild, String
"${PN}")
                                      , (EBuild -> String
hackage_name EBuild
ebuild, String
"${HACKAGE_N}")
                                      ]


        this_year :: String
        this_year :: String
this_year = TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
TC.formatTime TimeLocale
TC.defaultTimeLocale String
"%Y" UTCTime
now

-- | Convert http urls into https urls, unless whitelisted as http-only.
--
-- >>> toHttps "http://darcs.net"
-- "http://darcs.net"
-- >>> toHttps "http://pandoc.org"
-- "https://pandoc.org"
-- >>> toHttps "https://github.com"
-- "https://github.com"
toHttps :: String -> String
toHttps :: String -> String
toHttps String
x =
  case String -> Maybe URI
parseURI String
x of
    Just URI
uri -> if URI -> String
uriScheme URI
uri String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"http:" Bool -> Bool -> Bool
&&
                   (URIAuth -> String
uriRegName (URIAuth -> String) -> Maybe URIAuth -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> URI -> Maybe URIAuth
uriAuthority URI
uri)
                   Maybe String -> [Maybe String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem`
                   [Maybe String]
httpOnlyHomepages
                then String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"http" String
"https" String
x
                else String
x
    Maybe URI
Nothing -> String
x
  where
    replace :: [a] -> [a] -> [a] -> [a]
replace [a]
old [a]
new = [a] -> [[a]] -> [a]
forall a. [a] -> [[a]] -> [a]
L.intercalate [a]
new ([[a]] -> [a]) -> ([a] -> [[a]]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a] -> [[a]]
forall a. Eq a => [a] -> [a] -> [[a]]
LS.splitOn [a]
old
    -- add to this list with any non https-aware websites
    httpOnlyHomepages :: [Maybe String]
httpOnlyHomepages = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> [String] -> [Maybe String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ String
"leksah.org"
                                 , String
"darcs.net"
                                 , String
"khumba.net"
                                 ]

-- | Sort IUSE alphabetically
--
-- >>> sort_iuse ["+a","b"]
-- ["+a","b"]
sort_iuse :: [String] -> [String]
sort_iuse :: [String] -> [String]
sort_iuse = (String -> String -> Ordering) -> [String] -> [String]
forall a. (a -> a -> Ordering) -> [a] -> [a]
L.sortBy (String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (String -> String -> Ordering)
-> (String -> String) -> String -> String -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`F.on` (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile ( Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"+"))

-- | Drop trailing dot(s).
--
-- >>> drop_tdot "foo."
-- "foo"
-- >>> drop_tdot "foo..."
-- "foo"
drop_tdot :: String -> String
drop_tdot :: String -> String
drop_tdot = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.') (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
reverse

type DString = String -> String

ss :: String -> DString
ss :: String -> String -> String
ss = String -> String -> String
showString

sc :: Char -> DString
sc :: Char -> String -> String
sc = Char -> String -> String
showChar

nl :: DString
nl :: String -> String
nl = Char -> String -> String
sc Char
'\n'

verbatim :: DString -> [String] -> DString -> DString
verbatim :: (String -> String)
-> [String] -> (String -> String) -> String -> String
verbatim String -> String
pre [String]
s String -> String
post =
    if [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
s
        then String -> String
forall a. a -> a
id
        else String -> String
pre (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
            (((String -> String) -> String -> String -> String)
-> (String -> String) -> [String] -> String -> String
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\String -> String
acc String
v -> String -> String
acc (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
"\t" (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
v (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl) String -> String
forall a. a -> a
id [String]
s) (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
            String -> String
post

sconcat :: [DString] -> DString
sconcat :: [String -> String] -> String -> String
sconcat = ((String -> String) -> (String -> String) -> String -> String)
-> (String -> String) -> [String -> String] -> String -> String
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
L.foldl' (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) String -> String
forall a. a -> a
id

-- takes string and substitutes tabs to spaces
-- ebuild's convention is 4 spaces for one tab,
-- BUT! nested USE flags get moved too much to
-- right. Thus 8 :]
tab_size :: Int
tab_size :: Int
tab_size = Int
8

tabify_line :: String -> String
tabify_line :: String -> String
tabify_line String
l = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
need_tabs Char
'\t'  String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nonsp
    where (String
sp, String
nonsp)       = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' ') String
l
          (Int
full_tabs, Int
t) = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
sp Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
tab_size
          need_tabs :: Int
need_tabs = Int
full_tabs Int -> Int -> Int
forall a. Num a => a -> a -> a
+ if Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then Int
1 else Int
0

tabify :: String -> String
tabify :: String -> String
tabify = [String] -> String
unlines ([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
tabify_line ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

dep_str :: String -> [String] -> Dependency -> DString
dep_str :: String -> [String] -> Dependency -> String -> String
dep_str String
var [String]
extra Dependency
dep = String -> String -> String
ss String
var(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> String -> String
sc Char
'='(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> String -> String
quote' (String -> String -> String
ss (String -> String -> String) -> String -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
drop_leadings (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [String]
extra String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
deps_s)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
nl
    where indent :: Int
indent = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
tab_size
          deps_s :: String
deps_s = String -> String
tabify (Int -> Dependency -> String
dep2str Int
indent (Dependency -> String) -> Dependency -> String
forall a b. (a -> b) -> a -> b
$ Dependency -> Dependency
PN.normalize_depend Dependency
dep)
          drop_leadings :: String -> String
drop_leadings = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\t')

-- | Place a 'String' between quotes, and correctly handle special characters.
quote :: String -> DString
quote :: String -> String -> String
quote String
str = Char -> String -> String
sc Char
'"'(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss (String -> String
esc String
str)(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> String -> String
sc Char
'"'
  where
  esc :: String -> String
esc = (Char -> String) -> String -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Char -> String
esc'
  esc' :: Char -> String
esc' Char
c =
      case Char
c of
          Char
'\\' -> String
"\\\\"
          Char
'"'  -> String
"\\\""
          Char
'\n' -> String
" "
          Char
'`'  -> String
"'"
          Char
_    -> [Char
c]

quote' :: DString -> DString
quote' :: (String -> String) -> String -> String
quote' String -> String
str = Char -> String -> String
sc Char
'"'(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
str(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> String -> String
sc Char
'"'

sepBy :: String -> [String] -> ShowS
sepBy :: String -> [String] -> String -> String
sepBy String
_ []     = String -> String
forall a. a -> a
id
sepBy String
_ [String
x]    = String -> String -> String
ss String
x
sepBy String
s (String
x:[String]
xs) = String -> String -> String
ss String
x(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
ss String
s(String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String -> String
sepBy String
s [String]
xs

getRestIfPrefix :: String       -- ^ the prefix
                -> String       -- ^ the string
                -> Maybe String
getRestIfPrefix :: String -> String -> Maybe String
getRestIfPrefix (Char
p:String
ps) (Char
x:String
xs) = if Char
pChar -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
x then String -> String -> Maybe String
getRestIfPrefix String
ps String
xs else Maybe String
forall a. Maybe a
Nothing
getRestIfPrefix [] String
rest = String -> Maybe String
forall a. a -> Maybe a
Just String
rest
getRestIfPrefix String
_ [] = Maybe String
forall a. Maybe a
Nothing

subStr :: String                -- ^ the search string
       -> String                -- ^ the string to be searched
       -> Maybe (String,String) -- ^ Just (pre,post) if string is found
subStr :: String -> String -> Maybe (String, String)
subStr String
sstr String
str = case String -> String -> Maybe String
getRestIfPrefix String
sstr String
str of
    Maybe String
Nothing -> if String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
str then Maybe (String, String)
forall a. Maybe a
Nothing else case String -> String -> Maybe (String, String)
subStr String
sstr (String -> String
forall a. [a] -> [a]
tail String
str) of
        Maybe (String, String)
Nothing -> Maybe (String, String)
forall a. Maybe a
Nothing
        Just (String
pre,String
post) -> (String, String) -> Maybe (String, String)
forall a. a -> Maybe a
Just (String -> Char
forall a. [a] -> a
head String
strChar -> String -> String
forall a. a -> [a] -> [a]
:String
pre,String
post)
    Just String
rest -> (String, String) -> Maybe (String, String)
forall a. a -> Maybe a
Just ([],String
rest)

replaceMultiVars ::
    [(String,String)] -- ^ pairs of variable name and content
    -> String         -- ^ string to be searched
    -> String         -- ^ the result
replaceMultiVars :: [(String, String)] -> String -> String
replaceMultiVars [] String
str = String
str
replaceMultiVars whole :: [(String, String)]
whole@((String
pname,String
cont):[(String, String)]
rest) String
str = case String -> String -> Maybe (String, String)
subStr String
cont String
str of
    Maybe (String, String)
Nothing -> [(String, String)] -> String -> String
replaceMultiVars [(String, String)]
rest String
str
    Just (String
pre,String
post) -> ([(String, String)] -> String -> String
replaceMultiVars [(String, String)]
rest String
pre)String -> String -> String
forall a. [a] -> [a] -> [a]
++String
pnameString -> String -> String
forall a. [a] -> [a] -> [a]
++([(String, String)] -> String -> String
replaceMultiVars [(String, String)]
whole String
post)