2Module : Idris.Package.Parser
3Description : `iPKG` file parser and package description information.
6Maintainer : The Idris Community.
8{-# LANGUAGE CPP, ConstraintKinds #-}
9module Idris.Package.Parser where
11import Idris.AbsSyntaxTree
12import Idris.CmdOptions
14import Idris.Package.Common
15import Idris.Parser.Helpers hiding (stringLiteral)
20import Control.Applicative
21import Control.Monad.State.Strict
22import Data.List (union)
23import Data.Maybe (fromJust, isNothing)
24import System.Directory (doesFileExist)
26import System.FilePath (isValid, takeExtension, takeFileName)
27import qualified Text.PrettyPrint.ANSI.Leijen as PP
28import Text.Trifecta hiding (char, charLiteral, natural, span, string, symbol,
31type PParser = StateT PkgDesc IdrisInnerParser
33instance HasLastTokenSpan PParser where
34 getLastTokenSpan = return Nothing
36#if MIN_VERSION_base(4,9,0)
37instance {-# OVERLAPPING #-} DeltaParsing PParser where
40 position = lift position
41 {-# INLINE position #-}
42 slicedWith f (StateT m) = StateT $ \s -> slicedWith (\(a,s') b -> (f a b, s')) $ m s
43 {-# INLINE slicedWith #-}
46 restOfLine = lift restOfLine
47 {-# INLINE restOfLine #-}
50instance {-# OVERLAPPING #-} TokenParsing PParser where
51 someSpace = many (simpleWhiteSpace <|> singleLineComment <|> multiLineComment) *> pure ()
54parseDesc :: FilePath -> IO PkgDesc
56 when (not $ takeExtension fp == ".ipkg") $ do
57 putStrLn $ unwords ["The presented iPKG file does not have a '.ipkg' extension:", show fp]
58 exitWith (ExitFailure 1)
59 res <- doesFileExist fp
63 case runparser pPkg defaultPkg fp p of
64 Failure (ErrInfo err _) -> fail (show $ PP.plain err)
67 putStrLn $ unwords [ "The presented iPKG file does not exist:", show fp]
68 exitWith (ExitFailure 1)
70pPkg :: PParser PkgDesc
75 put (st { pkgname = p })
82-- | Parses a filename.
84-- | Treated for now as an identifier or a double-quoted string.
85filename :: (MonadicParsing m, HasLastTokenSpan m) => m String
88 -- Treat a double-quoted string as a filename to support spaces.
89 -- This also moves away from tying filenames to identifiers, so
90 -- it will also accept hyphens
91 -- (https://github.com/idris-lang/Idris-dev/issues/2721)
94 -- Through at least version 0.9.19.1, IPKG executable values were
95 -- possibly namespaced identifiers, like foo.bar.baz.
96 show <$> fst <$> iName []
97 case filenameErrorMessage filename of
98 Just errorMessage -> fail errorMessage
99 Nothing -> return filename)
102 -- TODO: Report failing span better! We could lookAhead,
103 -- or do something with DeltaParsing?
104 filenameErrorMessage :: FilePath -> Maybe String
105 filenameErrorMessage path = either Just (const Nothing) $ do
108 checkNoDirectoryComponent path
110 checkThat ok message =
111 if ok then Right () else Left message
114 checkThat (path /= "") "filename must not be empty"
117 checkThat (System.FilePath.isValid path)
118 "filename must contain only valid characters"
120 checkNoDirectoryComponent path =
121 checkThat (path == takeFileName path)
122 "filename must contain no directory component"
126pClause = do reserved "executable"; lchar '=';
129 put (st { execout = Just exec })
131 <|> do reserved "main"; lchar '=';
132 main <- fst <$> iName []
134 put (st { idris_main = Just main })
136 <|> do reserved "sourcedir"; lchar '=';
137 src <- fst <$> identifier
139 put (st { sourcedir = src })
141 <|> do reserved "opts"; lchar '=';
142 opts <- stringLiteral
144 let args = pureArgParser (words opts)
145 put (st { idris_opts = args ++ idris_opts st })
147 <|> do reserved "pkgs"; lchar '=';
148 ps <- sepBy1 (fst <$> identifier) (lchar ',')
150 let pkgs = pureArgParser $ concatMap (\x -> ["-p", x]) ps
152 put (st { pkgdeps = ps `union` (pkgdeps st)
153 , idris_opts = pkgs ++ idris_opts st})
155 <|> do reserved "modules"; lchar '=';
156 ms <- sepBy1 (fst <$> iName []) (lchar ',')
158 put (st { modules = modules st ++ ms })
160 <|> do reserved "libs"; lchar '=';
161 ls <- sepBy1 (fst <$> identifier) (lchar ',')
163 put (st { libdeps = libdeps st ++ ls })
165 <|> do reserved "objs"; lchar '=';
166 ls <- sepBy1 (fst <$> identifier) (lchar ',')
168 put (st { objs = objs st ++ ls })
170 <|> do reserved "makefile"; lchar '=';
171 mk <- fst <$> iName []
173 put (st { makefile = Just (show mk) })
175 <|> do reserved "tests"; lchar '=';
176 ts <- sepBy1 (fst <$> iName []) (lchar ',')
178 put st { idris_tests = idris_tests st ++ ts }
180 <|> do reserved "version"
182 vStr <- many (satisfy (not . isEol))
186 put st {pkgversion = Just vStr}
188 <|> do reserved "readme"
190 rme <- many (satisfy (not . isEol))
194 put (st { pkgreadme = Just rme })
196 <|> do reserved "license"
198 lStr <- many (satisfy (not . isEol))
201 put st {pkglicense = Just lStr}
203 <|> do reserved "homepage"
205 www <- many (satisfy (not . isEol))
209 put st {pkghomepage = Just www}
211 <|> do reserved "sourceloc"
213 srcpage <- many (satisfy (not . isEol))
217 put st {pkgsourceloc = Just srcpage}
219 <|> do reserved "bugtracker"
221 src <- many (satisfy (not . isEol))
225 put st {pkgbugtracker = Just src}
227 <|> do reserved "brief"
229 brief <- stringLiteral
232 put st {pkgbrief = Just brief}
234 <|> do reserved "author"; lchar '=';
235 author <- many (satisfy (not . isEol))
239 put st {pkgauthor = Just author}
241 <|> do reserved "maintainer"; lchar '=';
242 maintainer <- many (satisfy (not . isEol))
246 put st {pkgmaintainer = Just maintainer}
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