{-# LANGUAGE FlexibleInstances, OverloadedStrings, TemplateHaskell #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Debian.Sources
    {- ( SourceType(..)
    , SourceOption(..)
    , SourceOp(..)
    , DebSource(..)
    , parseSourceLine
    , parseSourceLine'
    , parseSourcesList
    ) -} where

import Control.Lens (makeLenses, review, view)
import Data.Maybe (fromJust)
import Data.Monoid ((<>))
import Data.Text (Text)
import Debian.Codename (Codename, codename, parseCodename)
import Debian.Pretty (PP(..))
import Debian.Release
import Debian.TH (here, Loc)
import Debian.VendorURI (parseVendorURI, VendorURI, vendorURI)
import Network.URI (parseURI, unEscapeString, escapeURIString, isAllowedInURI)
import Test.HUnit
import Text.ParserCombinators.Parsec
import Text.PrettyPrint (hcat, punctuate, render, text)
import Distribution.Pretty (Pretty(pretty), prettyShow)

data SourceType
    = Deb | DebSrc
    deriving (SourceType -> SourceType -> Bool
(SourceType -> SourceType -> Bool)
-> (SourceType -> SourceType -> Bool) -> Eq SourceType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SourceType -> SourceType -> Bool
$c/= :: SourceType -> SourceType -> Bool
== :: SourceType -> SourceType -> Bool
$c== :: SourceType -> SourceType -> Bool
Eq, Eq SourceType
Eq SourceType
-> (SourceType -> SourceType -> Ordering)
-> (SourceType -> SourceType -> Bool)
-> (SourceType -> SourceType -> Bool)
-> (SourceType -> SourceType -> Bool)
-> (SourceType -> SourceType -> Bool)
-> (SourceType -> SourceType -> SourceType)
-> (SourceType -> SourceType -> SourceType)
-> Ord SourceType
SourceType -> SourceType -> Bool
SourceType -> SourceType -> Ordering
SourceType -> SourceType -> SourceType
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 :: SourceType -> SourceType -> SourceType
$cmin :: SourceType -> SourceType -> SourceType
max :: SourceType -> SourceType -> SourceType
$cmax :: SourceType -> SourceType -> SourceType
>= :: SourceType -> SourceType -> Bool
$c>= :: SourceType -> SourceType -> Bool
> :: SourceType -> SourceType -> Bool
$c> :: SourceType -> SourceType -> Bool
<= :: SourceType -> SourceType -> Bool
$c<= :: SourceType -> SourceType -> Bool
< :: SourceType -> SourceType -> Bool
$c< :: SourceType -> SourceType -> Bool
compare :: SourceType -> SourceType -> Ordering
$ccompare :: SourceType -> SourceType -> Ordering
$cp1Ord :: Eq SourceType
Ord, Int -> SourceType -> ShowS
[SourceType] -> ShowS
SourceType -> String
(Int -> SourceType -> ShowS)
-> (SourceType -> String)
-> ([SourceType] -> ShowS)
-> Show SourceType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SourceType] -> ShowS
$cshowList :: [SourceType] -> ShowS
show :: SourceType -> String
$cshow :: SourceType -> String
showsPrec :: Int -> SourceType -> ShowS
$cshowsPrec :: Int -> SourceType -> ShowS
Show)

-- arch
-- lang
-- target
-- pdiffs
-- by-hash
-- allow-insecure=no
-- allow-weak=no
-- allow-downgrade-to-insecure=no
-- trusted=no
-- signed-by
-- check-valid-until
-- valid-until-min
-- valid-until-max
data SourceOption
    = SourceOption String SourceOp [String]
    deriving (SourceOption -> SourceOption -> Bool
(SourceOption -> SourceOption -> Bool)
-> (SourceOption -> SourceOption -> Bool) -> Eq SourceOption
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SourceOption -> SourceOption -> Bool
$c/= :: SourceOption -> SourceOption -> Bool
== :: SourceOption -> SourceOption -> Bool
$c== :: SourceOption -> SourceOption -> Bool
Eq, Eq SourceOption
Eq SourceOption
-> (SourceOption -> SourceOption -> Ordering)
-> (SourceOption -> SourceOption -> Bool)
-> (SourceOption -> SourceOption -> Bool)
-> (SourceOption -> SourceOption -> Bool)
-> (SourceOption -> SourceOption -> Bool)
-> (SourceOption -> SourceOption -> SourceOption)
-> (SourceOption -> SourceOption -> SourceOption)
-> Ord SourceOption
SourceOption -> SourceOption -> Bool
SourceOption -> SourceOption -> Ordering
SourceOption -> SourceOption -> SourceOption
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 :: SourceOption -> SourceOption -> SourceOption
$cmin :: SourceOption -> SourceOption -> SourceOption
max :: SourceOption -> SourceOption -> SourceOption
$cmax :: SourceOption -> SourceOption -> SourceOption
>= :: SourceOption -> SourceOption -> Bool
$c>= :: SourceOption -> SourceOption -> Bool
> :: SourceOption -> SourceOption -> Bool
$c> :: SourceOption -> SourceOption -> Bool
<= :: SourceOption -> SourceOption -> Bool
$c<= :: SourceOption -> SourceOption -> Bool
< :: SourceOption -> SourceOption -> Bool
$c< :: SourceOption -> SourceOption -> Bool
compare :: SourceOption -> SourceOption -> Ordering
$ccompare :: SourceOption -> SourceOption -> Ordering
$cp1Ord :: Eq SourceOption
Ord, Int -> SourceOption -> ShowS
[SourceOption] -> ShowS
SourceOption -> String
(Int -> SourceOption -> ShowS)
-> (SourceOption -> String)
-> ([SourceOption] -> ShowS)
-> Show SourceOption
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SourceOption] -> ShowS
$cshowList :: [SourceOption] -> ShowS
show :: SourceOption -> String
$cshow :: SourceOption -> String
showsPrec :: Int -> SourceOption -> ShowS
$cshowsPrec :: Int -> SourceOption -> ShowS
Show)

