{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-missing-signatures #-}
-- |Changelog and changes file support.
module Debian.Changes
    ( ChangesFile(..)
    , ChangedFileSpec(..)
    , changesFileName
    , ChangeLog(..)
    , ChangeLogEntry(..)
    , parseChangeLog
    , parseEntries -- was parseLog
    , parseEntry
    , parseChanges
    ) where

import Data.Either (partitionEithers)
import Data.List (intercalate, intersperse)
import Data.Monoid ((<>))
import Data.Text (Text, pack, unpack, strip)
import Debian.Arch (Arch, prettyArch)
import Debian.Codename (Codename, codename, parseCodename)
import qualified Debian.Control.String as S
import Debian.Pretty (PP(..))
import Debian.Release
import Debian.Version
import System.Posix.Types
import Text.Regex.TDFA hiding (empty)
import Text.PrettyPrint (Doc, text, hcat, render)
import Distribution.Pretty (Pretty(pretty))

-- |A file generated by dpkg-buildpackage describing the result of a
-- package build
data ChangesFile =
    Changes { ChangesFile -> [Char]
changeDir :: FilePath             -- ^ The full pathname of the directory holding the .changes file.
            , ChangesFile -> [Char]
changePackage :: String           -- ^ The package name parsed from the .changes file name
            , ChangesFile -> DebianVersion
changeVersion :: DebianVersion    -- ^ The version number parsed from the .changes file name
            , ChangesFile -> Codename
changeRelease :: Codename         -- ^ The Distribution field of the .changes file
            , ChangesFile -> Arch
changeArch :: Arch                -- ^ The architecture parsed from the .changes file name
            , ChangesFile -> Paragraph' Text
changeInfo :: S.Paragraph' Text   -- ^ The contents of the .changes file
            , ChangesFile -> ChangeLogEntry
changeEntry :: ChangeLogEntry     -- ^ The value of the Changes field of the .changes file
            , ChangesFile -> [ChangedFileSpec]
changeFiles :: [ChangedFileSpec]  -- ^ The parsed value of the Files attribute
            } deriving (ChangesFile -> ChangesFile -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChangesFile -> ChangesFile -> Bool
$c/= :: ChangesFile -> ChangesFile -> Bool
== :: ChangesFile -> ChangesFile -> Bool
$c== :: ChangesFile -> ChangesFile -> Bool
Eq, ReadPrec [ChangesFile]
ReadPrec ChangesFile
Int -> ReadS ChangesFile
ReadS [ChangesFile]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ChangesFile]
$creadListPrec :: ReadPrec [ChangesFile]
readPrec :: ReadPrec ChangesFile
$creadPrec :: ReadPrec ChangesFile
readList :: ReadS [ChangesFile]
$creadList :: ReadS [ChangesFile]
readsPrec :: Int -> ReadS ChangesFile
$creadsPrec :: Int -> ReadS ChangesFile
Read, Int -> ChangesFile -> ShowS
[ChangesFile] -> ShowS
ChangesFile -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [ChangesFile] -> ShowS
$cshowList :: [ChangesFile] -> ShowS
show :: ChangesFile -> [Char]
$cshow :: ChangesFile -> [Char]
showsPrec :: Int -> ChangesFile -> ShowS
$cshowsPrec :: Int -> ChangesFile -> ShowS
Show)

