on master help sign in
Merge pull request #125 from ngunn/dev

Fix cabal install missing docs.json (followup)

commit91de71a8a2295eda1f37ccbfad54df81cae63a55 authorEvan Czaplicki <info@elm-lang.org> dateFri 22 Mar 2013, 11:13 (14 years ago) parent0034b17175f268
4 files changed+51−39
Elm.cabal−2 Setup.hs+28−12 compiler/Model/Libraries.hs+2−4 compiler/Model/LoadLibraries.hs+21−21
Elm.cabal−2
@@ -33,8 +33,6 @@ Library
3333 exposed-modules: Language.Elm,
3434 Language.Elm.Quasi
3535 Hs-Source-Dirs: compiler, compiler/Gen, compiler/Model, compiler/Transform
36− extensions: CPP
37− cpp-options: -DELM_COMPILEDATADIR="dist/data"
3836 other-modules: Ast,
3937 Context,
4038 CompileToJS,
Setup.hs+28−12
@@ -7,6 +7,7 @@ import System.Cmd
77import System.Directory
88import System.FilePath
99import System.IO
10+import System.Process
1011
1112import Control.Monad
1213
@@ -29,6 +30,7 @@ import Control.Monad
2930-- Assumptions
3031-- Elm.cabal expects the generated files to end up in dist/data
3132rtsDir lbi = (buildDir lbi) </> ".." </> "data" -- git won't look in dist + cabal will clean it
33+jsDir lbi = (buildDir lbi) </> ".." </> "js"
3234
3335-- The runtime is called:
3436rts lbi = (rtsDir lbi) </> "elm-runtime.js"
@@ -44,13 +46,6 @@ types lbi = (rtsDir lbi) </> "docs.json"
4446-- buildDir with LocalBuildInfo points to "dist/build" (usually)
4547elm lbi = (buildDir lbi) </> "elm" </> "elm"
4648
47−-- "touch" is available as a system command.
48−-- There is no portable file touch (unix-compat might work but leads to cabal library dependency
49−-- issues: see: http://hackage.haskell.org/trac/summer-of-code/ticket/1602 )
50−-- Files that need recompilation after docs.json is updated
51−-- (Would be nice if this list was in the cabal file, but can't see any way to do that)
52−docTouches = ["compiler" </> "Model" </> "LoadLibraries.hs"]
53−
5449-- Care! This appears to be based on an unstable API
5550-- See: http://www.haskell.org/cabal/release/cabal-latest/doc/API/Cabal/Distribution-Simple.html#2
5651
@@ -67,11 +62,17 @@ myBuild pd lbi uh bf = do
6762 withExe pd (\x -> putStrLn (exeName x))
6863 buildHook simpleUserHooks (filterExe elmDoc pd) (filterLBI elmDoc lbi) uh bf
6964 putStrLn "Custom build step started: build docs.json"
70− buildTypes lbi
71− forM_ docTouches (\s -> system ("touch " ++ s)) -- NB non-portable
65+ buildTypes lbi -- see note(1) below
7266 putStrLn "Custom build step started: compile everything"
7367 buildHook simpleUserHooks pd lbi uh bf
7468
69+-- note(1): We use to include docs.json directly into LoadLibraries at compile time
70+-- If docs.json is used in other (template) haskell files, they should be copied
71+-- and compiled in a separate directory (eg, dist/copiedSrc).
72+-- This is to make sure they are re-compiled on docs.json changes.
73+-- Copying is a better solution than 'touch'ing the source files
74+-- (touch is non-portable and confusing wrt RCS).
75+
7576-- In the PackageDescription, the list of stuff to build is held in library (in a Maybe)
7677-- and the executables list. We want a PackageDescription that only mentions the executable 'name'
7778filterExe name pd = pd {
@@ -116,10 +117,25 @@ appendJS lbi file = do
116117 appendFile (rts lbi) str
117118
118119appendElm lbi file = do
119− system (elm lbi ++ " --only-js " ++ file)
120− let jsFile = replaceExtension file ".js"
120+ jsFile <- runElm lbi file
121121 appendJS lbi jsFile
122− removeFile jsFile
122+
123+-- replace 'system' call with 'runProcess' which handles args better and allows env variable
124+-- "Elm_datadir" which is used by LoadLibraries to find docs.json
125+runElm :: LocalBuildInfo -> String -> IO FilePath
126+runElm lbi file = do
127+ rts_c <- canonicalizePath (rts lbi) -- dist/data/elm-runtime.js
128+ let js = jsDir lbi -- dist/js
129+ let j = dropFileName (js </> file) -- dist/js/libraries/
130+ createDirectoryIfMissing True j -- must do before any canonicalization
131+ out_c <- canonicalizePath js -- dist/js (root folder)
132+ elm_c <- canonicalizePath (elm lbi) -- dist/build/elm/elm
133+ rtd_c <- canonicalizePath (rtsDir lbi) -- dist/data (for docs.json)
134+ handle <- runProcess elm_c ["--only-js", "--runtime="++rts_c, "--output-directory="++out_c, file]
135+ Nothing (Just [("Elm_datadir", rtd_c)]) Nothing Nothing Nothing
136+ waitForProcess handle
137+ return $ j </> replaceExtension (takeFileName file) ".js"
138+
123139
124140buildRuntime lbi = do
125141 createDirectoryIfMissing False (rtsDir lbi) -- dist should already exist
compiler/Model/Libraries.hs+2−4
@@ -1,10 +1,8 @@
1−{-# LANGUAGE TemplateHaskell #-}
2−
31module Libraries (libraries) where
42
53import qualified Data.Map as Map
64import Text.JSON
7−import LoadLibraries
5+import LoadLibraries (docs)
86
97libraries :: Map.Map String (Map.Map String String)
108libraries = case getLibs of
@@ -13,7 +11,7 @@ libraries = case getLibs of
1311
1412getLibs :: Result (Map.Map String (Map.Map String String))
1513getLibs = do
16− obj <- decodeStrict "{\"modules\":[]}" -- $(docs) :: Result (JSObject JSValue)
14+ obj <- decodeStrict docs :: Result (JSObject JSValue)
1715 modules <- valFromObj "modules" obj :: Result [JSObject JSValue]
1816 Map.fromList `fmap` mapM getValues modules
1917
compiler/Model/LoadLibraries.hs+21−21
@@ -1,36 +1,36 @@
1−{-# LANGUAGE CPP #-}
2−
31module LoadLibraries (docs) where
42
5−import Language.Haskell.TH.Syntax
3+import Control.DeepSeq (force)
4+import qualified Control.Exception as E
65import Paths_Elm
76import System.Directory
87import System.FilePath
8+import System.IO.Unsafe (unsafePerformIO)
9+
10+-- See stackoverflow discussion for trade-off between using unsafeIO or TemplateHaskell:
11+-- http://stackoverflow.com/questions/12716215/load-pure-global-variable-from-file
912
10−docs :: Q Exp
11−docs = liftString =<< qRunIO (readDocs dataDir)
13+-- Given the awkwardness of including a compile-time generated file
14+-- vs loading static data, then the unsafeIO seems better.
1215
13−-- When compiling elm (library and executable), docs.json isn't (yet) in the standard location
14−-- Therefore, Elm.cabal overrides the location.
15−-- Since this is only used by the TemplateHaskell, which reads the file at compile time,
16−-- this should be ok.
16+{-# NOINLINE docs #-}
17+docs :: String
18+docs = force . unsafePerformIO . safeReadDocs . getDataFileName $ "docs.json"
1719
18−dataDir :: IO FilePath
19−#if defined ELM_COMPILEDATADIR
20−dataDir = canonicalizePath (ELM_COMPILEDATADIR </> "docs.json")
21−#else
22−dataDir = getDataFileName "docs.json"
23−#endif
20+safeReadDocs :: IO FilePath -> IO String
21+safeReadDocs path = E.catch (readDocs path) (emitError path)
2422
2523readDocs :: IO FilePath -> IO String
2624readDocs path = do
2725 name <- path
2826 exists <- doesFileExist name
2927 if exists then readFile name
30− else putStrLn warning >> return "{\"modules\":[]}"
28+ else ioError . userError $ "File Not Found"
29+
3130
32−warning = "Warning! Types for standard library not loaded properly!\n\
33− Run the following commands after compilation:\n\
34− \n\
35− touch compiler/Model/LoadLibraries.hs\n\
36− cabal install\n\n"
31+emitError :: IO FilePath -> IOError -> IO String
32+emitError path err = do
33+ name <- path
34+ putStrLn $ "Error! Types for standard library not loaded properly!\n File should be here:" ++ name ++ "\n The file is created and copied by command: cabal install"
35+ putStrLn (show err)
36+ return "{\"modules\":[]}"