data SourceOp = OpSet | OpAdd | OpDel deriving (SourceOp -> SourceOp -> Bool
(SourceOp -> SourceOp -> Bool)
-> (SourceOp -> SourceOp -> Bool) -> Eq SourceOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SourceOp -> SourceOp -> Bool
$c/= :: SourceOp -> SourceOp -> Bool
== :: SourceOp -> SourceOp -> Bool
$c== :: SourceOp -> SourceOp -> Bool
Eq, Eq SourceOp
Eq SourceOp
-> (SourceOp -> SourceOp -> Ordering)
-> (SourceOp -> SourceOp -> Bool)
-> (SourceOp -> SourceOp -> Bool)
-> (SourceOp -> SourceOp -> Bool)
-> (SourceOp -> SourceOp -> Bool)
-> (SourceOp -> SourceOp -> SourceOp)
-> (SourceOp -> SourceOp -> SourceOp)
-> Ord SourceOp
SourceOp -> SourceOp -> Bool
SourceOp -> SourceOp -> Ordering
SourceOp -> SourceOp -> SourceOp
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 :: SourceOp -> SourceOp -> SourceOp
$cmin :: SourceOp -> SourceOp -> SourceOp
max :: SourceOp -> SourceOp -> SourceOp
$cmax :: SourceOp -> SourceOp -> SourceOp
>= :: SourceOp -> SourceOp -> Bool
$c>= :: SourceOp -> SourceOp -> Bool
> :: SourceOp -> SourceOp -> Bool
$c> :: SourceOp -> SourceOp -> Bool
<= :: SourceOp -> SourceOp -> Bool
$c<= :: SourceOp -> SourceOp -> Bool
< :: SourceOp -> SourceOp -> Bool
$c< :: SourceOp -> SourceOp -> Bool
compare :: SourceOp -> SourceOp -> Ordering
$ccompare :: SourceOp -> SourceOp -> Ordering
$cp1Ord :: Eq SourceOp
Ord, Int -> SourceOp -> ShowS
[SourceOp] -> ShowS
SourceOp -> String
(Int -> SourceOp -> ShowS)
-> (SourceOp -> String) -> ([SourceOp] -> ShowS) -> Show SourceOp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SourceOp] -> ShowS
$cshowList :: [SourceOp] -> ShowS
show :: SourceOp -> String
$cshow :: SourceOp -> String
showsPrec :: Int -> SourceOp -> ShowS
$cshowsPrec :: Int -> SourceOp -> ShowS
Show)

instance Pretty SourceOp where
    pretty :: SourceOp -> Doc
pretty SourceOp
OpSet = String -> Doc
text String
"="
    pretty SourceOp
OpAdd = String -> Doc
text String
"+="
    pretty SourceOp
OpDel = String -> Doc
text String
"-="

data DebSource
    = DebSource
    { DebSource -> SourceType
_sourceType :: SourceType
    , DebSource -> [SourceOption]
_sourceOptions :: [SourceOption]
    , DebSource -> VendorURI
_sourceUri :: VendorURI
    , DebSource -> Either String (Codename, [Section])
_sourceDist :: Either String (Codename, [Section])
    } deriving (DebSource -> DebSource -> Bool
(DebSource -> DebSource -> Bool)
-> (DebSource -> DebSource -> Bool) -> Eq DebSource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DebSource -> DebSource -> Bool
$c/= :: DebSource -> DebSource -> Bool
== :: DebSource -> DebSource -> Bool
$c== :: DebSource -> DebSource -> Bool
Eq, Eq DebSource
Eq DebSource
-> (DebSource -> DebSource -> Ordering)
-> (DebSource -> DebSource -> Bool)
-> (DebSource -> DebSource -> Bool)
-> (DebSource -> DebSource -> Bool)
-> (DebSource -> DebSource -> Bool)
-> (DebSource -> DebSource -> DebSource)
-> (DebSource -> DebSource -> DebSource)
-> Ord DebSource
DebSource -> DebSource -> Bool
DebSource -> DebSource -> Ordering
DebSource -> DebSource -> DebSource
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 :: DebSource -> DebSource -> DebSource
$cmin :: DebSource -> DebSource -> DebSource
max :: DebSource -> DebSource -> DebSource
$cmax :: DebSource -> DebSource -> DebSource
>= :: DebSource -> DebSource -> Bool
$c>= :: DebSource -> DebSource -> Bool
> :: DebSource -> DebSource -> Bool
$c> :: DebSource -> DebSource -> Bool
<= :: DebSource -> DebSource -> Bool
$c<= :: DebSource -> DebSource -> Bool
< :: DebSource -> DebSource -> Bool
$c< :: DebSource -> DebSource -> Bool
compare :: DebSource -> DebSource -> Ordering
$ccompare :: DebSource -> DebSource -> Ordering
$cp1Ord :: Eq DebSource
Ord, Int -> DebSource -> ShowS
[DebSource] -> ShowS
DebSource -> String
(Int -> DebSource -> ShowS)
-> (DebSource -> String)
-> ([DebSource] -> ShowS)
-> Show DebSource
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DebSource] -> ShowS
$cshowList :: [DebSource] -> ShowS
show :: DebSource -> String
$cshow :: DebSource -> String
showsPrec :: Int -> DebSource -> ShowS
$cshowsPrec :: Int -> DebSource -> ShowS
Show)

