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 let idx = PkgIndex (pkgIndex (pkgname pkgdesc))
46 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
48 do dir <- getCurrentDirectory
49 setCurrentDirectory $ dir </> sourcedir pkgdesc
50 make (makefile pkgdesc)
51 m_ist <- 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)
58 setCurrentDirectory dir
60 Nothing -> exitWith (ExitFailure 1)
62 -- Quit with error code if there was a problem
64 Just _ -> exitWith (ExitFailure 1)
66 when install $ installPkg pkgdesc
68-- | Type check packages only
70-- This differs from build in that executables are not built, if the
71-- package contains an executable.
72checkPkg :: Bool -- ^ Show Warnings
73 -> Bool -- ^ quit on failure
74 -> FilePath -- ^ Path to ipkg file.
76checkPkg warnonly quit fpath
77 = do pkgdesc <- parseDesc fpath
78 ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
80 do dir <- getCurrentDirectory
81 setCurrentDirectory $ dir </> sourcedir pkgdesc
82 make (makefile pkgdesc)
83 res <- buildMods (NoREPL : Verbose : idris_opts pkgdesc)
85 setCurrentDirectory dir
86 when quit $ case res of
87 Nothing -> exitWith (ExitFailure 1)
90 Just _ -> exitWith (ExitFailure 1)
93-- | Check a package and start a REPL
94replPkg :: FilePath -> Idris ()
95replPkg fp = do orig <- getIState
96 runIO $ checkPkg False False fp
97 pkgdesc <- runIO $ parseDesc fp -- bzzt, repetition!
98 let opts = idris_opts pkgdesc
99 let mod = idris_main pkgdesc
100 let f = toPath (showCG mod)
102 dir <- runIO $ getCurrentDirectory
103 runIO $ setCurrentDirectory $ dir </> sourcedir pkgdesc
106 then idrisMain ((Filename f) : opts)
107 else iputStrLn "Can't start REPL: no main module given"
108 runIO $ setCurrentDirectory dir
110 where toPath n = foldl1' (</>) $ splitOn "." n
112-- | Clean Package build files
113cleanPkg :: FilePath -- ^ Path to ipkg file.
116 = do pkgdesc <- parseDesc fp
117 dir <- getCurrentDirectory
118 setCurrentDirectory $ dir </> sourcedir pkgdesc
119 clean (makefile pkgdesc)
120 mapM_ rmIBC (modules pkgdesc)
121 rmIdx (pkgname pkgdesc)
122 case execout pkgdesc of
124 Just s -> rmFile $ dir </> s
126-- | Generate IdrisDoc for package
127-- TODO: Handle case where module does not contain a matching namespace
128-- E.g. from prelude.ipkg: IO, Prelude.Chars, Builtins
130-- Issue number #1572 on the issue tracker
131-- https://github.com/idris-lang/Idris-dev/issues/1572
132documentPkg :: FilePath -- ^ Path to .ipkg file.
135 do pkgdesc <- parseDesc fp
136 cd <- getCurrentDirectory
137 let pkgDir = cd </> takeDirectory fp
138 outputDir = cd </> (pkgname pkgdesc) ++ "_doc"
139 opts = NoREPL : Verbose : idris_opts pkgdesc
140 mods = modules pkgdesc
141 fs = map (foldl1' (</>) . splitOn "." . showCG) mods
142 setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
143 make (makefile pkgdesc)
144 setCurrentDirectory $ pkgDir
145 let run l = runExceptT . execStateT l
147 load (f:fs) = do loadModule f; load fs
148 loader = do idrisMain opts; load fs
149 idrisInstance <- run loader idrisInit
150 setCurrentDirectory cd
151 case idrisInstance of
152 Left err -> do putStrLn $ pshow idrisInit err; exitWith (ExitFailure 1)
154 do docRes <- generateDocs ist mods outputDir
157 Left msg -> do putStrLn msg
158 exitWith (ExitFailure 1)
160-- | Build a package with a sythesized main function that runs the tests
161testPkg :: FilePath -> IO ()
163 = do pkgdesc <- parseDesc fp
164 ok <- mapM (testLib True (pkgname pkgdesc)) (libdeps pkgdesc)
166 do dir <- getCurrentDirectory
167 setCurrentDirectory $ dir </> sourcedir pkgdesc
168 make (makefile pkgdesc)
169 -- Get a temporary file to save the tests' source in
170 (tmpn, tmph) <- tempIdr
172 "module Test_______\n" ++
173 concat ["import " ++ show m ++ "\n"
174 | m <- modules pkgdesc] ++
175 "namespace Main\n" ++
178 concat [show t ++ "\n "
179 | t <- idris_tests pkgdesc]
181 (tmpn', tmph') <- tempfile
183 m_ist <- idris (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
185 setCurrentDirectory dir
187 Nothing -> exitWith (ExitFailure 1)
189 -- Quit with error code if problem building
191 Just _ -> exitWith (ExitFailure 1)
193 where tempIdr :: IO (FilePath, Handle)
194 tempIdr = do dir <- getTemporaryDirectory
195 openTempFile (normalise dir) "idristests.idr"
198installPkg :: PkgDesc -> IO ()
200 = do dir <- getCurrentDirectory
201 setCurrentDirectory $ dir </> sourcedir pkgdesc
202 case (execout pkgdesc) of
203 Nothing -> do mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
204 installIdx (pkgname pkgdesc)
205 Just o -> return () -- do nothing, keep executable locally, for noe
206 mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
208-- ---------------------------------------------------------- [ Helper Methods ]
209-- Methods for building, testing, installing, and removal of idris
212buildMods :: [Opt] -> [Name] -> IO (Maybe IState)
213buildMods opts ns = do let f = map (toPath . showCG) ns
214 idris (map Filename f ++ opts)
215 where toPath n = foldl1' (</>) $ splitOn "." n
217testLib :: Bool -> String -> String -> IO Bool
221 (tmpf, tmph) <- tempfile
223 let libtest = d </> "rts" </> "libtest.c"
224 e <- rawSystem gcc [libtest, "-l" ++ f, "-o", tmpf]
226 ExitSuccess -> return True
228 then do putStrLn $ "Not building " ++ p ++
229 " due to missing library " ++ f
231 else fail $ "Missing library " ++ f
233rmIBC :: Name -> IO ()
234rmIBC m = rmFile $ toIBCFile m
236rmIdx :: String -> IO ()
237rmIdx p = do let f = pkgIndex p
238 ex <- doesFileExist f
241toIBCFile (UN n) = str n ++ ".ibc"
242toIBCFile (NS n ns) = foldl1' (</>) (reverse (toIBCFile n : map str ns))
244installIBC :: String -> Name -> IO ()
245installIBC p m = do let f = toIBCFile m
247 let destdir = d </> p </> getDest m
248 putStrLn $ "Installing " ++ f ++ " to " ++ destdir
249 createDirectoryIfMissing True destdir
250 copyFile f (destdir </> takeFileName f)
252 where getDest (UN n) = ""
253 getDest (NS n ns) = foldl1' (</>) (reverse (getDest n : map str ns))
255installIdx :: String -> IO ()
256installIdx p = do d <- getTargetDir
258 let destdir = d </> p
259 putStrLn $ "Installing " ++ f ++ " to " ++ destdir
260 createDirectoryIfMissing True destdir
261 copyFile f (destdir </> takeFileName f)
264installObj :: String -> String -> IO ()
265installObj p o = do d <- getTargetDir
266 let destdir = addTrailingPathSeparator (d </> p)
267 putStrLn $ "Installing " ++ o ++ " to " ++ destdir
268 createDirectoryIfMissing True destdir
269 copyFile o (destdir </> takeFileName o)
272#ifdef mingw32_HOST_OS
275mkDirCmd = "mkdir -p "
278-- ------------------------------------------------------- [ Makefile Commands ]
279-- | Invoke a Makefile's default target.
280make :: Maybe String -> IO ()
281make Nothing = return ()
282make (Just s) = do rawSystem "make" ["-f", s]
285-- | Invoke a Makefile's clean target.
286clean :: Maybe String -> IO ()
287clean Nothing = return ()
288clean (Just s) = do rawSystem "make" ["-f", s, "clean"]
291-- --------------------------------------------------------------------- [ 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