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.Trans.Except (runExceptT)
18import Data.List.Split(splitOn)
22import Idris.Parser (loadModule)
23import Idris.Output (pshow)
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 dir <- getCurrentDirectory
46 let idx = PkgIndex (pkgIndex (pkgname pkgdesc))
47 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
49 do m_ist <- inPkgDir pkgdesc $
50 do make (makefile pkgdesc)
51 case (execout pkgdesc) of
52 Nothing -> buildMods (idx : NoREPL : Verbose : idris_opts pkgdesc)
54 Just o -> do let exec = dir </> o
56 (idx : NoREPL : Verbose : Output exec : idris_opts pkgdesc)
59 Nothing -> exitWith (ExitFailure 1)
61 -- Quit with error code if there was a problem
63 Just _ -> exitWith (ExitFailure 1)
65 when install $ installPkg pkgdesc
67-- | Type check packages only
69-- This differs from build in that executables are not built, if the
70-- package contains an executable.
71checkPkg :: Bool -- ^ Show Warnings
72 -> Bool -- ^ quit on failure
73 -> FilePath -- ^ Path to ipkg file.
75checkPkg warnonly quit fpath
76 = do pkgdesc <- parseDesc fpath
77 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
79 do res <- inPkgDir pkgdesc $
80 do make (makefile pkgdesc)
81 buildMods (NoREPL : Verbose : idris_opts pkgdesc)
83 when quit $ case res of
84 Nothing -> exitWith (ExitFailure 1)
87 Just _ -> exitWith (ExitFailure 1)
90-- | Check a package and start a REPL
91replPkg :: FilePath -> Idris ()
92replPkg fp = do orig <- getIState
93 runIO $ checkPkg False False fp
94 pkgdesc <- runIO $ parseDesc fp -- bzzt, repetition!
95 let opts = idris_opts pkgdesc
96 let mod = idris_main pkgdesc
97 let f = toPath (showCG mod)
99 dir <- runIO $ getCurrentDirectory
100 runIO $ setCurrentDirectory $ dir </> sourcedir pkgdesc
103 then idrisMain ((Filename f) : opts)
104 else iputStrLn "Can't start REPL: no main module given"
105 runIO $ setCurrentDirectory dir
107 where toPath n = foldl1' (</>) $ splitOn "." n
109-- | Clean Package build files
110cleanPkg :: FilePath -- ^ Path to ipkg file.
113 = do pkgdesc <- parseDesc fp
114 dir <- getCurrentDirectory
116 do clean (makefile pkgdesc)
117 mapM_ rmIBC (modules pkgdesc)
118 rmIdx (pkgname pkgdesc)
119 case execout pkgdesc of
121 Just s -> rmFile $ dir </> s
123-- | Generate IdrisDoc for package
124-- TODO: Handle case where module does not contain a matching namespace
125-- E.g. from prelude.ipkg: IO, Prelude.Chars, Builtins
127-- Issue number #1572 on the issue tracker
128-- https://github.com/idris-lang/Idris-dev/issues/1572
129documentPkg :: FilePath -- ^ Path to .ipkg file.
132 do pkgdesc <- parseDesc fp
133 cd <- getCurrentDirectory
134 let pkgDir = cd </> takeDirectory fp
135 outputDir = cd </> (pkgname pkgdesc) ++ "_doc"
136 opts = NoREPL : Verbose : idris_opts pkgdesc
137 mods = modules pkgdesc
138 fs = map (foldl1' (</>) . splitOn "." . showCG) mods
139 setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
140 make (makefile pkgdesc)
141 setCurrentDirectory $ pkgDir
142 let run l = runExceptT . execStateT l
144 load (f:fs) = do loadModule f; load fs
145 loader = do idrisMain opts; load fs
146 idrisInstance <- run loader idrisInit
147 setCurrentDirectory cd
148 case idrisInstance of
149 Left err -> do putStrLn $ pshow idrisInit err; exitWith (ExitFailure 1)
151 do docRes <- generateDocs ist mods outputDir
154 Left msg -> do putStrLn msg
155 exitWith (ExitFailure 1)
157-- | Build a package with a sythesized main function that runs the tests
158testPkg :: FilePath -> IO ()
160 = do pkgdesc <- parseDesc fp
161 ok <- mapM (testLib True (pkgname pkgdesc)) (libdeps pkgdesc)
163 do m_ist <- inPkgDir pkgdesc $
164 do make (makefile pkgdesc)
165 -- Get a temporary file to save the tests' source in
166 (tmpn, tmph) <- tempIdr
168 "module Test_______\n" ++
169 concat ["import " ++ show m ++ "\n"
170 | m <- modules pkgdesc] ++
171 "namespace Main\n" ++
174 concat [show t ++ "\n "
175 | t <- idris_tests pkgdesc]
177 (tmpn', tmph') <- tempfile
179 m_ist <- idris (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
183 Nothing -> exitWith (ExitFailure 1)
185 -- Quit with error code if problem building
187 Just _ -> exitWith (ExitFailure 1)
189 where tempIdr :: IO (FilePath, Handle)
190 tempIdr = do dir <- getTemporaryDirectory
191 openTempFile (normalise dir) "idristests.idr"
194installPkg :: PkgDesc -> IO ()
197 do case (execout pkgdesc) of
198 Nothing -> do mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
199 installIdx (pkgname pkgdesc)
200 Just o -> return () -- do nothing, keep executable locally, for noe
201 mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
203-- ---------------------------------------------------------- [ Helper Methods ]
204-- Methods for building, testing, installing, and removal of idris
207buildMods :: [Opt] -> [Name] -> IO (Maybe IState)
208buildMods opts ns = do let f = map (toPath . showCG) ns
209 idris (map Filename f ++ opts)
210 where toPath n = foldl1' (</>) $ splitOn "." n
212testLib :: Bool -> String -> String -> IO Bool
216 (tmpf, tmph) <- tempfile
218 let libtest = d </> "rts" </> "libtest.c"
219 e <- rawSystem gcc [libtest, "-l" ++ f, "-o", tmpf]
221 ExitSuccess -> return True
223 then do putStrLn $ "Not building " ++ p ++
224 " due to missing library " ++ f
226 else fail $ "Missing library " ++ f
228rmIBC :: Name -> IO ()
229rmIBC m = rmFile $ toIBCFile m
231rmIdx :: String -> IO ()
232rmIdx p = do let f = pkgIndex p
233 ex <- doesFileExist f
236toIBCFile (UN n) = str n ++ ".ibc"
237toIBCFile (NS n ns) = foldl1' (</>) (reverse (toIBCFile n : map str ns))
239installIBC :: String -> Name -> IO ()
240installIBC p m = do let f = toIBCFile m
242 let destdir = d </> p </> getDest m
243 putStrLn $ "Installing " ++ f ++ " to " ++ destdir
244 createDirectoryIfMissing True destdir
245 copyFile f (destdir </> takeFileName f)
247 where getDest (UN n) = ""
248 getDest (NS n ns) = foldl1' (</>) (reverse (getDest n : map str ns))
250installIdx :: String -> IO ()
251installIdx p = do d <- getTargetDir
253 let destdir = d </> p
254 putStrLn $ "Installing " ++ f ++ " to " ++ destdir
255 createDirectoryIfMissing True destdir
256 copyFile f (destdir </> takeFileName f)
259installObj :: String -> String -> IO ()
260installObj p o = do d <- getTargetDir
261 let destdir = addTrailingPathSeparator (d </> p)
262 putStrLn $ "Installing " ++ o ++ " to " ++ destdir
263 createDirectoryIfMissing True destdir
264 copyFile o (destdir </> takeFileName o)
267#ifdef mingw32_HOST_OS
270mkDirCmd = "mkdir -p "
273inPkgDir :: PkgDesc -> IO a -> IO a
274inPkgDir pkgdesc action =
275 do dir <- getCurrentDirectory
276 when (sourcedir pkgdesc /= "") $
277 do putStrLn $ "Entering directory `" ++ ("." </> sourcedir pkgdesc) ++ "'"
278 setCurrentDirectory $ dir </> sourcedir pkgdesc
280 when (sourcedir pkgdesc /= "") $
281 do putStrLn $ "Leaving directory `" ++ ("." </> sourcedir pkgdesc) ++ "'"
282 setCurrentDirectory dir
285-- ------------------------------------------------------- [ Makefile Commands ]
286-- | Invoke a Makefile's default target.
287make :: Maybe String -> IO ()
288make Nothing = return ()
289make (Just s) = do rawSystem "make" ["-f", s]
292-- | Invoke a Makefile's clean target.
293clean :: Maybe String -> IO ()
294clean Nothing = return ()
295clean (Just s) = do rawSystem "make" ["-f", s, "clean"]
298-- --------------------------------------------------------------------- [ 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