instance Pretty SourceType where
    pretty :: SourceType -> Doc
pretty SourceType
Deb = String -> Doc
text String
"deb"
    pretty SourceType
DebSrc = String -> Doc
text String
"deb-src"

instance Pretty SourceOption where
    pretty :: SourceOption -> Doc
pretty (SourceOption String
k SourceOp
op [String]
vs) = String -> Doc
text String
k Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> SourceOp -> Doc
forall a. Pretty a => a -> Doc
pretty SourceOp
op Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> [Doc] -> Doc
hcat (Doc -> [Doc] -> [Doc]
punctuate (String -> Doc
text String
",") ((String -> Doc) -> [String] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map String -> Doc
text [String]
vs))

instance Pretty DebSource where
    pretty :: DebSource -> Doc
pretty (DebSource SourceType
thetype [SourceOption]
theoptions VendorURI
theuri Either String (Codename, [Section])
thedist) =
        [Doc] -> Doc
hcat (Doc -> [Doc] -> [Doc]
punctuate (String -> Doc
text String
" ")
                ([SourceType -> Doc
forall a. Pretty a => a -> Doc
pretty SourceType
thetype] [Doc] -> [Doc] -> [Doc]
forall a. [a] -> [a] -> [a]
++
                 (case [SourceOption]
theoptions of
                    [] -> []
                    [SourceOption]
_ -> [String -> Doc
text String
"[" Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> [Doc] -> Doc
hcat (Doc -> [Doc] -> [Doc]
punctuate (String -> Doc
text String
", ") ((SourceOption -> Doc) -> [SourceOption] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map SourceOption -> Doc
forall a. Pretty a => a -> Doc
pretty [SourceOption]
theoptions)) Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> String -> Doc
text String
"]"]) [Doc] -> [Doc] -> [Doc]
forall a. [a] -> [a] -> [a]
++
                 [String -> Doc
text (URI -> String
forall a. Show a => a -> String
show (Getting URI VendorURI URI -> VendorURI -> URI
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting URI VendorURI URI
Iso' VendorURI URI
vendorURI VendorURI
theuri))] [Doc] -> [Doc] -> [Doc]
forall a. [a] -> [a] -> [a]
++
                 case Either String (Codename, [Section])
thedist of
                   Left String
exactPath -> [String -> Doc
text ((Char -> Bool) -> ShowS
escapeURIString Char -> Bool
isAllowedInURI String
exactPath)]
                   Right (Codename
dist, [Section]
sections) ->
                       (String -> Doc) -> [String] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map String -> Doc
text (Codename -> String
codename Codename
dist String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (Section -> String) -> [Section] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Section -> String
sectionName' [Section]
sections)))

instance Pretty (PP [DebSource]) where
    pretty :: PP [DebSource] -> Doc
pretty = [Doc] -> Doc
hcat ([Doc] -> Doc)
-> (PP [DebSource] -> [Doc]) -> PP [DebSource] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DebSource -> Doc) -> [DebSource] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (\ DebSource
x -> DebSource -> Doc
forall a. Pretty a => a -> Doc
pretty DebSource
x Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> String -> Doc
text String
"\n") ([DebSource] -> [Doc])
-> (PP [DebSource] -> [DebSource]) -> PP [DebSource] -> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PP [DebSource] -> [DebSource]
forall a. PP a -> a
unPP

{-

deb uri distribution [component1] [componenent2] [...]

The URI for the deb type must specify the base of the Debian
distribution, from which APT will find the information it needs.

distribution can specify an exact path, in which case the components
must be omitted and distribution must end with a slash (/).

If distribution does not specify an exact path, at least one component
must be present.

Distribution may also contain a variable, $(ARCH), which expands to
the Debian architecture (i386, m68k, powerpc, ...)  used on the
system.

The rest of the line can be marked as a comment by using a #.

Additional Notes:

 + Lines can begin with leading white space.

 + If the dist ends with slash (/), then it must be an absolute path
   and it is an error to specify components after it.

-}

