packages feed

idris-0.9.4: src/Pkg/Package.hs

module Pkg.Package where

import System.Process
import System.Directory
import System.Exit
import System.IO

import Util.System

import Control.Monad
import Data.List

import Core.TT
import Idris.REPL
import Idris.AbsSyntax

import Pkg.PParser

import Paths_idris

-- To build a package:
-- * read the package description
-- * check all the library dependencies exist
-- * invoke the makefile if there is one
-- * invoke idris on each module, with idris_opts
-- * install everything into datadir/pname, if install flag is set

buildPkg :: Bool -> (Bool, FilePath) -> IO ()
buildPkg warnonly (install, fp) 
     = do pkgdesc <- parseDesc fp
          ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
          when (and ok) $
            do make (makefile pkgdesc)
               dir <- getCurrentDirectory
               setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
               case (execout pkgdesc) of
                   Nothing -> buildMods (NoREPL : Verbose : idris_opts pkgdesc)
                                    (modules pkgdesc)
                   Just o -> do let exec = dir ++ "/" ++ o
                                buildMod 
                                    (NoREPL : Verbose : Output exec : idris_opts pkgdesc) 
                                    (idris_main pkgdesc)
               setCurrentDirectory dir
               when install $ installPkg pkgdesc

cleanPkg :: FilePath -> IO ()
cleanPkg fp 
     = do pkgdesc <- parseDesc fp
          clean (makefile pkgdesc)
          dir <- getCurrentDirectory
          setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
          mapM_ rmIBC (modules pkgdesc)
          case execout pkgdesc of
               Nothing -> return ()
               Just s -> do let exec = dir ++ "/" ++ s
                            putStrLn $ "Removing " ++ exec
                            system $ "rm -f " ++ exec 
                            return ()

installPkg :: PkgDesc -> IO ()
installPkg pkgdesc
     = do dir <- getCurrentDirectory
          setCurrentDirectory $ dir ++ "/" ++ sourcedir pkgdesc
          case (execout pkgdesc) of
              Nothing -> mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
              Just o -> return () -- do nothing, keep executable locally, for noe
          mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)

buildMod :: [Opt] -> Name -> IO ()
buildMod opts n = do let f = map slash $ show n
                     idris (Filename f : opts) 
                     return ()
    where slash '.' = '/'
          slash x = x

buildMods :: [Opt] -> [Name] -> IO ()
buildMods opts ns = do let f = map ((map slash) . show) ns
                       idris (map Filename f ++ opts) 
                       return ()
    where slash '.' = '/'
          slash x = x

testLib :: Bool -> String -> String -> IO Bool
testLib warn p f 
    = do d <- getDataDir
         gcc <- getCC
         (tmpf, tmph) <- tempfile
         hClose tmph
         e <- system $ gcc ++ " " ++ d ++ "/rts/libtest.c -l" ++ f ++ " -o " ++ tmpf
         case e of
            ExitSuccess -> return True
            _ -> do if warn 
                       then do putStrLn $ "Not building " ++ p ++ 
                                          " due to missing library " ++ f
                               return False
                       else fail $ "Missing library " ++ f

rmIBC :: Name -> IO ()
rmIBC m = do let f = toIBCFile m 
             putStrLn $ "Removing " ++ f
             system $ "rm -f " ++ f
             return ()
             
toIBCFile (UN n) = n ++ ".ibc"
toIBCFile (NS n ns) = concat (intersperse "/" (reverse ns)) ++ "/" ++ toIBCFile n 

installIBC :: String -> Name -> IO ()
installIBC p m = do let f = toIBCFile m
                    d <- getDataDir
                    let destdir = d ++ "/" ++ p ++ "/" ++ getDest m
                    putStrLn $ "Installing " ++ f ++ " to " ++ destdir
                    system $ "mkdir -p " ++ destdir 
                    system $ "install " ++ f ++ " " ++ destdir
                    return ()
    where getDest (UN n) = ""
          getDest (NS n ns) = concat (intersperse "/" (reverse ns)) ++ "/" ++ getDest n 

installObj :: String -> String -> IO ()
installObj p o = do d <- getDataDir
                    let destdir = d ++ "/" ++ p ++ "/"
                    putStrLn $ "Installing " ++ o ++ " to " ++ destdir
                    system $ "mkdir -p " ++ destdir 
                    system $ "install " ++ o ++ " " ++ destdir
                    return ()

make :: Maybe String -> IO ()
make Nothing = return ()
make (Just s) = do system $ "make -f " ++ s
                   return ()

clean :: Maybe String -> IO ()
clean Nothing = return ()
clean (Just s) = do system $ "make -f " ++ s ++ " clean"
                    return ()