{-# 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
#if !MIN_VERSION_extra(1,6,4)
import Data.Maybe (fromMaybe)
#endif
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.RPM.NVR
import Data.RPM.VerRel
import System.FilePath (takeFileName)

-- | 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 String
n VerRel
vr String
a) = String
n String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"-" 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 -> String
forall a. Semigroup a => a -> a -> a
<> String
a

-- | Either read a name-version-release.arch or return a failure string
--
-- Strips off ".rpm" extension and any directory path prefix.
eitherNVRA :: String -> Either String NVRA
eitherNVRA :: String -> Either String NVRA
eitherNVRA String
"" = String -> Either String NVRA
forall a b. a -> Either a b
Left String
"NVRA string cannot be empty"
eitherNVRA s :: String
s@(Char
'-':String
_) = 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
$ String
"NVRA cannot start with '-': " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
eitherNVRA String
s =
  let nvra :: String
nvra = String -> String -> String
forall a. Eq a => [a] -> [a] -> [a]
dropSuffix String
".rpm" (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
takeFileName String
s
  in
    case [String] -> [String]
forall a. [a] -> [a]
reverse (String -> String -> [String]
forall a. (Partial, Eq a) => [a] -> [a] -> [[a]]
splitOn String
"-" String
nvra) of
      String
relarch:String
ver:[String]
emaN ->
        if String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
relarch Bool -> Bool -> Bool
|| String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
ver Bool -> Bool -> Bool
|| [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
emaN
        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
$ String
"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
"." String
relarch of
            (String
"",String
_) -> 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
$ String
"No arch suffix for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
            (String
_,String
"") -> 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
$ String
"Package release should not end in '.' " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s
            (String
reldot,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] -> 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 Int
1 String
reldot)) String
arch
      [String]
_ -> 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
$ String
"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 NVRA
p = NVRA -> String
rpmName NVRA
p String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> NVRA -> String
rpmArch NVRA
p

#if !MIN_VERSION_extra(1,6,4)
dropSuffix :: Eq a => [a] -> [a] -> [a]
dropSuffix a b = fromMaybe b $ stripSuffix a b
#endif