-- |quoteWords - similar to words, but with special handling of
-- double-quotes and brackets.
--
-- The handling double quotes and [] is supposed to match:
-- apt-0.6.44.2\/apt-pkg\/contrib\/strutl.cc:ParseQuoteWord()
--
-- The behaviour can be defined as:
--
--  Break the string into space seperated words ignoring spaces that
--  appear between \"\" or []. Strip trailing and leading white space
--  around words. Strip out double quotes, but leave the square
--  brackets intact.
quoteWords :: String -> [String]
quoteWords :: String -> [String]
quoteWords [] = []
quoteWords String
s = String -> [String]
quoteWords' ((Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') String
s)
    where
      quoteWords' :: String -> [String]
      quoteWords' :: String -> [String]
quoteWords' [] = []
      quoteWords' String
str =
          case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break ((Char -> String -> Bool) -> String -> Char -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem (String
" [\"" :: String)) String
str of
            ([],[]) -> []
            (String
w, []) -> [String
w]
            (String
w, (Char
' ':String
rest)) -> String
w String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (String -> [String]
quoteWords' ((Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') String
rest))
            (String
w, (Char
'"':String
rest)) ->
                case (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
rest of
                  (String
w',(Char
'"':String
rest)) ->
                      case String -> [String]
quoteWords' String
rest of
                        [] ->  [String
w String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w']
                        (String
w'':[String]
ws) -> ((String
w String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w'')String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
ws)
                  (String
_w',[]) -> String -> [String]
forall a. HasCallStack => String -> a
error (String
"quoteWords: missing \" in the string: "  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s)
                  (String, String)
_ -> String -> [String]
forall a. HasCallStack => String -> a
error (String
"the impossible happened in SourcesList.quoteWords")
            (String
w, (Char
'[':String
rest)) ->
                case (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
rest of
                  (String
w',(Char
']':String
rest)) ->
                      case String -> [String]
quoteWords' String
rest of
                        []       -> [String
w String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"]
                        (String
w'':[String]
ws) -> ((String
w String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
w'')String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
ws)
                  (String
_w',[]) -> String -> [String]
forall a. HasCallStack => String -> a
error (String
"quoteWords: missing ] in the string: "  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s)
                  (String, String)
_ -> String -> [String]
forall a. HasCallStack => String -> a
error (String
"the impossible happened in SourcesList.quoteWords")
            (String, String)
_ -> String -> [String]
forall a. HasCallStack => String -> a
error (String
"the impossible happened in SourcesList.quoteWords")

stripLine :: String -> String
stripLine :: ShowS
stripLine = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'#') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ')

sourceLines :: String -> [String]
sourceLines :: String -> [String]
sourceLines = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ShowS
stripLine ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

-- |parseSourceLine -- parses a source line
-- the argument must be a non-empty, valid source line with comments stripped
-- see: 'sourceLines'
parseSourceLine :: [Loc] -> String -> DebSource
parseSourceLine :: [Loc] -> String -> DebSource
parseSourceLine [Loc]
locs String
str = (String -> DebSource)
-> (DebSource -> DebSource) -> Either String DebSource -> DebSource
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> DebSource
forall a. HasCallStack => String -> a
error DebSource -> DebSource
forall a. a -> a
id ([Loc] -> String -> Either String DebSource
parseSourceLine' [Loc]
locs String
str)
{-
    case quoteWords str of
      (theTypeStr : theUriStr : theDistStr : sectionStrs) ->
          let sections = map parseSection' sectionStrs
              theType = case unEscapeString theTypeStr of
                          "deb" -> Deb
                          "deb-src" -> DebSrc
                          o -> error ("parseSourceLine: invalid type " ++ o ++ " in line:\n" ++ str)
              theUri = case parseURI theUriStr of
                         Nothing -> error ("parseSourceLine: invalid uri " ++ theUriStr ++ " in the line:\n" ++ str)
                         Just u -> u
              theDist = unEscapeString theDistStr
          in
            case last theDist of
              '/' -> if null sections
                      then DebSource { sourceType = theType, sourceOptions = [], sourceUri = theUri, sourceDist = Left theDist }
                      else error ("parseSourceLine: Dist is an exact path, so sections are not allowed on the line:\n" ++ str)
              _ -> if null sections
                    then error ("parseSourceLine: Dist is not an exact path, so at least one section is required on the line:\n" ++ str)
                    else DebSource { sourceType = theType, sourceOptions = [], sourceUri = theUri, sourceDist = Right (parseReleaseName theDist, sections) }
      _ -> error ("parseSourceLine: invalid line in sources.list:\n" ++ str)
-}

parseOptions :: String -> Either ParseError [SourceOption]
parseOptions :: String -> Either ParseError [SourceOption]
parseOptions String
s = Parsec String () [SourceOption]
-> String -> String -> Either ParseError [SourceOption]
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parsec String () [SourceOption]
pOptions String
s String
s

pOptions :: CharParser () [SourceOption]
pOptions :: Parsec String () [SourceOption]
pOptions = do Char
_ <- Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'['
              ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
              [SourceOption]
opts <- ParsecT String () Identity SourceOption
-> ParsecT String () Identity Char
-> Parsec String () [SourceOption]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy1 ParsecT String () Identity SourceOption
pOption (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',')
              ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
              Char
_ <- Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
']'
              [SourceOption] -> Parsec String () [SourceOption]
forall (m :: * -> *) a. Monad m => a -> m a
return [SourceOption]
opts

pOption :: CharParser () SourceOption
pOption :: ParsecT String () Identity SourceOption
pOption = do ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
             String
key <- ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf [Char
'+',Char
'-',Char
'=',Char
' ',Char
'\t'])
             ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
             SourceOp
op <- CharParser () SourceOp
pOp
             ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
             [String]
values <- ParsecT String () Identity String
-> ParsecT String () Identity Char
-> ParsecT String () Identity [String]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy1 (ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf [Char
',',Char
']',Char
' ',Char
'\t'])) (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',')
             ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf [Char
' ',Char
'\t'])
             SourceOption -> ParsecT String () Identity SourceOption
