{-# LANGUAGE CPP #-}

-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 2 of the License, or
-- (at your option) any later version.

-- | A type for a (binary) RPM package.
module Data.RPM.NVRA (
  NVRA(..),
  readNVRA,
  eitherNVRA,
  maybeNVRA,
  showNVRA,
  showPkgIdent,
  showPkgVerRel,
  )
where

import Data.Either.Extra
import Data.List.Extra
import Data.Maybe
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.RPM.NVR
import Data.RPM.VerRel

-- | RPM package with name, version-release, and architecture
--
-- If arch is not needed use NVR instead.
--
-- FIXME: add epoch field
data NVRA = NVRA {NVRA -> String
rpmName :: String,
                  NVRA -> VerRel
rpmVerRel :: VerRel,
                  NVRA -> String
rpmArch :: String}
  deriving (NVRA -> NVRA -> Bool
(NVRA -> NVRA -> Bool) -> (NVRA -> NVRA -> Bool) -> Eq NVRA
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NVRA -> NVRA -> Bool
$c/= :: NVRA -> NVRA -> Bool
== :: NVRA -> NVRA -> Bool
$c== :: NVRA -> NVRA -> Bool
Eq, Eq NVRA
Eq NVRA =>
(NVRA -> NVRA -> Ordering)
-> (NVRA -> NVRA -> Bool)
-> (NVRA -> NVRA -> Bool)
-> (NVRA -> NVRA -> Bool)
-> (NVRA -> NVRA -> Bool)
-> (NVRA -> NVRA -> NVRA)
-> (NVRA -> NVRA -> NVRA)
-> Ord NVRA
NVRA -> NVRA -> Bool
NVRA -> NVRA -> Ordering
NVRA -> NVRA -> NVRA
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: NVRA -> NVRA -> NVRA
$cmin :: NVRA -> NVRA -> NVRA
max :: NVRA -> NVRA -> NVRA
$cmax :: NVRA -> NVRA -> NVRA
>= :: NVRA -> NVRA -> Bool
$c>= :: NVRA -> NVRA -> Bool
> :: NVRA -> NVRA -> Bool
$c> :: NVRA -> NVRA -> Bool
<= :: NVRA -> NVRA -> Bool
$c<= :: NVRA -> NVRA -> Bool
< :: NVRA -> NVRA -> Bool
$c< :: NVRA -> NVRA -> Bool
compare :: NVRA -> NVRA -> Ordering
$ccompare :: NVRA -> NVRA -> Ordering
$cp1Ord :: Eq NVRA
Ord)

-- | Render an RpmPackage
showNVRA :: NVRA -> String
showNVRA :: NVRA -> String
showNVRA (NVRA n :: String
n vr :: VerRel
vr a :: String
a) = String
n String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "-" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> VerRel -> String
showVerRel VerRel
vr String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
a

-- | Either read a name-version-release.arch or return a failure string
eitherNVRA :: String -> Either String NVRA
eitherNVRA :: String -> Either String NVRA
eitherNVRA "" = String -> Either String NVRA
forall a b. a -> Either a b
Left "NVRA string cannot be empty"
eitherNVRA s :: String
s@('-':_) = String -> Either String NVRA
forall a b. a -> Either a b
Left (String -> Either String NVRA) -> String -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ "NVRA cannot start with '-': " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
eitherNVRA s :: String
s =
  let nvra :: String
nvra = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
s (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripSuffix ".rpm" String
s
  in
    case [String] -> [String]
forall a. [a] -> [a]
reverse (String -> String -> [String]
forall a. (Partial, Eq a) => [a] -> [a] -> [[a]]
splitOn "-" String
nvra) of
      ps :: [String]
ps@(relarch :: String
relarch:ver :: String
ver:emaN :: [String]
emaN) ->
        if (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
ps
        then String -> Either String NVRA
forall a b. a -> Either a b
Left (String -> Either String NVRA) -> String -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ "Bad NVRA string: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
        else
          case String -> String -> (String, String)
forall a. Eq a => [a] -> [a] -> ([a], [a])
breakOnEnd "." String
relarch of
            ("",_) -> String -> Either String NVRA
forall a b. a -> Either a b
Left (String -> Either String NVRA) -> String -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ "No arch suffix for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
            (_,"") -> String -> Either String NVRA
forall a b. a -> Either a b
Left (String -> Either String NVRA) -> String -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ "Package release should not end in '.' " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
            (reldot :: String
reldot,arch :: String
arch) ->
              NVRA -> Either String NVRA
forall a b. b -> Either a b
Right (NVRA -> Either String NVRA) -> NVRA -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ String -> VerRel -> String -> NVRA
NVRA (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "-" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. [a] -> [a]
reverse [String]
emaN) (String -> String -> VerRel
VerRel String
ver (Int -> String -> String
forall a. Int -> [a] -> [a]
dropEnd 1 String
reldot)) String
arch
      _ -> String -> Either String NVRA
forall a b. a -> Either a b
Left (String -> Either String NVRA) -> String -> Either String NVRA
forall a b. (a -> b) -> a -> b
$ "NVRA string must have form 'name-version-release.arch': " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s

-- | Maybe read an NVRA
maybeNVRA :: String -> Maybe NVRA
maybeNVRA :: String -> Maybe NVRA
maybeNVRA = Either String NVRA -> Maybe NVRA
forall a b. Either a b -> Maybe b
eitherToMaybe (Either String NVRA -> Maybe NVRA)
-> (String -> Either String NVRA) -> String -> Maybe NVRA
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String NVRA
eitherNVRA

-- | Parse an NVRA with arch suffix
--
-- Errors if not of the form "name-version-release[.arch]"
readNVRA :: String -> NVRA
readNVRA :: String -> NVRA
readNVRA = (String -> NVRA) -> (NVRA -> NVRA) -> Either String NVRA -> NVRA
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> NVRA
forall a. Partial => String -> a
error NVRA -> NVRA
forall a. a -> a
id (Either String NVRA -> NVRA)
-> (String -> Either String NVRA) -> String -> NVRA
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String NVRA
eitherNVRA

-- | Render the version-release of an NVRA
showPkgVerRel :: NVRA -> String
showPkgVerRel :: NVRA -> String
showPkgVerRel = VerRel -> String
showVerRel (VerRel -> String) -> (NVRA -> VerRel) -> NVRA -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NVRA -> VerRel
rpmVerRel

-- | Identifier for an RPM package identified by name and arch
showPkgIdent :: NVRA -> String
showPkgIdent :: NVRA -> String
showPkgIdent p :: NVRA
p = NVRA -> String
rpmName NVRA
p String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> NVRA -> String
rpmArch NVRA
p