-- |An entry in the list of files generated by the build.
data ChangedFileSpec =
    ChangedFileSpec { ChangedFileSpec -> [Char]
changedFileMD5sum :: String
                    , ChangedFileSpec -> [Char]
changedFileSHA1sum :: String
                    , ChangedFileSpec -> [Char]
changedFileSHA256sum :: String
                    , ChangedFileSpec -> FileOffset
changedFileSize :: FileOffset
                    , ChangedFileSpec -> SubSection
changedFileSection :: SubSection
                    , ChangedFileSpec -> [Char]
changedFilePriority :: String
                    , ChangedFileSpec -> [Char]
changedFileName :: FilePath
                    } deriving (ChangedFileSpec -> ChangedFileSpec -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChangedFileSpec -> ChangedFileSpec -> Bool
$c/= :: ChangedFileSpec -> ChangedFileSpec -> Bool
== :: ChangedFileSpec -> ChangedFileSpec -> Bool
$c== :: ChangedFileSpec -> ChangedFileSpec -> Bool
Eq, ReadPrec [ChangedFileSpec]
ReadPrec ChangedFileSpec
Int -> ReadS ChangedFileSpec
ReadS [ChangedFileSpec]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ChangedFileSpec]
$creadListPrec :: ReadPrec [ChangedFileSpec]
readPrec :: ReadPrec ChangedFileSpec
$creadPrec :: ReadPrec ChangedFileSpec
readList :: ReadS [ChangedFileSpec]
$creadList :: ReadS [ChangedFileSpec]
readsPrec :: Int -> ReadS ChangedFileSpec
$creadsPrec :: Int -> ReadS ChangedFileSpec
Read, Int -> ChangedFileSpec -> ShowS
[ChangedFileSpec] -> ShowS
ChangedFileSpec -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [ChangedFileSpec] -> ShowS
$cshowList :: [ChangedFileSpec] -> ShowS
show :: ChangedFileSpec -> [Char]
$cshow :: ChangedFileSpec -> [Char]
showsPrec :: Int -> ChangedFileSpec -> ShowS
$cshowsPrec :: Int -> ChangedFileSpec -> ShowS
Show)

-- |A changelog is a series of ChangeLogEntries
data ChangeLogEntry =
    Entry { ChangeLogEntry -> [Char]
logPackage :: String -- FIXME: Should be a SrcPkgName
          , ChangeLogEntry -> DebianVersion
logVersion :: DebianVersion
          , ChangeLogEntry -> [Codename]
logDists :: [Codename]
          , ChangeLogEntry -> [Char]
logUrgency :: String
          , ChangeLogEntry -> [Char]
logComments :: String
          , ChangeLogEntry -> [Char]
logWho :: String
          , ChangeLogEntry -> [Char]
logDate :: String
          }
  | WhiteSpace String -- ^ The parser here never returns this
  deriving (ChangeLogEntry -> ChangeLogEntry -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChangeLogEntry -> ChangeLogEntry -> Bool
$c/= :: ChangeLogEntry -> ChangeLogEntry -> Bool
== :: ChangeLogEntry -> ChangeLogEntry -> Bool
$c== :: ChangeLogEntry -> ChangeLogEntry -> Bool
Eq, ReadPrec [ChangeLogEntry]
ReadPrec ChangeLogEntry
Int -> ReadS ChangeLogEntry
ReadS [ChangeLogEntry]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ChangeLogEntry]
$creadListPrec :: ReadPrec [ChangeLogEntry]
readPrec :: ReadPrec ChangeLogEntry
$creadPrec :: ReadPrec ChangeLogEntry
readList :: ReadS [ChangeLogEntry]
$creadList :: ReadS [ChangeLogEntry]
readsPrec :: Int -> ReadS ChangeLogEntry
$creadsPrec :: Int -> ReadS ChangeLogEntry
Read, Int -> ChangeLogEntry -> ShowS
[ChangeLogEntry] -> ShowS
ChangeLogEntry -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [ChangeLogEntry] -> ShowS
$cshowList :: [ChangeLogEntry] -> ShowS
show :: ChangeLogEntry -> [Char]
$cshow :: ChangeLogEntry -> [Char]
showsPrec :: Int -> ChangeLogEntry -> ShowS
$cshowsPrec :: Int -> ChangeLogEntry -> ShowS
Show)

newtype ChangeLog = ChangeLog [ChangeLogEntry] deriving (ChangeLog -> ChangeLog -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ChangeLog -> ChangeLog -> Bool
$c/= :: ChangeLog -> ChangeLog -> Bool
== :: ChangeLog -> ChangeLog -> Bool
$c== :: ChangeLog -> ChangeLog -> Bool
Eq, ReadPrec [ChangeLog]
ReadPrec ChangeLog
Int -> ReadS ChangeLog
ReadS [ChangeLog]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ChangeLog]
$creadListPrec :: ReadPrec [ChangeLog]
readPrec :: ReadPrec ChangeLog
$creadPrec :: ReadPrec ChangeLog
readList :: ReadS [ChangeLog]
$creadList :: ReadS [ChangeLog]
readsPrec :: Int -> ReadS ChangeLog
$creadsPrec :: Int -> ReadS ChangeLog
Read, Int -> ChangeLog -> ShowS
[ChangeLog] -> ShowS
ChangeLog -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [ChangeLog] -> ShowS
$cshowList :: [ChangeLog] -> ShowS
show :: ChangeLog -> [Char]
$cshow :: ChangeLog -> [Char]
showsPrec :: Int -> ChangeLog -> ShowS
$cshowsPrec :: Int -> ChangeLog -> ShowS
Show)