forall (m :: * -> *) a. Monad m => a -> m a
return (SourceOption -> ParsecT String () Identity SourceOption)
-> SourceOption -> ParsecT String () Identity SourceOption
forall a b. (a -> b) -> a -> b
$ String -> SourceOp -> [String] -> SourceOption
SourceOption String
key SourceOp
op [String]
values

pOp :: CharParser () SourceOp
pOp :: CharParser () SourceOp
pOp = do (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'+' ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=' ParsecT String () Identity Char
-> CharParser () SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a. Monad m => a -> m a
return SourceOp
OpAdd)
         CharParser () SourceOp
-> CharParser () SourceOp -> CharParser () SourceOp
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
         (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'-' ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=' ParsecT String () Identity Char
-> CharParser () SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a. Monad m => a -> m a
return SourceOp
OpDel)
         CharParser () SourceOp
-> CharParser () SourceOp -> CharParser () SourceOp
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
         (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=' ParsecT String () Identity Char
-> CharParser () SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SourceOp -> CharParser () SourceOp
forall (m :: * -> *) a. Monad m => a -> m a
return SourceOp
OpSet)

parseSourceLine' :: [Loc] -> String -> Either String DebSource
parseSourceLine' :: [Loc] -> String -> Either String DebSource
parseSourceLine' [Loc]
locs String
str =
    case String -> [String]
quoteWords String
str of
      String
theTypeStr : theOptionStr :: String
theOptionStr@(Char
'[' : String
_) : String
theURIStr : String
theDistStr : [String]
sectionStrs ->
          (ParseError -> Either String DebSource)
-> ([SourceOption] -> Either String DebSource)
-> Either ParseError [SourceOption]
-> Either String DebSource
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
            (String -> Either String DebSource
forall a b. a -> Either a b
Left (String -> Either String DebSource)
-> (ParseError -> String) -> ParseError -> Either String DebSource
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
forall a. Show a => a -> String
show)
            (\[SourceOption]
opts -> String
-> [SourceOption]
-> String
-> String
-> [String]
-> Either String DebSource
go String
theTypeStr [SourceOption]
opts String
theURIStr String
theDistStr [String]
sectionStrs)
            (String -> Either ParseError [SourceOption]
parseOptions String
theOptionStr)
      String
theTypeStr : String
theURIStr : String
theDistStr : [String]
sectionStrs ->
          String
-> [SourceOption]
-> String
-> String
-> [String]
-> Either String DebSource
go String
theTypeStr [] String
theURIStr String
theDistStr [String]
sectionStrs
      [String]
_ -> String -> Either String DebSource
forall a b. a -> Either a b
Left (String
"parseSourceLine: invalid line in sources.list:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
str)
    where
      go :: String -> [SourceOption] -> String -> String -> [String] -> Either String DebSource
      go :: String
-> [SourceOption]
-> String
-> String
-> [String]
-> Either String DebSource
go String
theTypeStr [SourceOption]
theOptions String
theURIStr String
theDistStr [String]
sectionStrs =
          let sections :: [Section]
sections = (String -> Section) -> [String] -> [Section]
forall a b. (a -> b) -> [a] -> [b]
map String -> Section
parseSection' [String]
sectionStrs
              theType :: Either String SourceType
theType = case ShowS
unEscapeString String
theTypeStr of
                          String
"deb" -> SourceType -> Either String SourceType
forall a b. b -> Either a b
Right SourceType
Deb
                          String
"deb-src" -> SourceType -> Either String SourceType
forall a b. b -> Either a b
Right SourceType
DebSrc
                          String
s -> String -> Either String SourceType
forall a b. a -> Either a b
Left (String
"parseSourceLine" String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Loc] -> String
forall a. Pretty a => a -> String
prettyShow (Int
String
String -> String -> String -> CharPos -> CharPos -> Loc
$here Loc -> [Loc] -> [Loc]
forall a. a -> [a] -> [a]
: [Loc]
locs) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": invalid type " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" in line:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
str String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" str=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
str)
              theURI :: Either String VendorURI
