on master help sign in
Fix cabal install missing docs.json

See: https://github.com/evancz/Elm/issues/120 Add build-hook to Setup.hs so that elm-doc gets build and executed before library or elm exec gets built. Add preprocessor to Elm.cabal so LoadLibraries.hs can load docs.json from the build folder instead of installed folder Add touch to Setup.hs otherwise LoadLibraries.hs doesn't get recompiled. This is non-portable, but I can't find a portable way (see Setup.hs for details) cabal clean && cabal install now works (tested on ghc 7.4.1)

commit14e32add30c690b1309252d530afbea29cc448ec authorngunn <ngunn@computationalthinking.org.uk> dateThu 21 Mar 2013, 13:31 (14 years ago) parent0064813
3 files changed+114−35
Elm.cabal+4 Setup.hs+88−27 compiler/Model/LoadLibraries.hs+22−8
Elm.cabal+4
@@ -33,6 +33,8 @@ 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"
3638 other-modules: Ast,
3739 Context,
3840 CompileToJS,
@@ -87,6 +89,8 @@ Library
8789Executable elm
8890 Main-is: Compiler.hs
8991 Hs-Source-Dirs: compiler, compiler/Gen, compiler/Model, compiler/Transform
92+ extensions: CPP
93+ cpp-options: -DELM_COMPILEDATADIR="dist/data"
9094 other-modules: Ast,
9195 Context,
9296 CompileToJS,
Setup.hs+88−27
@@ -8,33 +8,99 @@ import System.Directory
88import System.FilePath
99import System.IO
1010
11+import Control.Monad
12+
13+-- Part 1
14+-- ------
15+-- Add a build callout
16+-- We need to build elm-doc and run it because that generates the file "docs.json" needs by Libraries.hs
17+-- which is part of the elm library and executable
18+-- Unfort. there seems to be no way to tell cabal that:
19+-- (a) elm-doc generates docs.json, and
20+-- (b) elm (library) depends on docs.json
21+-- Therefore, we either use make instead (or a script), or hack around in cabal
22+
23+-- Part 2
24+-- ------
1125-- Add a post-build callout.
12−-- We need to build the runtime.js after we've built elm,
26+-- We need to build the runtime.js after we've built elm (because we use elm to generate some of the JavaScript),
1327-- but before cabal does the install file copy step
1428
15−main :: IO ()
16−main = defaultMainWithHooks simpleUserHooks { postBuild = myPostBuild }
29+-- Assumptions
30+-- Elm.cabal expects the generated files to end up in dist/data
31+rtsDir lbi = (buildDir lbi) </> ".." </> "data" -- git won't look in dist + cabal will clean it
32+
33+-- The runtime is called:
34+rts lbi = (rtsDir lbi) </> "elm-runtime.js"
35+
36+-- The json file is called:
37+
38+-- The elm-docs executable is called:
39+elmDoc = "elm-doc"
40+elm_doc lbi = (buildDir lbi) </> elmDoc </> elmDoc
41+
42+types lbi = (rtsDir lbi) </> "docs.json"
43+
44+-- buildDir with LocalBuildInfo points to "dist/build" (usually)
45+elm lbi = (buildDir lbi) </> "elm" </> "elm"
46+
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"]
1753
1854-- Care! This appears to be based on an unstable API
1955-- See: http://www.haskell.org/cabal/release/cabal-latest/doc/API/Cabal/Distribution-Simple.html#2
2056
21−myPostBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
22−myPostBuild as bfs pd lbi = do
23− putStrLn "Custom build step started"
24− buildRuntime lbi
57+
58+main :: IO ()
59+main = defaultMainWithHooks simpleUserHooks { buildHook = myBuild, postBuild = myPostBuild }
60+
61+
62+-- Build
63+
64+myBuild :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
65+myBuild pd lbi uh bf = do
66+ putStrLn $ "Custom build step started: compile " ++ elmDoc
67+ withExe pd (\x -> putStrLn (exeName x))
68+ buildHook simpleUserHooks (filterExe elmDoc pd) (filterLBI elmDoc lbi) uh bf
69+ putStrLn "Custom build step started: build docs.json"
2570 buildTypes lbi
26− postBuild simpleUserHooks as bfs pd lbi
71+ forM_ docTouches (\s -> system ("touch " ++ s)) -- NB non-portable
72+ putStrLn "Custom build step started: compile everything"
73+ buildHook simpleUserHooks pd lbi uh bf
2774
28−-- put js file in dist folder so git doesn't notice
29−rtsDir = "dist" </> "data"
75+-- In the PackageDescription, the list of stuff to build is held in library (in a Maybe)
76+-- and the executables list. We want a PackageDescription that only mentions the executable 'name'
77+filterExe name pd = pd {
78+ library = Nothing,
79+ executables = filter (\x -> (exeName x == name)) (executables pd)
80+ }
3081
31−rts = rtsDir </> "elm-runtime.js"
32−types = rtsDir </> "docs.json"
82+-- It's not enough to fix the PackageDescription, we also have to fix the LocalBuildInfo.
83+-- This includes the component build order (data ComponentName) which is horribly internal.
84+filterLBI name lbi = lbi {
85+ libraryConfig = Nothing,
86+ compBuildOrder = [CExeName name],
87+ executableConfigs = filter (\a -> (fst a == name)) (executableConfigs lbi)
88+ }
89+
90+buildTypes lbi = do
91+ createDirectoryIfMissing False (rtsDir lbi) -- dist should already exist
92+ files <- getFiles ".elm" "libraries"
93+ system (elm_doc lbi ++ " " ++ unwords files ++ " > " ++ (types lbi))
94+ putStrLn $ "Custom build step completed: " ++ elmDoc
3395
34−-- buildDir with LocalBuildInfo points to "dist/build" (usually)
35−elm lbi = (buildDir lbi) </> "elm" </> "elm"
36−elm_doc lbi = (buildDir lbi) </> "elm-doc" </> "elm-doc"
3796
97+-- Post Build
98+
99+myPostBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
100+myPostBuild as bfs pd lbi = do
101+ putStrLn "Custom post build step started: build elm-runtime.js"
102+ buildRuntime lbi
103+ postBuild simpleUserHooks as bfs pd lbi
38104
39105getFiles ext dir = do
40106 contents <- map (dir </>) `fmap` getDirectoryContents dir
@@ -43,30 +109,25 @@ getFiles ext dir = do
43109 filess <- mapM (getFiles ext) dirs
44110 return (files ++ concat filess)
45111
46−appendJS file = do
112+appendJS lbi file = do
47113 putStrLn (dropExtension file)
48114 str <- readFile file
49115 length str `seq` return ()
50− appendFile rts str
116+ appendFile (rts lbi) str
51117
52118appendElm lbi file = do
53119 system (elm lbi ++ " --only-js " ++ file)
54120 let jsFile = replaceExtension file ".js"
55− appendJS jsFile
121+ appendJS lbi jsFile
56122 removeFile jsFile
57123
58124buildRuntime lbi = do
59− createDirectoryIfMissing False rtsDir -- dist should already exist
60− writeFile rts "Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
125+ createDirectoryIfMissing False (rtsDir lbi) -- dist should already exist
126+ writeFile (rts lbi) "Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
61127 \Elm.Graphics = {}; ElmRuntime = {}; ElmRuntime.Render = {}\n"
62− mapM_ appendJS =<< getFiles ".js" "libraries"
128+ mapM_ (appendJS lbi) =<< getFiles ".js" "libraries"
63129 mapM_ (appendElm lbi) =<< getFiles ".elm" "libraries"
64− mapM_ appendJS =<< getFiles ".js" "runtime"
130+ mapM_ (appendJS lbi) =<< getFiles ".js" "runtime"
65131 putStrLn "\n+------------------------------------------+\
66132 \\n| Success building runtime and libraries! |\
67133 \\n+------------------------------------------+\n"
68−
69−buildTypes lbi = do
70− files <- getFiles ".elm" "libraries"
71− system (elm_doc lbi ++ " " ++ unwords files ++ " > " ++ types)
72− putStrLn "Custom build step completed: elm-doc"
compiler/Model/LoadLibraries.hs+22−8
@@ -1,22 +1,36 @@
1+{-# LANGUAGE CPP #-}
12
23module LoadLibraries (docs) where
34
45import Language.Haskell.TH.Syntax
56import Paths_Elm
67import System.Directory
8+import System.FilePath
79
810docs :: Q Exp
9−docs = liftString =<< qRunIO readDocs
11+docs = liftString =<< qRunIO (readDocs dataDir)
1012
11−readDocs :: IO String
12−readDocs = do
13− name <- getDataFileName "docs.json"
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.
17+
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
24+
25+readDocs :: IO FilePath -> IO String
26+readDocs path = do
27+ name <- path
1428 exists <- doesFileExist name
1529 if exists then readFile name
1630 else putStrLn warning >> return "{\"modules\":[]}"
1731
1832warning = "Warning! Types for standard library not loaded properly!\n\
19− \Run the following commands after compilation:\n\
20− \\n\
21− \ touch compiler/Model/LoadLibraries.hs\n\
22− \ cabal install\n\n"
33+ Run the following commands after compilation:\n\
34+ \n\
35+ touch compiler/Model/LoadLibraries.hs\n\
36+ cabal install\n\n"