{-
instance Show ChangesFile where
    show = changesFileName
-}

changesFileName :: ChangesFile -> String
changesFileName :: ChangesFile -> [Char]
changesFileName = Doc -> [Char]
render forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Pretty a => a -> Doc
pretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> PP a
PP

instance Pretty (PP ChangesFile) where
    pretty :: PP ChangesFile -> Doc
pretty (PP ChangesFile
changes) = [Char] -> Doc
text (ChangesFile -> [Char]
changePackage ChangesFile
changes forall a. [a] -> [a] -> [a]
++ [Char]
"_") forall a. Semigroup a => a -> a -> a
<> DebianVersion -> Doc
prettyDebianVersion (ChangesFile -> DebianVersion
changeVersion ChangesFile
changes) forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text [Char]
"_" forall a. Semigroup a => a -> a -> a
<> Arch -> Doc
prettyArch (ChangesFile -> Arch
changeArch ChangesFile
changes) forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text [Char]
".changes"

instance Pretty (PP ChangedFileSpec) where
    pretty :: PP ChangedFileSpec -> Doc
pretty (PP ChangedFileSpec
file) =
        [Char] -> Doc
text (ChangedFileSpec -> [Char]
changedFileMD5sum ChangedFileSpec
file forall a. Semigroup a => a -> a -> a
<> [Char]
" " forall a. Semigroup a => a -> a -> a
<>
              forall a. Show a => a -> [Char]
show (ChangedFileSpec -> FileOffset
changedFileSize ChangedFileSpec
file) forall a. Semigroup a => a -> a -> a
<> [Char]
" " forall a. Semigroup a => a -> a -> a
<>
              SubSection -> [Char]
sectionName (ChangedFileSpec -> SubSection
changedFileSection ChangedFileSpec
file) forall a. Semigroup a => a -> a -> a
<> [Char]
" " forall a. Semigroup a => a -> a -> a
<>
              ChangedFileSpec -> [Char]
changedFilePriority ChangedFileSpec
file forall a. Semigroup a => a -> a -> a
<> [Char]
" " forall a. Semigroup a => a -> a -> a
<>
              ChangedFileSpec -> [Char]
changedFileName ChangedFileSpec
file)

instance Pretty (PP ChangeLogEntry) where
    pretty :: PP ChangeLogEntry -> Doc
pretty (PP (Entry [Char]
package DebianVersion
ver [Codename]
dists [Char]
urgency [Char]
details [Char]
who [Char]
date)) =
        [Doc] -> Doc
hcat [ [Char] -> Doc
text [Char]
package forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text [Char]
" (" forall a. Semigroup a => a -> a -> a
<> DebianVersion -> Doc
prettyDebianVersion DebianVersion
ver forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text ([Char]
") " forall a. Semigroup a => a -> a -> a
<> forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" " (forall a b. (a -> b) -> [a] -> [b]
map Codename -> [Char]
codename [Codename]
dists) forall a. [a] -> [a] -> [a]
++ [Char]
"; urgency=" forall a. [a] -> [a] -> [a]
++ [Char]
urgency)
             , [Char] -> Doc
text [Char]
"\n\n"
             , [Char] -> Doc
text [Char]
"  " forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text (ShowS
strip' [Char]
details)
             , [Char] -> Doc
text [Char]
"\n\n"
             , [Char] -> Doc
text ([Char]
" -- " forall a. Semigroup a => a -> a -> a
<> [Char]
who forall a. Semigroup a => a -> a -> a
<> [Char]
"  " forall a. Semigroup a => a -> a -> a
<> [Char]
date)
             , [Char] -> Doc
text [Char]
"\n" ]
    pretty (PP (WhiteSpace [Char]
_)) = forall a. HasCallStack => [Char] -> a
error [Char]
"instance Pretty ChangeLogEntry"

instance Pretty (PP [ChangeLogEntry]) where
    pretty :: PP [ChangeLogEntry] -> Doc
