    {-# 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.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
    $c== :: SourceType -> SourceType -> Bool
    == :: SourceType -> SourceType -> Bool
    $c/= :: SourceType -> SourceType -> Bool
    /= :: 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
    $ccompare :: SourceType -> SourceType -> Ordering
    compare :: SourceType -> SourceType -> Ordering
    $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
    >= :: SourceType -> SourceType -> Bool
    $cmax :: SourceType -> SourceType -> SourceType
    max :: SourceType -> SourceType -> SourceType
    $cmin :: SourceType -> SourceType -> SourceType
    min :: SourceType -> SourceType -> 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
    $cshowsPrec :: Int -> SourceType -> ShowS
    showsPrec :: Int -> SourceType -> ShowS
    $cshow :: SourceType -> String
    show :: SourceType -> String
    $cshowList :: [SourceType] -> ShowS
    showList :: [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
    $c== :: SourceOption -> SourceOption -> Bool
    == :: SourceOption -> SourceOption -> Bool
    $c/= :: SourceOption -> SourceOption -> Bool
    /= :: 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
    $ccompare :: SourceOption -> SourceOption -> Ordering
    compare :: SourceOption -> SourceOption -> Ordering
    $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
    >= :: SourceOption -> SourceOption -> Bool
    $cmax :: SourceOption -> SourceOption -> SourceOption
    max :: SourceOption -> SourceOption -> SourceOption
    $cmin :: SourceOption -> SourceOption -> SourceOption
    min :: SourceOption -> SourceOption -> 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
    $cshowsPrec :: Int -> SourceOption -> ShowS
    showsPrec :: Int -> SourceOption -> ShowS
    $cshow :: SourceOption -> String
    show :: SourceOption -> String
    $cshowList :: [SourceOption] -> ShowS
    showList :: [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
    $c== :: SourceOp -> SourceOp -> Bool
    == :: SourceOp -> SourceOp -> Bool
    $c/= :: SourceOp -> SourceOp -> Bool
    /= :: 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
    $ccompare :: SourceOp -> SourceOp -> Ordering
    compare :: SourceOp -> SourceOp -> Ordering
    $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
    >= :: SourceOp -> SourceOp -> Bool
    $cmax :: SourceOp -> SourceOp -> SourceOp
    max :: SourceOp -> SourceOp -> SourceOp
    $cmin :: SourceOp -> SourceOp -> SourceOp
    min :: SourceOp -> SourceOp -> 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
    $cshowsPrec :: Int -> SourceOp -> ShowS
    showsPrec :: Int -> SourceOp -> ShowS
    $cshow :: SourceOp -> String
    show :: SourceOp -> String
    $cshowList :: [SourceOp] -> ShowS
    showList :: [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
    $c== :: DebSource -> DebSource -> Bool
    == :: DebSource -> DebSource -> Bool
    $c/= :: DebSource -> DebSource -> Bool
    /= :: 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
    $ccompare :: DebSource -> DebSource -> Ordering
    compare :: DebSource -> DebSource -> Ordering
    $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
    >= :: DebSource -> DebSource -> Bool
    $cmax :: DebSource -> DebSource -> DebSource
    max :: DebSource -> DebSource -> DebSource
    $cmin :: DebSource -> DebSource -> DebSource
    min :: DebSource -> DebSource -> 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
    $cshowsPrec :: Int -> DebSource -> ShowS
    showsPrec :: Int -> DebSource -> ShowS
    $cshow :: DebSource -> String
    show :: DebSource -> String
    $cshowList :: [DebSource] -> ShowS
    showList :: [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 a. Eq a => a -> [a] -> 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 a. [a] -> 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 -> ParsecT String () Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '['
                  skipMany (oneOf [' ','\t'])
                  opts <- sepBy1 pOption (char ',')
                  skipMany (oneOf [' ','\t'])
                  _ <- char ']'
                  return 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'])
                 key <- ParsecT String () Identity Char
    -> ParsecT String () Identity String
    forall s u (m :: * -> *) a. 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'])
                 skipMany (oneOf [' ','\t'])
                 op <- pOp
                 skipMany (oneOf [' ','\t'])
                 values <- sepBy1 (many1 (noneOf [',',']',' ','\t'])) (char ',')
                 skipMany (oneOf [' ','\t'])
                 return $ SourceOption key op 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 a b.
    ParsecT String () Identity a
    -> ParsecT String () Identity b -> ParsecT String () Identity b
    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 a b.
    ParsecT String () Identity a
    -> ParsecT String () Identity b -> ParsecT String () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> SourceOp -> CharParser () SourceOp
    forall a. a -> ParsecT String () Identity a
    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 a b.
    ParsecT String () Identity a
    -> ParsecT String () Identity b -> ParsecT String () Identity b
    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 a b.
    ParsecT String () Identity a
    -> ParsecT String () Identity b -> ParsecT String () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> SourceOp -> CharParser () SourceOp
    forall a. a -> ParsecT String () Identity a
    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 a b.
    ParsecT String () Identity a
    -> ParsecT String () Identity b -> ParsecT String () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> SourceOp -> CharParser () SourceOp
    forall a. a -> ParsecT String () Identity a
    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. HasCallStack => [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 a. [a] -> 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 :: 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 a. [a] -> 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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)