theURI = case [Loc] -> String -> Maybe VendorURI
parseVendorURI (Int
String
String -> String -> String -> CharPos -> CharPos -> Loc
$here Loc -> [Loc] -> [Loc]
forall a. a -> [a] -> [a]
: [Loc]
locs) String
theURIStr of
                         Maybe VendorURI
Nothing -> String -> Either String VendorURI
forall a b. a -> Either a b
Left (String
"parseSourceLine' " String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Loc] -> String
forall a. Pretty a => a -> String
prettyShow (Int
String
String -> String -> String -> CharPos -> CharPos -> Loc
$here Loc -> [Loc] -> [Loc]
forall a. a -> [a] -> [a]
: [Loc]
locs) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": invalid uri " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
theURIStr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" str=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
str)
                         Just VendorURI
u -> VendorURI -> Either String VendorURI
forall a b. b -> Either a b
Right VendorURI
u
              theDist :: String
theDist = ShowS
unEscapeString String
theDistStr
          in
            case (String -> Char
forall a. [a] -> a
last String
theDist, Either String SourceType
theType, Either String VendorURI
theURI) of
              (Char
'/', Right SourceType
typ, Right VendorURI
uri) -> if [Section] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Section]
sections
                      then DebSource -> Either String DebSource
forall a b. b -> Either a b
Right (DebSource -> Either String DebSource)
-> DebSource -> Either String DebSource
forall a b. (a -> b) -> a -> b
$ DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource { _sourceType :: SourceType
_sourceType = SourceType
typ, _sourceOptions :: [SourceOption]
_sourceOptions = [SourceOption]
theOptions, _sourceUri :: VendorURI
_sourceUri = VendorURI
uri, _sourceDist :: Either String (Codename, [Section])
_sourceDist = String -> Either String (Codename, [Section])
forall a b. a -> Either a b
Left String
theDist }
                      else String -> Either String DebSource
forall a b. a -> Either a b
Left (String
"parseSourceLine: Dist is an exact path, so sections are not allowed on the line:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
str)
              (Char
_, Right SourceType
typ, Right VendorURI
uri) -> if [Section] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Section]
sections
                    then String -> Either String DebSource
forall a b. a -> Either a b
Left (String
"parseSourceLine: Dist is not an exact path, so at least one section is required on the line:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
str)
                    else DebSource -> Either String DebSource
forall a b. b -> Either a b
Right (DebSource -> Either String DebSource)
-> DebSource -> Either String DebSource
forall a b. (a -> b) -> a -> b
$ DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource { _sourceType :: SourceType
_sourceType = SourceType
typ, _sourceOptions :: [SourceOption]
_sourceOptions = [SourceOption]
theOptions, _sourceUri :: VendorURI
_sourceUri = VendorURI
uri, _sourceDist :: Either String (Codename, [Section])
_sourceDist = (Codename, [Section]) -> Either String (Codename, [Section])
forall a b. b -> Either a b
Right ((String -> Codename
parseCodename String
theDist), [Section]
sections) }
              (Char
_, Left String
msg, Either String VendorURI
_) -> String -> Either String DebSource
forall a b. a -> Either a b
Left String
msg
              (Char
_, Either String SourceType
_, Left String
msg) -> String -> Either String DebSource
forall a b. a -> Either a b
Left String
msg

parseSourcesList :: [Loc] -> String -> [DebSource]
parseSourcesList :: [Loc] -> String -> [DebSource]
parseSourcesList [Loc]
locs = (String -> DebSource) -> [String] -> [DebSource]
forall a b. (a -> b) -> [a] -> [b]
map ([Loc] -> String -> DebSource
parseSourceLine [Loc]
locs) ([String] -> [DebSource])
-> (String -> [String]) -> String -> [DebSource]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
sourceLines

-- * Unit Tests

-- TODO: add test cases that test for unterminated double-quote or bracket
testQuoteWords :: Test
testQuoteWords :: Test
testQuoteWords =
    [Assertion] -> Test
forall t. (Testable t, HasCallStack) => t -> Test
test [ String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, no quoting" [String
"hello", String
"world",String
"!"] (String -> [String]
quoteWords String
"  hello    world !  ")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, double quotes" [String
"hello  world",String
"!"] (String -> [String]
quoteWords String
"  hel\"lo  world\" !  ")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, square brackets" [String
"hel[lo  worl]d",String
"!"] (String -> [String]
quoteWords String
"  hel[lo  worl]d ! ")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, square-bracket at end" [String
"hel[lo world]"] (String -> [String]
quoteWords String
" hel[lo world]")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, double quote at end" [String
"hello world"] (String -> [String]
quoteWords String
" hel\"lo world\"")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, square-bracket at beginning" [String
"[hello wo]rld",String
"!"] (String -> [String]
quoteWords String
"[hello wo]rld !")
         , String -> [String] -> [String] -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"Space seperate words, double quote at beginning" [String
"hello world",String
"!"] (String -> [String]
quoteWords String
"\"hello wor\"ld !")
         ]