pretty = [Doc] -> Doc
hcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> [a] -> [a]
intersperse ([Char] -> Doc
text [Char]
"\n") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. Pretty a => a -> Doc
pretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> PP a
PP) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. PP a -> a
unPP

strip' :: ShowS
strip' = Text -> [Char]
unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
strip forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
pack

instance Pretty (PP ChangeLog) where
    pretty :: PP ChangeLog -> Doc
pretty (PP (ChangeLog [ChangeLogEntry]
xs)) = [Doc] -> Doc
hcat (forall a. a -> [a] -> [a]
intersperse ([Char] -> Doc
text [Char]
"\n") (forall a b. (a -> b) -> [a] -> [b]
map (forall a. Pretty a => a -> Doc
pretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> PP a
PP) [ChangeLogEntry]
xs))

-- |Show just the top line of a changelog entry (for debugging output.)
_showHeader :: ChangeLogEntry -> Doc
_showHeader :: ChangeLogEntry -> Doc
_showHeader (Entry [Char]
package DebianVersion
ver [Codename]
dists [Char]
urgency [Char]
_ [Char]
_ [Char]
_) =
    [Char] -> Doc
text ([Char]
package forall a. Semigroup a => a -> a -> a
<> [Char]
" (") forall a. Semigroup a => a -> a -> a
<> DebianVersion -> Doc
prettyDebianVersion DebianVersion
ver forall a. Semigroup a => a -> a -> a
<> [Char] -> Doc
text ([Char]
") " forall a. Semigroup a => a -> a -> a
<> forall a. [a] -> [[a]] -> [a]
intercalate [Char]
" " (forall a b. (a -> b) -> [a] -> [b]
map Codename -> [Char]
codename [Codename]
dists) forall a. Semigroup a => a -> a -> a
<> [Char]
"; urgency=" forall a. Semigroup a => a -> a -> a
<> [Char]
urgency forall a. Semigroup a => a -> a -> a
<> [Char]
"...")
_showHeader (WhiteSpace [Char]
_) = forall a. HasCallStack => [Char] -> a
error [Char]
"_showHeader"

{-
format is a series of entries like this:

     package (version) distribution(s); urgency=urgency
    [optional blank line(s), stripped]
       * change details
         more change details
    [blank line(s), included in output of dpkg-parsechangelog]
       * even more change details
    [optional blank line(s), stripped]
      -- maintainer name <email address>[two spaces]  date

package and version are the source package name and version number.

distribution(s) lists the distributions where this version should be
installed when it is uploaded - it is copied to the Distribution field
in the .changes file. See Distribution, Section 5.6.14.

urgency is the value for the Urgency field in the .changes file for
the upload (see Urgency, Section 5.6.17). It is not possible to
specify an urgency containing commas; commas are used to separate
keyword=value settings in the dpkg changelog format (though there is
currently only one useful keyword, urgency).

The change details may in fact be any series of lines starting with at
least two spaces, but conventionally each change starts with an
asterisk and a separating space and continuation lines are indented so
as to bring them in line with the start of the text above. Blank lines
may be used here to separate groups of changes, if desired.

If this upload resolves bugs recorded in the Bug Tracking System
(BTS), they may be automatically closed on the inclusion of this
package into the Debian archive by including the string: closes:
Bug#nnnnn in the change details.[16] This information is conveyed via
the Closes field in the .changes file (see Closes, Section 5.6.22).

The maintainer name and email address used in the changelog should be
the details of the person uploading this version. They are not
necessarily those of the usual package maintainer. The information
here will be copied to the Changed-By field in the .changes file (see
Changed-By, Section 5.6.4), and then later used to send an
acknowledgement when the upload has been installed.

The date must be in RFC822 format[17]; it must include the time zone
specified numerically, with the time zone name or abbreviation
optionally present as a comment in parentheses.

The first "title" line with the package name must start at the left
hand margin. The "trailer" line with the maintainer and date details
must be preceded by exactly one space. The maintainer details and the
date must be separated by exactly two spaces.

The entire changelog must be encoded in UTF-8.
-}

-- | Parse the entries of a debian changelog and verify they are all
-- valid.
parseChangeLog :: String -> Either [[String]] ChangeLog
parseChangeLog :: [Char] -> Either [[[Char]]] ChangeLog
parseChangeLog [Char]
s =
    case forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Char] -> [Either [[Char]] ChangeLogEntry]
