2Module : Idris.Package.Parser
3Description : `iPKG` file parser and package description information.
6Maintainer : The Idris Community.
8{-# LANGUAGE FlexibleContexts #-}
9module Idris.Package.Parser where
11import Idris.CmdOptions
13import Idris.Package.Common
14import Idris.Parser.Helpers (IdrisInnerParser, MonadicParsing, eol, iName,
15 identifier, isEol, lchar, packageName,
16 parseErrorDoc, reserved, runparser, someSpace,
19import Control.Applicative
20import Control.Monad.State.Strict
21import Data.List (union)
22import System.Directory (doesFileExist)
24import System.FilePath (isValid, takeExtension, takeFileName)
25import Text.Megaparsec ((<?>))
26import qualified Text.Megaparsec as P
27import qualified Text.Megaparsec.Char as P
28import qualified Text.PrettyPrint.ANSI.Leijen as PP
30type PParser = StateT PkgDesc IdrisInnerParser
32parseDesc :: FilePath -> IO PkgDesc
34 when (not $ takeExtension fp == ".ipkg") $ do
35 putStrLn $ unwords ["The presented iPKG file does not have a '.ipkg' extension:", show fp]
36 exitWith (ExitFailure 1)
37 res <- doesFileExist fp
41 case runparser pPkg defaultPkg fp p of
42 Left err -> fail (show $ PP.plain $ parseErrorDoc err)
45 putStrLn $ unwords [ "The presented iPKG file does not exist:", show fp]
46 exitWith (ExitFailure 1)
48pPkg :: PParser PkgDesc
53 modify $ \st -> st { pkgname = p }
59pPkgName :: PParser PkgName
60pPkgName = (either fail pure . pkgName =<< packageName) <?> "PkgName"
62-- | Parses a filename.
64-- | Treated for now as an identifier or a double-quoted string.
65filename :: (MonadicParsing m) => m String
67 -- Treat a double-quoted string as a filename to support spaces.
68 -- This also moves away from tying filenames to identifiers, so
69 -- it will also accept hyphens
70 -- (https://github.com/idris-lang/Idris-dev/issues/2721)
71 filename <- fst <$> stringLiteral
72 -- Through at least version 0.9.19.1, IPKG executable values were
73 -- possibly namespaced identifiers, like foo.bar.baz.
74 <|> show . fst <$> iName []
75 case filenameErrorMessage filename of
76 Just errorMessage -> fail errorMessage
77 Nothing -> return filename)
80 -- TODO: Report failing span better! We could lookAhead,
81 -- or do something with DeltaParsing?
82 filenameErrorMessage :: FilePath -> Maybe String
83 filenameErrorMessage path = either Just (const Nothing) $ do
86 checkNoDirectoryComponent path
88 checkThat ok message =
89 if ok then Right () else Left message
92 checkThat (path /= "") "filename must not be empty"
95 checkThat (System.FilePath.isValid path)
96 "filename must contain only valid characters"
98 checkNoDirectoryComponent path =
99 checkThat (path == takeFileName path)
100 "filename must contain no directory component"
102textUntilEol :: MonadicParsing m => m String
103textUntilEol = many (P.satisfy (not . isEol)) <* eol <* someSpace
105clause :: String -> PParser a -> (PkgDesc -> a -> PkgDesc) -> PParser ()
106clause name p f = do value <- reserved name *> lchar '=' *> p <* someSpace
107 modify $ \st -> f st value
109commaSep :: MonadicParsing m => m a -> m [a]
110commaSep p = P.sepBy1 p (lchar ',')
113pClause = clause "executable" filename (\st v -> st { execout = Just v })
114 <|> clause "main" (fst <$> iName []) (\st v -> st { idris_main = Just v })
115 <|> clause "sourcedir" (fst <$> identifier) (\st v -> st { sourcedir = v })
116 <|> clause "opts" (pureArgParser . words . fst <$> stringLiteral) (\st v -> st { idris_opts = v ++ idris_opts st })
117 <|> clause "pkgs" (commaSep (pPkgName <* someSpace)) (\st ps ->
118 let pkgs = pureArgParser $ concatMap (\x -> ["-p", show x]) ps
119 in st { pkgdeps = ps `union` pkgdeps st
120 , idris_opts = pkgs ++ idris_opts st })
121 <|> clause "modules" (commaSep (fst <$> iName [])) (\st v -> st { modules = modules st ++ v })
122 <|> clause "libs" (commaSep (fst <$> identifier)) (\st v -> st { libdeps = libdeps st ++ v })
123 <|> clause "objs" (commaSep (fst <$> identifier)) (\st v -> st { objs = objs st ++ v })
124 <|> clause "makefile" (fst <$> iName []) (\st v -> st { makefile = Just (show v) })
125 <|> clause "tests" (commaSep (fst <$> iName [])) (\st v -> st { idris_tests = idris_tests st ++ v })
126 <|> clause "version" textUntilEol (\st v -> st { pkgversion = Just v })
127 <|> clause "readme" textUntilEol (\st v -> st { pkgreadme = Just v })
128 <|> clause "license" textUntilEol (\st v -> st { pkglicense = Just v })
129 <|> clause "homepage" textUntilEol (\st v -> st { pkghomepage = Just v })
130 <|> clause "sourceloc" textUntilEol (\st v -> st { pkgsourceloc = Just v })
131 <|> clause "bugtracker" textUntilEol (\st v -> st { pkgbugtracker = Just v })
132 <|> clause "brief" (fst <$> stringLiteral) (\st v -> st { pkgbrief = Just v })
133 <|> clause "author" textUntilEol (\st v -> st { pkgauthor = Just v })
134 <|> clause "maintainer" textUntilEol (\st v -> st { pkgmaintainer = Just v })
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list