testSourcesList :: Test
testSourcesList :: Test
testSourcesList =
    [Assertion] -> Test
forall t. (Testable t, HasCallStack) => t -> Test
test [ String -> String -> String -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"parse and pretty sources.list" String
validSourcesListExpected (Doc -> String
render (Doc -> String) -> (String -> Doc) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PP [DebSource] -> Doc
forall a. Pretty a => a -> Doc
pretty (PP [DebSource] -> Doc)
-> (String -> PP [DebSource]) -> String -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [DebSource] -> PP [DebSource]
forall a. a -> PP a
PP ([DebSource] -> PP [DebSource])
-> (String -> [DebSource]) -> String -> PP [DebSource]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Loc] -> String -> [DebSource]
parseSourcesList [Int
String
String -> String -> String -> CharPos -> CharPos -> Loc
$here] ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
validSourcesListStr) ]

testSourcesList2 :: Test
testSourcesList2 :: Test
testSourcesList2 =
    [Assertion] -> Test
forall t. (Testable t, HasCallStack) => t -> Test
test [ String -> String -> String -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"pretty sources.list" String
validSourcesListExpected (Doc -> String
render (Doc -> String) -> ([DebSource] -> Doc) -> [DebSource] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PP [DebSource] -> Doc
forall a. Pretty a => a -> Doc
pretty (PP [DebSource] -> Doc)
-> ([DebSource] -> PP [DebSource]) -> [DebSource] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [DebSource] -> PP [DebSource]
forall a. a -> PP a
PP ([DebSource] -> String) -> [DebSource] -> String
forall a b. (a -> b) -> a -> b
$ [DebSource]
validSourcesList) ]