parseEntries [Char]
s) of
      ([], [ChangeLogEntry]
xs) -> forall a b. b -> Either a b
Right ([ChangeLogEntry] -> ChangeLog
ChangeLog [ChangeLogEntry]
xs)
      ([[[Char]]]
ss, [ChangeLogEntry]
_) -> forall a b. a -> Either a b
Left [[[Char]]]
ss

-- |Parse a Debian Changelog and return a lazy list of entries
parseEntries :: String -> [Either [String] ChangeLogEntry]
parseEntries :: [Char] -> [Either [[Char]] ChangeLogEntry]
parseEntries [Char]
"" = []
parseEntries [Char]
text =
    case [Char] -> Either [[Char]] (ChangeLogEntry, [Char])
parseEntry [Char]
text of
      Left [[Char]]
messages -> [forall a b. a -> Either a b
Left [[Char]]
messages]
      Right (ChangeLogEntry
entry, [Char]
text') -> forall a b. b -> Either a b
Right ChangeLogEntry
entry forall a. a -> [a] -> [a]
: [Char] -> [Either [[Char]] ChangeLogEntry]
parseEntries [Char]
text'

-- |Parse a single changelog entry, returning the entry and the remaining text.
parseEntry :: String -> Either [String] (ChangeLogEntry, String)
parseEntry :: [Char] -> Either [[Char]] (ChangeLogEntry, [Char])
parseEntry [Char]
text =
    case [Char]
text forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ [Char]
entryRE :: MatchResult String of
      MatchResult [Char]
x | forall a. MatchResult a -> [a]
mrSubList MatchResult [Char]
x forall a. Eq a => a -> a -> Bool
== [] -> forall a b. a -> Either a b
Left [[Char]
"Parse error in " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [Char]
text]
      MR {mrAfter :: forall a. MatchResult a -> a
mrAfter = [Char]
after, mrSubList :: forall a. MatchResult a -> [a]
mrSubList = [[Char]
_, [Char]
name, [Char]
ver, [Char]
dists, [Char]
urgency, [Char]
_, [Char]
details, [Char]
_, [Char]
_, [Char]
who, [Char]
_, [Char]
date, [Char]
_]} ->
          forall a b. b -> Either a b
Right ([Char]
-> DebianVersion
-> [Codename]
-> [Char]
-> [Char]
-> [Char]
-> [Char]
-> ChangeLogEntry
Entry [Char]
name
                         (forall string. ParseDebianVersion string => string -> DebianVersion
parseDebianVersion' [Char]
ver)
                         (forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Codename
parseCodename forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
words forall a b. (a -> b) -> a -> b
$ [Char]
dists)
                         [Char]
urgency
                         ([Char]
"  " forall a. [a] -> [a] -> [a]
++ Text -> [Char]
unpack (Text -> Text
strip ([Char] -> Text
pack [Char]
details)) forall a. [a] -> [a] -> [a]
++ [Char]
"\n")
                         (forall a. Int -> [a] -> [a]
take (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
who forall a. Num a => a -> a -> a
- Int
2) [Char]
who)
                         [Char]
date,
                   [Char]
after)
      MR {mrBefore :: forall a. MatchResult a -> a
mrBefore = [Char]
_before, mrMatch :: forall a. MatchResult a -> a
mrMatch = [Char]
_matched, mrAfter :: forall a. MatchResult a -> a
mrAfter = [Char]
after, mrSubList :: forall a. MatchResult a -> [a]
mrSubList = [[Char]]
matches} ->
          forall a b. a -> Either a b
Left [[Char]
"Internal error\n after=" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [Char]
after forall a. [a] -> [a] -> [a]
++ [Char]
"\n " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show (forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Char]]
matches) forall a. [a] -> [a] -> [a]
++ [Char]
" matches: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [[Char]]
matches]

entryRE :: [Char]
entryRE = [Char]
bol forall a. [a] -> [a] -> [a]
++ [Char]
blankLines forall a. [a] -> [a] -> [a]
++ [Char]
headerRE forall a. [a] -> [a] -> [a]
++ [Char]
changeDetails forall a. [a] -> [a] -> [a]
++ [Char]
signature forall a. [a] -> [a] -> [a]
++ [Char]
blankLines
changeDetails :: [Char]
changeDetails = [Char]
"((\n| \n| -\n|([^ ]| [^--]| -[^--])[^\n]*\n)*)"
signature :: [Char]
signature = [Char]
" -- ([ ]*([^ ]+ )* )([^\n]*)\n"

