module Debian.Repo.SourcesList
(parseSourceLine,
parseSourceLine',
parseSourcesList,
quoteWords
)
where
import Debian.URI
import Debian.Repo.Types
import Data.List
import Data.Maybe
quoteWords :: String -> [String]
quoteWords [] = []
quoteWords s = quoteWords' (dropWhile (==' ') s)
where
quoteWords' :: String -> [String]
quoteWords' [] = []
quoteWords' str =
case break (flip elem " [\"") str of
([],[]) -> []
(w, []) -> [w]
(w, (' ':rest)) -> w : (quoteWords' (dropWhile (==' ') rest))
(w, ('"':rest)) ->
case break (== '"') rest of
(w',('"':rest)) ->
case quoteWords' rest of
[] -> [w ++ w']
(w'':ws) -> ((w ++ w' ++ w''): ws)
(_w',[]) -> error ("quoteWords: missing \" in the string: " ++ s)
_ -> error ("the impossible happened in SourcesList.quoteWords")
(w, ('[':rest)) ->
case break (== ']') rest of
(w',(']':rest)) ->
case quoteWords' rest of
[] -> [w ++ "[" ++ w' ++ "]"]
(w'':ws) -> ((w ++ "[" ++ w' ++ "]" ++ w''): ws)
(_w',[]) -> error ("quoteWords: missing ] in the string: " ++ s)
_ -> error ("the impossible happened in SourcesList.quoteWords")
_ -> error ("the impossible happened in SourcesList.quoteWords")
stripLine :: String -> String
stripLine = takeWhile (/= '#') . dropWhile (== ' ')
sourceLines :: String -> [String]
sourceLines = filter (not . null) . map stripLine . lines
parseSourceLine :: String -> DebSource
parseSourceLine 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, 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, sourceUri = theUri, sourceDist = Right (parseReleaseName theDist, sections) }
_ -> error ("parseSourceLine: invalid line in sources.list:\n" ++ str)
parseSourceLine' :: String -> Maybe DebSource
parseSourceLine' str =
case quoteWords str of
(theTypeStr : theUriStr : theDistStr : sectionStrs) ->
let sections = map parseSection' sectionStrs
theType = case unEscapeString theTypeStr of
"deb" -> Just Deb
"deb-src" -> Just DebSrc
_ -> Nothing
theUri = case parseURI theUriStr of
Nothing -> Nothing
Just u -> Just u
theDist = unEscapeString theDistStr
in
case (last theDist, theType, theUri) of
('/', Just typ, Just uri) -> if null sections
then Just $ DebSource { sourceType = typ, sourceUri = uri, sourceDist = Left theDist }
else error ("parseSourceLine: Dist is an exact path, so sections are not allowed on the line:\n" ++ str)
(_, Just typ, Just uri) -> if null sections
then Nothing
else Just $ DebSource { sourceType = typ, sourceUri = uri, sourceDist = Right ((parseReleaseName theDist), sections) }
_ -> Nothing
_ -> Nothing
parseSourcesList :: String -> [DebSource]
parseSourcesList = map parseSourceLine . sourceLines