2module Pkg.Package where
8import System.FilePath ((</>), addTrailingPathSeparator, takeFileName, takeDirectory, normalise)
9import System.Directory (createDirectoryIfMissing, copyFile)
14import Control.Monad.Trans.State.Strict (execStateT)
15import Control.Monad.Error (runErrorT)
18import Data.List.Split(splitOn)
22import Idris.Parser (loadModule)
23import Idris.Output (pshow)
32import Paths_idris (getDataDir)
35-- * read the package description
36-- * check all the library dependencies exist
37-- * invoke the makefile if there is one
38-- * invoke idris on each module, with idris_opts
39-- * install everything into datadir/pname, if install flag is set
41-- | Run the package through the idris compiler.
42buildPkg :: Bool -> (Bool, FilePath) -> IO ()
43buildPkg warnonly (install, fp)
44 = do pkgdesc <- parseDesc fp
45 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
47 do dir <- getCurrentDirectory
48 setCurrentDirectory $ dir </> sourcedir pkgdesc
49 make (makefile pkgdesc)
50 m_ist <- case (execout pkgdesc) of
51 Nothing -> buildMods (NoREPL : Verbose : idris_opts pkgdesc)
53 Just o -> do let exec = dir </> o
55 (NoREPL : Verbose : Output exec : idris_opts pkgdesc)
57 setCurrentDirectory dir
59 Nothing -> exitWith (ExitFailure 1)
61 -- Quit with error code if there was a problem
63 Just _ -> exitWith (ExitFailure 1)
65 -- Also give up if there are metavariables to solve
66 case (map fst (idris_metavars ist) \\ primDefs) of
67 _ -> when install $ installPkg pkgdesc
69-- then putStrLn "Can't install: there are undefined metavariables:"
70-- else putStrLn "There are undefined metavariables:"
71-- putStrLn $ "\t" ++ show ms
72-- exitWith (ExitFailure 1)
74-- | Type check packages only
76-- This differs from build in that executables are not built, if the
77-- package contains an executable.
78checkPkg :: Bool -- ^ Show Warnings
79 -> Bool -- ^ quit on failure
80 -> FilePath -- ^ Path to ipkg file.
82checkPkg warnonly quit fpath
83 = do pkgdesc <- parseDesc fpath
84 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
86 do dir <- getCurrentDirectory
87 setCurrentDirectory $ dir </> sourcedir pkgdesc
88 make (makefile pkgdesc)
89 res <- buildMods (NoREPL : Verbose : idris_opts pkgdesc)
91 setCurrentDirectory dir
92 when quit $ case res of
93 Nothing -> exitWith (ExitFailure 1)
96 Just _ -> exitWith (ExitFailure 1)
99-- | Check a package and start a REPL
100replPkg :: FilePath -> Idris ()
101replPkg fp = do orig <- getIState
102 runIO $ checkPkg False False fp
103 pkgdesc <- runIO $ parseDesc fp -- bzzt, repetition!
104 let opts = idris_opts pkgdesc
105 let mod = idris_main pkgdesc
106 let f = toPath (showCG mod)
108 dir <- runIO $ getCurrentDirectory
109 runIO $ setCurrentDirectory $ dir </> sourcedir pkgdesc
112 then idrisMain ((Filename f) : opts)
113 else iputStrLn "Can't start REPL: no main module given"
114 runIO $ setCurrentDirectory dir
116 where toPath n = foldl1' (</>) $ splitOn "." n
118-- | Clean Package build files
119cleanPkg :: FilePath -- ^ Path to ipkg file.
122 = do pkgdesc <- parseDesc fp
123 dir <- getCurrentDirectory
124 setCurrentDirectory $ dir </> sourcedir pkgdesc
125 clean (makefile pkgdesc)
126 mapM_ rmIBC (modules pkgdesc)
127 case execout pkgdesc of
129 Just s -> rmFile $ dir </> s
131-- | Generate IdrisDoc for package
132-- TODO: Handle case where module does not contain a matching namespace
133-- E.g. from prelude.ipkg: IO, Prelude.Chars, Builtins
134documentPkg :: FilePath -- ^ Path to .ipkg file.
137 do pkgdesc <- parseDesc fp
138 cd <- getCurrentDirectory
139 let pkgDir = cd </> takeDirectory fp
140 outputDir = cd </> (pkgname pkgdesc) ++ "_doc"
141 opts = NoREPL : Verbose : idris_opts pkgdesc
142 mods = modules pkgdesc
143 fs = map (foldl1' (</>) . splitOn "." . showCG) mods
144 setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
145 make (makefile pkgdesc)
146 setCurrentDirectory $ pkgDir
147 let run l = runErrorT . (execStateT l)
149 load (f:fs) = do loadModule stdout f; load fs
150 loader = do idrisMain opts; load fs
151 idrisInstance <- run loader idrisInit
152 setCurrentDirectory cd
153 case idrisInstance of
154 Left err -> do putStrLn $ pshow idrisInit err; exitWith (ExitFailure 1)
156 do docRes <- generateDocs ist mods outputDir
159 Left msg -> do putStrLn msg
160 exitWith (ExitFailure 1)
162-- | Build a package with a sythesized main function that runs the tests
163testPkg :: FilePath -> IO ()
165 = do pkgdesc <- parseDesc fp
166 ok <- mapM (testLib True (pkgname pkgdesc)) (libdeps pkgdesc)
168 do dir <- getCurrentDirectory
169 setCurrentDirectory $ dir </> sourcedir pkgdesc
170 make (makefile pkgdesc)
171 -- Get a temporary file to save the tests' source in
172 (tmpn, tmph) <- tempIdr
174 "module Test_______\n" ++
175 concat ["import " ++ show m ++ "\n"
176 | m <- modules pkgdesc] ++
177 "namespace Main\n" ++
180 concat [show t ++ "\n "
181 | t <- idris_tests pkgdesc]
183 (tmpn', tmph') <- tempfile
185 m_ist <- idris (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
187 setCurrentDirectory dir
189 Nothing -> exitWith (ExitFailure 1)
191 -- Quit with error code if problem building
193 Just _ -> exitWith (ExitFailure 1)
195 where tempIdr :: IO (FilePath, Handle)
196 tempIdr = do dir <- getTemporaryDirectory
197 openTempFile (normalise dir) "idristests.idr"
200installPkg :: PkgDesc -> IO ()
202 = do dir <- getCurrentDirectory
203 setCurrentDirectory $ dir </> sourcedir pkgdesc
204 case (execout pkgdesc) of
205 Nothing -> mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
206 Just o -> return () -- do nothing, keep executable locally, for noe
207 mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
209-- ---------------------------------------------------------- [ Helper Methods ]
210-- Methods for building, testing, installing, and removal of idris
213buildMods :: [Opt] -> [Name] -> IO (Maybe IState)
214buildMods opts ns = do let f = map (toPath . showCG) ns
215-- putStrLn $ "MODULE: " ++ show f
216 idris (map Filename f ++ opts)
217 where toPath n = foldl1' (</>) $ splitOn "." n
219testLib :: Bool -> String -> String -> IO Bool
223 (tmpf, tmph) <- tempfile
225 let libtest = d </> "rts" </> "libtest.c"
226 e <- system $ gcc ++ " " ++ libtest ++ " -l" ++ f ++ " -o " ++ tmpf
228 ExitSuccess -> return True
230 then do putStrLn $ "Not building " ++ p ++
231 " due to missing library " ++ f
233 else fail $ "Missing library " ++ f
235rmIBC :: Name -> IO ()
236rmIBC m = rmFile $ toIBCFile m
238toIBCFile (UN n) = str n ++ ".ibc"
239toIBCFile (NS n ns) = foldl1' (</>) (reverse (toIBCFile n : map str ns))
241installIBC :: String -> Name -> IO ()
242installIBC p m = do let f = toIBCFile m
244 let destdir = d </> p </> getDest m
245 putStrLn $ "Installing " ++ f ++ " to " ++ destdir
246 createDirectoryIfMissing True destdir
247 copyFile f (destdir </> takeFileName f)
249 where getDest (UN n) = ""
250 getDest (NS n ns) = foldl1' (</>) (reverse (getDest n : map str ns))
253installObj :: String -> String -> IO ()
254installObj p o = do d <- getTargetDir
255 let destdir = addTrailingPathSeparator (d </> p)
256 putStrLn $ "Installing " ++ o ++ " to " ++ destdir
257 createDirectoryIfMissing True destdir
258 copyFile o (destdir </> takeFileName o)
261#ifdef mingw32_HOST_OS
264mkDirCmd = "mkdir -p "
267-- ------------------------------------------------------- [ Makefile Commands ]
268-- | Invoke a Makefile's default target.
269make :: Maybe String -> IO ()
270make Nothing = return ()
271make (Just s) = do system $ "make -f " ++ s
274-- | Invoke a Makefile's clean target.
275clean :: Maybe String -> IO ()
276clean Nothing = return ()
277clean (Just s) = do system $ "make -f " ++ s ++ " clean"
280-- --------------------------------------------------------------------- [ EOF ]
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