-- |Parse the changelog information that shows up in the .changes
-- file, i.e. a changelog entry with no signature.
parseChanges :: Text -> Maybe ChangeLogEntry
parseChanges :: Text -> Maybe ChangeLogEntry
parseChanges Text
text =
    case Text -> [Char]
unpack Text
text forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ [Char]
changesRE :: MatchResult String of
      MR {mrSubList :: forall a. MatchResult a -> [a]
mrSubList = []} -> forall a. Maybe a
Nothing
      MR {mrSubList :: forall a. MatchResult a -> [a]
mrSubList = [[Char]
_, [Char]
name, [Char]
ver, [Char]
dists, [Char]
urgency, [Char]
_, [Char]
details]} ->
          forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Char]
-> DebianVersion
-> [Codename]
-> [Char]
-> [Char]
-> [Char]
-> [Char]
-> ChangeLogEntry
Entry [Char]
name
                       (forall string. ParseDebianVersion string => string -> DebianVersion
parseDebianVersion' [Char]
ver)
                       (forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Codename
parseCodename forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
words forall a b. (a -> b) -> a -> b
$ [Char]
dists)
                       [Char]
urgency
                       [Char]
details
                       [Char]
"" [Char]
""
      MR {mrSubList :: forall a. MatchResult a -> [a]
mrSubList = [[Char]]
x} -> forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"Unexpected match: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show [[Char]]
x
    where
      changesRE :: [Char]
changesRE = [Char]
bol forall a. [a] -> [a] -> [a]
++ [Char]
blankLines forall a. [a] -> [a] -> [a]
++ [Char]
optWhite forall a. [a] -> [a] -> [a]
++ [Char]
headerRE forall a. [a] -> [a] -> [a]
++ [Char]
"(.*)$"

headerRE :: [Char]
headerRE =
    [Char]
package forall a. [a] -> [a] -> [a]
++ [Char]
ver forall a. [a] -> [a] -> [a]
++ [Char]
dists forall a. [a] -> [a] -> [a]
++ [Char]
urgency
    where
      package :: [Char]
package = [Char]
"([^ \t(]*)" forall a. [a] -> [a] -> [a]
++ [Char]
optWhite
      ver :: [Char]
ver = [Char]
"\\(([^)]*)\\)" forall a. [a] -> [a] -> [a]
++ [Char]
optWhite
      dists :: [Char]
dists = [Char]
"([^;]*);" forall a. [a] -> [a] -> [a]
++ [Char]
optWhite
      urgency :: [Char]
urgency = [Char]
"urgency=([^\n]*)\n" forall a. [a] -> [a] -> [a]
++ [Char]
blankLines

blankLines :: [Char]
blankLines = [Char]
blankLine forall a. [a] -> [a] -> [a]
++ [Char]
"*"
blankLine :: [Char]
blankLine = [Char]
"(" forall a. [a] -> [a] -> [a]
++ [Char]
optWhite forall a. [a] -> [a] -> [a]
++ [Char]
"\n)"
optWhite :: [Char]
optWhite = [Char]
"[ \t]*"
bol :: [Char]
bol = [Char]
"^"

