11module Install where
22import Control.Monad
3+ import Data.List
34import Data.Maybe
45import Data.Word
56import Foreign.Storable
67import Foreign.Marshal.Utils
78import Foreign.Ptr
89import System.Directory
9- import System.Envirinment
10+ import System.Environment
1011import System.FilePath
1112import System.Process
1213import MicroHs.Config
1314
1415type CConf = [(Key , Value )]
1516
16- theConfig :: String
17- theConfig | _isWindows = " windows"
18- | otherwise = " unix"
19-
20- rts :: String
21- rts = " src" </> " runtime"
22-
23- doIt :: Bool
24- doIt = False
2517
2618main :: IO ()
2719main = do
2820 args <- getArgs
2921 let flags = decodeArgs defaultFlags args
22+ confText <- macroExpand flags <$> readFile (confFile flags)
3023 home <- getHomeDirectory
31- confText <- readFile (confFile flags)
3224 let conf = either (\ s -> error $ " cannot parse config " ++ s) id $
33- parseConfig confFile confText
34- cconf = fromMaybe (error $ " Cannot locate section " ++ theConfig) $
35- lookup theConfig conf
36- mcabal = home </> " .mcabal"
37- mcabalBin = mcabal </> " bin"
25+ parseConfig (confFile flags) confText
26+ cc = fromMaybe (error $ " Cannot locate section " ++ target flags) $
27+ lookup (target flags) conf
28+ exe | target flags == " windows" = " exe"
29+ | otherwise = " "
30+ inst = fromMaybe (home </> " .mcabal" ) (instDirM flags)
31+ flags' = flags { exeSuffix = exe, cconf = cc, instDir = inst, conf = confText }
32+
33+ install flags
34+
35+ install :: Flags -> IO ()
36+ install flags = do
37+ instBin flags
38+ vers <- init <$> mhsOut flags [" --numeric-version" ]
39+ let flags' = flags { version = vers }
40+ mkMachdep flags'
41+ mkConf flags
42+ copyRTS flags'
43+ copyBase flags'
44+ checkPath flags'
45+
46+ instBin :: Flags -> IO ()
47+ instBin flags = do
48+ let mCabal = instDir flags
49+ mcabalBin = mCabal </> " bin"
3850 exes = [" mhs" , " cpphs" , " mcabal" ]
39- --
40- mkdir " bin "
41- mapM_ (buildBin cconf) exes
42- machdep $ rts </> " MachDeps.h "
43- mkdir mcabalBin
44- let cpbin pgm = let exe = pgm <.> exeSuffix in copy (" bin" </> exe) (mcabalBin </> exe)
51+ mkdir flags " bin "
52+ mapM_ (buildBin flags) exes
53+ mkdir flags mcabalBin
54+ let cpbin pgm = do
55+ let exe = pgm <.> exeSuffix flags
56+ copy flags (" bin" </> exe) (mcabalBin </> exe)
4557 mapM_ cpbin exes
46- version <- init <$> mhsOut [" --numeric-version" ]
47- let mCabalMhs = mcabal </> (" mhs-" ++ version)
48- mData = mCabalMhs </> " packages" </> (" mhs-" ++ version) </> " data"
49- mkdir mData
50- copy " mhs.conf" (mData </> " mhs.conf" )
51- copyDir rts (mData </> rts)
52-
53- {-
54- MCABALMHS=$(MCABAL)/mhs-$(VERSION)
55- MDATA=$(MCABALMHS)/packages/mhs-$(VERSION)/data
56- MRUNTIME=$(MDATA)/$(RTS)
57- cp -r $(RTS)/* $(MRUNTIME)
58- @mkdir -p $(MCABALMHS)
59- bin/mhs -Q generated/base.pkg $(MCABALMHS)
60- @echo $$PATH | tr ':' '\012' | grep -q $(MCABALBIN) || echo '***' Add $(MCABALBIN) to the PATH
61- -}
62-
63- buildBin :: CConf -> String -> IO ()
64- buildBin cconf pgm = do
58+
59+ mkMachdep :: Flags -> IO ()
60+ mkMachdep flags =
61+ machdep flags $ " src" </> " runtime" </> " MachDeps.h"
62+
63+ mkConf :: Flags -> IO ()
64+ mkConf flags = do
65+ msg flags $ " create mhs.conf"
66+ unless (dryRun flags) $
67+ writeFile " mhs.conf" (conf flags)
68+
69+ copyRTS :: Flags -> IO ()
70+ copyRTS flags = do
71+ let mCabalMhs = instDir flags </> (" mhs-" ++ version flags)
72+ let mData = mCabalMhs </> " packages" </> (" mhs-" ++ version flags) </> " data"
73+ rts = " src" </> " runtime"
74+ mkdir flags mData
75+ copy flags " mhs.conf" (mData </> " mhs.conf" )
76+ copyDir flags rts (mData </> rts)
77+
78+ copyBase :: Flags -> IO ()
79+ copyBase flags = do
80+ let mCabalMhs = instDir flags </> (" mhs-" ++ version flags)
81+ mkdir flags mCabalMhs
82+ out <- mhsOut flags [" -Q" , " generated" </> " base.pkg" , mCabalMhs]
83+ msg flags out
84+
85+ checkPath :: Flags -> IO ()
86+ checkPath flags = do
87+ path <- fromMaybe " " <$> lookupEnv " PATH"
88+ let paths = splitOn pathSep path
89+ pathSep | target flags == " windows" = " ;"
90+ | otherwise = " :"
91+ bin = instDir flags </> bin
92+ when (bin `notElem` paths) $
93+ putStrLn $ " Please add " ++ bin ++ " to your PATH"
94+
95+ buildBin :: Flags -> String -> IO ()
96+ buildBin flags pgm = do
6597 let src = " generated" </> pgm <.> " .c"
66- dst = " bin" </> pgm <.> exeSuffix
67- cc cconf [get cconf " ccflags" , " -I" ++ rts, " -I" ++ (rts </> get cconf " conf" ),
98+ dst = " bin" </> pgm <.> exeSuffix flags
99+ ccf = cconf flags
100+ rts = " src" </> " runtime"
101+ cc flags [get ccf " ccflags" , " -I" ++ rts, " -I" ++ (rts </> get ccf " conf" ),
68102 rts </> " main.c" , rts </> " eval.c" ,
69- src, get cconf " cclibs" , getD cconf " -o" " cout" ++ dst]
103+ src, get ccf " cclibs" , getD ccf " -o" " cout" ++ dst]
70104
71- mhsOut :: [String ] -> IO String
72- mhsOut args =
73- readProcess (" bin" </> " mhs" <.> exeSuffix) args " "
105+ mhsOut :: Flags -> [String ] -> IO String
106+ mhsOut flags args = do
107+ let exe = " bin" </> " mhs" <.> exeSuffix flags
108+ msg flags $ unwords (exe: args)
109+ if dryRun flags then
110+ return " MHSOUT"
111+ else
112+ readProcess exe args " "
74113
75114-----
76115
@@ -82,33 +121,30 @@ get cconf key = getD cconf (error $ "Cannot find " ++ key) key
82121
83122-----
84123
85- cc :: CConf -> [String ] -> IO ()
86- cc cconf args = do
87- let c = get cconf " cc"
88- msg $ unwords (c : args)
89- when doIt $
124+ cc :: Flags -> [String ] -> IO ()
125+ cc flags args = do
126+ let c = get ( cconf flags) " cc"
127+ msg flags $ unwords (c : args)
128+ unless (dryRun flags) $
90129 callProcess c args
91130
92- exeSuffix :: String
93- exeSuffix | _isWindows = " exe"
94- | otherwise = " "
95-
96- msg :: String -> IO ()
97- msg s = putStrLn s
131+ msg :: Flags -> String -> IO ()
132+ msg flags s | not (quiet flags) = putStrLn s
133+ | otherwise = return ()
98134
99135-----
100136
101- mkdir :: FilePath -> IO ()
102- mkdir dir = do
103- msg $ " mkdir " ++ dir
104- when doIt $
137+ mkdir :: Flags -> FilePath -> IO ()
138+ mkdir flags dir = do
139+ msg flags $ " mkdir " ++ dir
140+ unless (dryRun flags) $
105141 createDirectoryIfMissing True dir
106142
107- machdep :: FilePath -> IO ()
108- machdep name = do
109- msg $ " create " ++ name
143+ machdep :: Flags -> FilePath -> IO ()
144+ machdep flags name = do
145+ msg flags $ " create " ++ name
110146 big <- isBigEndian
111- when doIt $
147+ unless (dryRun flags) $
112148 writeFile name $ unlines
113149 [ " #define WORD_SIZE_IN_BITS " ++ show _wordSize
114150 , (if big then " #define" else " #undef" ) ++ " WORDS_BIGENDIAN"
@@ -122,54 +158,90 @@ isBigEndian = do
122158 b <- peek (castPtr p :: Ptr Word8 )
123159 return (b == 1 )
124160
125- copy :: FilePath -> FilePath -> IO ()
126- copy src dst = do
127- msg $ unwords [" cp" , src, dst]
128- when doIt $ do
161+ copy :: Flags -> FilePath -> FilePath -> IO ()
162+ copy flags src dst = do
163+ msg flags $ unwords [" cp" , src, dst]
164+ unless (dryRun flags) $ do
129165 copyFile src dst
130166 copyPermissions src dst
131167
132- copyDir :: FilePath -> FilePath -> IO ()
133- copyDir src dst = do
134- mkdir dst
168+ copyDir :: Flags -> FilePath -> FilePath -> IO ()
169+ copyDir flags src dst = do
170+ mkdir flags dst
135171 let one file = do
136172 d <- doesDirectoryExist file
137- (if d then copyDir else copy) (src </> d ) (dst </> d )
173+ (if d then copyDir else copy) flags (src </> file ) (dst </> file )
138174 mapM_ one =<< listDirectory src
139175
176+ splitOn :: String -> String -> [String ]
177+ splitOn d = loop []
178+ where loop [] [] = []
179+ loop r [] = [reverse r]
180+ loop r s@ (c: cs) | Just s' <- stripPrefix d s = reverse r : loop [] s'
181+ | otherwise = loop (c: r) cs
182+
183+ macroExpand :: Flags -> String -> String
184+ macroExpand flags = loop
185+ where loop [] = []
186+ loop (' $' : cs) = p ++ loop r where (p, r) = expnd (macros flags) cs
187+ loop (c: cs) = c : loop cs
188+ expnd [] s = (" " , s)
189+ expnd ((m,e): ms) s | Just r <- stripPrefix m s = (e, r)
190+ | otherwise = expnd ms s
191+
140192-----
141193
142194data Flags = Flags
143- { target :: String
144- , dryRun :: Bool
145- , verbose :: Bool
146- , macros :: [String ]
147- , goals :: [String ]
148- , confFile :: FilePath
195+ { target :: String
196+ , dryRun :: Bool
197+ , verbose :: Bool
198+ , quiet :: Bool
199+ , macros :: [(String , String )]
200+ , goals :: [String ]
201+ , confFile :: FilePath
202+ , instDirM :: Maybe FilePath
203+ -- The rest are for internal use
204+ , exeSuffix :: String
205+ , instDir :: FilePath
206+ , cconf :: CConf
207+ , version :: String
208+ , conf :: String
149209 }
150210 deriving (Show )
151211
152212defaultFlags :: Flags
153- defaultFlags = Flags
154- { target = if _isWindows then " windows" else " unix"
155- , dryRun = False
156- , verbose = False
157- , macros = []
158- , goals = []
159- , confFile = " mhs.conf"
160- }
213+ defaultFlags =
214+ Flags
215+ { target = if _isWindows then " windows" else " unix"
216+ , dryRun = False
217+ , verbose = False
218+ , quiet = False
219+ , macros = []
220+ , goals = []
221+ , confFile = " mhs.conf.in"
222+ , instDirM = Nothing
223+ --
224+ , exeSuffix = undefined
225+ , instDir = undefined
226+ , cconf = undefined
227+ , version = undefined
228+ , conf = undefined
229+ }
161230
162231decodeArgs :: Flags -> [String ] -> Flags
163232decodeArgs f [] = f
164233decodeArgs f (arg: args) =
165234 case arg of
166235 " --help" -> error usage
167236 " -v" -> decodeArgs f{verbose = True } args
237+ " -q" -> decodeArgs f{quiet = True } args
168238 " --dryrun" -> decodeArgs f{dryRun = True } args
169- ' -' : ' t' : s -> decodeArgs f{target = s} mdls args
239+ ' -' : ' t' : s -> decodeArgs f{target = s} args
240+ ' -' : ' i' : s -> decodeArgs f{instDirM = Just s} args
170241 ' -' : _ -> error $ " Unknown flag: " ++ arg ++ " \n " ++ usage
171- _ | ' =' `elem` arg -> decodeArgs f{macros = macros f ++ [arg]} args
242+ _ | (m, ' =' : e) <- span (/= ' =' ) arg
243+ -> decodeArgs f{macros = macros f ++ [(m, e)]} args
172244 | otherwise -> decodeArgs f{goals = goals f ++ [arg]} args
173245
174246usage :: String
175- usage = " \n install [--help] [-v] [--dryrun] [-tTARGET] [NAME=MACRO] [GOAL]\n "
247+ usage = " \n install [--help] [-v] [--dryrun] [-tTARGET] [-iDIR] [ NAME=MACRO] [GOAL]\n "
0 commit comments