validSourcesListStr :: String
validSourcesListStr :: String
validSourcesListStr =
          [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [ String
" # A comment only line "
                    , String
" deb ftp://ftp.debian.org/debian unstable main contrib non-free # typical deb line"
                    , String
" deb-src ftp://ftp.debian.org/debian unstable main contrib non-free # typical deb-src line"
                    , String
""
                    , String
"# comment line"
                    , String
"deb http://pkg-kde.alioth.debian.org/kde-3.5.0/ ./ # exact path"
                    , String
"deb [trusted=yes] http://ftp.debian.org/whee \"space dist\" main"
                    , String
"deb [trusted=yes] http://ftp.debian.org/whee dist space%20section"
                    ]

validSourcesList :: [DebSource]
validSourcesList :: [DebSource]
validSourcesList =
    [DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource {_sourceType :: SourceType
_sourceType = SourceType
Deb, _sourceOptions :: [SourceOption]
_sourceOptions = [], _sourceUri :: VendorURI
_sourceUri = (AReview VendorURI URI -> URI -> VendorURI
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview VendorURI URI
Iso' VendorURI URI
vendorURI (URI -> VendorURI) -> (Maybe URI -> URI) -> Maybe URI -> VendorURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe URI -> URI
forall a. HasCallStack => Maybe a -> a
fromJust) (String -> Maybe URI
parseURI String
"ftp://ftp.debian.org/debian"), _sourceDist :: Either String (Codename, [Section])
_sourceDist = (Codename, [Section]) -> Either String (Codename, [Section])
forall a b. b -> Either a b
Right (String -> Codename
parseCodename String
"unstable",[String -> Section
Section String
"main",String -> Section
Section String
"contrib",String -> Section
Section String
"non-free"])},
     DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource {_sourceType :: SourceType
_sourceType = SourceType
DebSrc, _sourceOptions :: [SourceOption]
_sourceOptions = [], _sourceUri :: VendorURI
_sourceUri = (AReview VendorURI URI -> URI -> VendorURI
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview VendorURI URI
Iso' VendorURI URI
vendorURI (URI -> VendorURI) -> (Maybe URI -> URI) -> Maybe URI -> VendorURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe URI -> URI
forall a. HasCallStack => Maybe a -> a
fromJust) (String -> Maybe URI
parseURI String
"ftp://ftp.debian.org/debian"), _sourceDist :: Either String (Codename, [Section])
_sourceDist = (Codename, [Section]) -> Either String (Codename, [Section])
forall a b. b -> Either a b
Right (String -> Codename
parseCodename String
"unstable",[String -> Section
Section String
"main",String -> Section
Section String
"contrib",String -> Section
Section String
"non-free"])},
     DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource {_sourceType :: SourceType
_sourceType = SourceType
Deb, _sourceOptions :: [SourceOption]
_sourceOptions = [], _sourceUri :: VendorURI
_sourceUri = (AReview VendorURI URI -> URI -> VendorURI
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview VendorURI URI
Iso' VendorURI URI
vendorURI (URI -> VendorURI) -> (Maybe URI -> URI) -> Maybe URI -> VendorURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe URI -> URI
forall a. HasCallStack => Maybe a -> a
fromJust) (String -> Maybe URI
parseURI String
"http://pkg-kde.alioth.debian.org/kde-3.5.0/"), _sourceDist :: Either String (Codename, [Section])
_sourceDist = String -> Either String (Codename, [Section])
forall a b. a -> Either a b
Left String
"./"},
     DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource {_sourceType :: SourceType
_sourceType = SourceType
Deb, _sourceOptions :: [SourceOption]
_sourceOptions = [String -> SourceOp -> [String] -> SourceOption
SourceOption String
"trusted" SourceOp
OpSet [String
"yes"]], _sourceUri :: VendorURI
_sourceUri = (AReview VendorURI URI -> URI -> VendorURI
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview VendorURI URI
Iso' VendorURI URI
vendorURI (URI -> VendorURI) -> (Maybe URI -> URI) -> Maybe URI -> VendorURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe URI -> URI
forall a. HasCallStack => Maybe a -> a
fromJust) (String -> Maybe URI
parseURI String
"http://ftp.debian.org/whee"), _sourceDist :: Either String (Codename, [Section])
_sourceDist = (Codename, [Section]) -> Either String (Codename, [Section])
forall a b. b -> Either a b
Right (String -> Codename
parseCodename String
"space dist",[String -> Section
Section String
"main"])},
     DebSource :: SourceType
-> [SourceOption]
-> VendorURI
-> Either String (Codename, [Section])
-> DebSource
DebSource {_sourceType :: SourceType
_sourceType = SourceType
Deb, _sourceOptions :: [SourceOption]
_sourceOptions = [String -> SourceOp -> [String] -> SourceOption
SourceOption String
"trusted" SourceOp
OpSet [String
"yes"]], _sourceUri :: VendorURI
_sourceUri = (AReview VendorURI URI -> URI -> VendorURI
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview VendorURI URI
Iso' VendorURI URI
vendorURI (URI -> VendorURI) -> (Maybe URI -> URI) -> Maybe URI -> VendorURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe URI -> URI
forall a. HasCallStack => Maybe a -> a
fromJust) (String -> Maybe URI
parseURI String
"http://ftp.debian.org/whee"), _sourceDist :: Either String (Codename, [Section])
_sourceDist = (Codename, [Section]) -> Either String (Codename, [Section])
forall a b. b -> Either a b
Right (String -> Codename
parseCodename String
"dist",[String -> Section
Section String
"space section"])}]

validSourcesListExpected :: String
validSourcesListExpected :: String
validSourcesListExpected =
          [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [ String
"deb ftp://ftp.debian.org/debian unstable main contrib non-free"
                    , String
"deb-src ftp://ftp.debian.org/debian unstable main contrib non-free"
                    , String
"deb http://pkg-kde.alioth.debian.org/kde-3.5.0/ ./"
                    , String
"deb [trusted=yes] http://ftp.debian.org/whee space%20dist main"
                    , String
"deb [trusted=yes] http://ftp.debian.org/whee dist space%20section"
                    ]
_invalidSourcesListStr1 :: Text
_invalidSourcesListStr1 :: Text
_invalidSourcesListStr1 = Text
"deb http://pkg-kde.alioth.debian.org/kde-3.5.0/ ./ main contrib non-free # exact path with sections"

testSourcesListParse :: Test
testSourcesListParse :: Test
testSourcesListParse =
    [Assertion] -> Test
forall t. (Testable t, HasCallStack) => t -> Test
test [ String -> String -> String -> Assertion
forall a.
(HasCallStack, Eq a, Show a) =>
String -> a -> a -> Assertion
assertEqual String
"" String
gutsy ([String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> (String -> [String]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"\n") ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DebSource -> String) -> [DebSource] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Doc -> String
render (Doc -> String) -> (DebSource -> Doc) -> DebSource -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DebSource -> Doc
forall a. Pretty a => a -> Doc
pretty) ([DebSource] -> [String])
-> (String -> [DebSource]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Loc] -> String -> [DebSource]
parseSourcesList [Int
String
String -> String -> String -> CharPos -> CharPos -> Loc
$here] ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
gutsy) ]
    where
      gutsy :: String
gutsy = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"deb http://us.archive.ubuntu.com/ubuntu/ gutsy main restricted universe multiverse\n",
                      String
"deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy main restricted universe multiverse\n",
                      String
"deb http://us.archive.ubuntu.com/ubuntu/ gutsy-updates main restricted universe multiverse\n",
                      String
"deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy-updates main restricted universe multiverse\n",
                      String
"deb http://us.archive.ubuntu.com/ubuntu/ gutsy-backports main restricted universe multiverse\n",
                      String
"deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy-backports main restricted universe multiverse\n",
                      String
"deb http://security.ubuntu.com/ubuntu/ gutsy-security main restricted universe multiverse\n",
                      String
"deb-src http://security.ubuntu.com/ubuntu/ gutsy-security main restricted universe multiverse\n"]

sourcesListTests :: Test
sourcesListTests :: Test
sourcesListTests =
    [Test] -> Test
TestList [ Test
testQuoteWords, Test
testSourcesList, Test
testSourcesList2, Test
testSourcesListParse ]

$(makeLenses ''DebSource)