-- This can be used for tests
_s1 :: [Char]
_s1 = [[Char]] -> [Char]
unlines
     [[Char]
"haskell-regex-compat (0.92-3+seereason1~jaunty4) jaunty-seereason; urgency=low",
      [Char]
"",
      [Char]
"  [ Joachim Breitner ]",
      [Char]
"  * Adjust priority according to override file",
      [Char]
"  * Depend on hscolour (Closes: #550769)",
      [Char]
"",
      [Char]
"  [ Marco Túlio Gontijo e Silva ]",
      [Char]
"  * debian/control: Use more sintetic name for Vcs-Darcs.",
      [Char]
"  * Built from sid apt pool",
      [Char]
"  * Build dependency changes:",
      [Char]
"     cpphs:                    1.9-1+seereason1~jaunty5     -> 1.9-1+seereason1~jaunty6",
      [Char]
"     ghc6:                     6.10.4-1+seereason5~jaunty1  -> 6.12.1-0+seereason1~jaunty1",
      [Char]
"     ghc6-doc:                 6.10.4-1+seereason5~jaunty1  -> 6.12.1-0+seereason1~jaunty1",
      [Char]
"     ghc6-prof:                6.10.4-1+seereason5~jaunty1  -> 6.12.1-0+seereason1~jaunty1",
      [Char]
"     haddock:                  2.4.2-3+seereason3~jaunty1   -> 6.12.1-0+seereason1~jaunty1",
      [Char]
"     haskell-devscripts:       0.6.18-21+seereason1~jaunty1 -> 0.6.18-23+seereason1~jaunty1",
      [Char]
"     haskell-regex-base-doc:   0.93.1-5+seereason1~jaunty1  -> 0.93.1-5++1+seereason1~jaunty1",
      [Char]
"     haskell-regex-posix-doc:  0.93.2-4+seereason1~jaunty1  -> 0.93.2-4+seereason1~jaunty2",
      [Char]
"     libghc6-regex-base-dev:   0.93.1-5+seereason1~jaunty1  -> 0.93.1-5++1+seereason1~jaunty1",
      [Char]
"     libghc6-regex-base-prof:  0.93.1-5+seereason1~jaunty1  -> 0.93.1-5++1+seereason1~jaunty1",
      [Char]
"     libghc6-regex-posix-dev:  0.93.2-4+seereason1~jaunty1  -> 0.93.2-4+seereason1~jaunty2",
      [Char]
"     libghc6-regex-posix-prof: 0.93.2-4+seereason1~jaunty1  -> 0.93.2-4+seereason1~jaunty2",
      [Char]
"",
      [Char]
" -- SeeReason Autobuilder <autobuilder@seereason.org>  Fri, 25 Dec 2009 01:55:37 -0800",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.92-3) unstable; urgency=low",
      [Char]
"",
      [Char]
"  [ Joachim Breitner ]",
      [Char]
"  * Adjust priority according to override file",
      [Char]
"  * Depend on hscolour (Closes: #550769)",
      [Char]
"",
      [Char]
"  [ Marco Túlio Gontijo e Silva ]",
      [Char]
"  * debian/control: Use more sintetic name for Vcs-Darcs.",
      [Char]
"",
      [Char]
" -- Joachim Breitner <nomeata@debian.org>  Mon, 20 Jul 2009 13:05:35 +0200",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.92-2) unstable; urgency=low",
      [Char]
"",
      [Char]
"  * Adopt package for the Debian Haskell Group",
      [Char]
"  * Fix \"FTBFS with new dpkg-dev\" by adding comma to debian/control",
      [Char]
"    (Closes: #536473)",
      [Char]
"",
      [Char]
" -- Joachim Breitner <nomeata@debian.org>  Mon, 20 Jul 2009 12:05:40 +0200",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.92-1.1) unstable; urgency=low",
      [Char]
"",
      [Char]
"  * Rebuild for GHC 6.10.",
      [Char]
"  * NMU with permission of the author.",
      [Char]
"",
      [Char]
" -- John Goerzen <jgoerzen@complete.org>  Mon, 16 Mar 2009 10:12:04 -0500",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.92-1) unstable; urgency=low",
      [Char]
"",
      [Char]
"  * New upstream release",
      [Char]
"  * debian/control:",
      [Char]
"    - Bump Standards-Version. No changes needed.",
      [Char]
"",
      [Char]
" -- Arjan Oosting <arjan@debian.org>  Sun, 18 Jan 2009 00:05:02 +0100",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.91-1) unstable; urgency=low",
      [Char]
"",
      [Char]
"  * Take over package from Ian, as I already maintain haskell-regex-base,",
      [Char]
"    and move Ian to the Uploaders field.",
      [Char]
"  * Packaging complete redone (based on my haskell-regex-base package).",
      [Char]
"",
      [Char]
" -- Arjan Oosting <arjan@debian.org>  Sat, 19 Jan 2008 16:48:39 +0100",
      [Char]
"",
      [Char]
"haskell-regex-compat (0.71.0.1-1) unstable; urgency=low",
      [Char]
" ",
      [Char]
"  * Initial release (used to be part of ghc6).",
      [Char]
"  * Using \"Generic Haskell cabal library packaging files v9\".",
      [Char]
"  ",
      [Char]
" -- Ian Lynagh (wibble) <igloo@debian.org>  Wed, 21 Nov 2007 01:26:57 +0000"]