hie-bios 0.7.1 → 0.7.2
raw patch · 10 files changed
+108/−62 lines, 10 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- HIE.Bios.Cradle: readProcessWithOutputFile :: LoggingFunction -> FilePath -> CreateProcess -> IO (ExitCode, [String], [String], [String])
+ HIE.Bios.Cradle: readProcessWithOutputs :: Outputs -> LoggingFunction -> FilePath -> CreateProcess -> IO (ExitCode, [String], [String], [(OutputName, Maybe [String])])
Files
- ChangeLog.md +6/−0
- README.md +8/−14
- hie-bios.cabal +8/−4
- src/HIE/Bios/Cradle.hs +68/−43
- src/HIE/Bios/Environment.hs +5/−1
- tests/BiosTests.hs +1/−0
- tests/projects/deps-bios-new/A.hs +1/−0
- tests/projects/deps-bios-new/B.hs +3/−0
- tests/projects/deps-bios-new/hie-bios.sh +5/−0
- tests/projects/deps-bios-new/hie.yaml +3/−0
ChangeLog.md view
@@ -1,5 +1,11 @@ # ChangeLog hie-bios +## 2020-12-16 - 0.7.2++* Faster Bios protocol [#271](https://github.com/mpickering/hie-bios/pull/271)+* Modify unreachable cabal website links [#259](https://github.com/mpickering/hie-bios/pull/259)+* Only take the last line of output in getRuntimeGhcX [#256](https://github.com/mpickering/hie-bios/pull/256)+ ## 2020-09-01 - 0.7.1 * Add explicit type for stack.yaml location [#243](https://github.com/mpickering/hie-bios/pull/243)
README.md view
@@ -209,7 +209,7 @@ This configuration should work in (almost) every standard project setup, since `cabal` finds the component associated to a given source file. However, due to an unfortunate [bug](https://github.com/haskell/cabal/issues/6622), this fails on some files with `cabal` versions older than `3.4`. So, to make your project loadable by older `cabal` versions, you can specify a component to load.-A [component](https://cabal.readthedocs.io/en/stable/nix-local-build.html?highlight=component#cabal-v2-build) is roughly speaking a library, executable, test-suite or benchmark in `cabal`.+A [component](https://cabal.readthedocs.io/en/latest/nix-local-build.html?highlight=component#cabal-v2-build) is roughly speaking a library, executable, test-suite or benchmark in `cabal`. The `hie.yaml` file looks like this: ```yaml@@ -228,7 +228,7 @@ component: "lib:hie-bios" ``` -The component syntax `"lib:hie-bios"` refers to the library of the package `hie-bios`. For a complete reference of the component syntax, we refer to the [documentation](https://cabal.readthedocs.io/en/stable/nix-local-build.html?highlight=component#cabal-v2-build).+The component syntax `"lib:hie-bios"` refers to the library of the package `hie-bios`. For a complete reference of the component syntax, we refer to the [documentation](https://cabal.readthedocs.io/en/latest/nix-local-build.html?highlight=component#cabal-v2-build). Note that `cabal` and `stack` have different ways of specifying their components.@@ -560,29 +560,23 @@ - default.nix ``` -For the `Bios` cradle type, there is an optional field for specifying a program-or shell command to obtain cradle dependencies from:+For the `Bios` cradle type, the newline-separated cradle dependencies must be written out+to the file specified by the `HIE_BIOS_DEPS` environment variable. +Previous versions implemented a different mechanism for collecting cradle dependencies+by means of a second program/shell field. This is still supported for backwards+compatibility:+ ```yaml cradle: bios:- program: ./flags.sh dependency-program: ./dependency.sh ``` ```yaml cradle: bios:- shell: build-tool flags $HIE_BIOS_ARG > $HIE_BIOS_OUTPUT dependency-shell: build-tool dependencies $HIE_BIOS_ARG > $HIE_BIOS_OUTPUT ```--The dependency program or command is executed in a similar fashion to the bios-program, using the environment variables HIE_BIOS_ARG and HIE_BIOS_OUTPUT to-communicate respectively the path of the source file being loaded, and the path-where the set of dependency paths should be written, one per line,-and relative to the root of the cradle, not to the location of the program.--Programs and shell commands for flags and dependencies can be mixed and matched. ## Configuration specification
hie-bios.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: 2.2 Name: hie-bios-Version: 0.7.1+Version: 0.7.2 Author: Matthew Pickering <matthewtpickering@gmail.com> Maintainer: Matthew Pickering <matthewtpickering@gmail.com> License: BSD-3-Clause@@ -19,6 +19,10 @@ tests/configs/*.yaml tests/projects/symlink-test/a/A.hs tests/projects/symlink-test/hie.yaml+ tests/projects/deps-bios-new/A.hs+ tests/projects/deps-bios-new/B.hs+ tests/projects/deps-bios-new/hie-bios.sh+ tests/projects/deps-bios-new/hie.yaml tests/projects/multi-direct/A.hs tests/projects/multi-direct/B.hs tests/projects/multi-direct/hie.yaml@@ -142,8 +146,8 @@ autogen-modules: Paths_hie_bios Build-Depends: base >= 4.8 && < 5,- aeson >= 1.4.1 && < 2,- base16-bytestring >= 0.1.1 && < 0.2,+ aeson >= 1.4.5 && < 2,+ base16-bytestring >= 0.1.1 && < 1.1, bytestring >= 0.10.8 && < 0.11, deepseq >= 1.4.3 && < 1.5, containers >= 0.5.10 && < 0.7,@@ -160,7 +164,7 @@ unix-compat >= 0.5.1 && < 0.6, unordered-containers >= 0.2.9 && < 0.3, vector >= 0.12.0 && < 0.13,- yaml >= 0.8.32 && < 0.12,+ yaml >= 0.10.0 && < 0.12, hslogger >= 1.2 && < 1.4, file-embed >= 0.0.11 && < 1, conduit >= 1.3 && < 2,
src/HIE/Bios/Cradle.hs view
@@ -18,7 +18,7 @@ , isDefaultCradle , isOtherCradle , getCradle- , readProcessWithOutputFile+ , readProcessWithOutputs , readProcessWithCwd , makeCradleResult ) where@@ -33,6 +33,7 @@ import HIE.Bios.Config import HIE.Bios.Environment (getCacheDir) import System.Directory hiding (findFile)+import Control.Monad.Trans.Cont import Control.Monad.Trans.Maybe import System.FilePath import Control.Monad@@ -59,6 +60,8 @@ import Data.Maybe (fromMaybe, maybeToList) import GHC.Fingerprint (fingerprintString) +hie_bios_output :: String+hie_bios_output = "HIE_BIOS_OUTPUT" ---------------------------------------------------------------- -- | Given root\/foo\/bar.hs, return root\/hie.yaml, or wherever the yaml file was found.@@ -357,10 +360,10 @@ biosDepsAction :: LoggingFunction -> FilePath -> Maybe Callable -> FilePath -> IO [FilePath] biosDepsAction l wdir (Just biosDepsCall) fp = do biosDeps' <- callableToProcess biosDepsCall (Just fp)- (ex, sout, serr, args) <- readProcessWithOutputFile l wdir biosDeps'+ (ex, sout, serr, [(_, args)]) <- readProcessWithOutputs [hie_bios_output] l wdir biosDeps' case ex of ExitFailure _ -> error $ show (ex, sout, serr)- ExitSuccess -> return args+ ExitSuccess -> return $ fromMaybe [] args biosDepsAction _ _ Nothing _ = return [] biosAction :: FilePath@@ -371,13 +374,17 @@ -> IO (CradleLoadResult ComponentOptions) biosAction wdir bios bios_deps l fp = do bios' <- callableToProcess bios (Just fp)- (ex, _stdo, std, res) <- readProcessWithOutputFile l wdir bios'- deps <- biosDepsAction l wdir bios_deps fp+ (ex, _stdo, std, [(_, res),(_, mb_deps)]) <-+ readProcessWithOutputs [hie_bios_output, "HIE_BIOS_DEPS"] l wdir bios'++ deps <- case mb_deps of+ Just x -> return x+ Nothing -> biosDepsAction l wdir bios_deps fp -- Output from the program should be written to the output file and -- delimited by newlines. -- Execute the bios action and add dependencies of the cradle. -- Removes all duplicates.- return $ makeCradleResult (ex, std, wdir, res) deps+ return $ makeCradleResult (ex, std, wdir, fromMaybe [] res) deps callableToProcess :: Callable -> Maybe String -> IO CreateProcess callableToProcess (Command shellCommand) file = do@@ -491,8 +498,9 @@ cabalAction work_dir mc l fp = do withCabalWrapperTool ("ghc", []) work_dir $ \wrapper_fp -> do let cab_args = ["v2-repl", "--with-compiler", wrapper_fp, fromMaybe (fixTargetPath fp) mc]- (ex, output, stde, args) <-- readProcessWithOutputFile l work_dir (proc "cabal" cab_args)+ (ex, output, stde, [(_,mb_args)]) <-+ readProcessWithOutputs [hie_bios_output] l work_dir (proc "cabal" cab_args)+ let args = fromMaybe [] mb_args case processCabalWrapperArgs args of Nothing -> do -- Best effort. Assume the working directory is the@@ -502,7 +510,7 @@ ["Failed to parse result of calling cabal" , unlines output , unlines stde- , unlines args])+ , unlines $ args]) Just (componentDir, final_args) -> do deps <- cabalCradleDependencies work_dir componentDir pure $ makeCradleResult (ex, stde, componentDir, final_args) deps@@ -615,16 +623,17 @@ let ghcProcArgs = ("stack", stackYamlProcessArgs syaml <> ["exec", "ghc", "--"]) -- Same wrapper works as with cabal withCabalWrapperTool ghcProcArgs work_dir $ \wrapper_fp -> do- (ex1, _stdo, stde, args) <-- readProcessWithOutputFile l work_dir $+ (ex1, _stdo, stde, [(_, mb_args)]) <-+ readProcessWithOutputs [hie_bios_output] l work_dir $ stackProcess syaml $ ["repl", "--no-nix-pure", "--with-ghc", wrapper_fp] <> [ comp | Just comp <- [mc] ] (ex2, pkg_args, stdr, _) <-- readProcessWithOutputFile l work_dir $+ readProcessWithOutputs [hie_bios_output] l work_dir $ stackProcess syaml ["path", "--ghc-package-path"] let split_pkgs = concatMap splitSearchPath pkg_args pkg_ghc_args = concatMap (\p -> ["-package-db", p] ) split_pkgs+ args = fromMaybe [] mb_args case processCabalWrapperArgs args of Nothing -> do -- Best effort. Assume the working directory is the@@ -776,49 +785,65 @@ e <- getEnvironment return $ Map.toList $ Map.delete "GHC_PACKAGE_PATH" $ Map.fromList e --- | Call a given process.--- * A special file is created for the process to write to, the process can discover the name of--- the file by reading the @HIE_BIOS_OUTPUT@ environment variable. The contents of this file is--- returned by the function.+type Outputs = [OutputName]+type OutputName = String++-- | Call a given process with temp files for the process to write to.+-- * The process can discover the temp files paths by reading the environment.+-- * The contents of the temp files are returned by this function, if any. -- * The logging function is called every time the process emits anything to stdout or stderr. -- it can be used to report progress of the process to a user. -- * The process is executed in the given directory.-readProcessWithOutputFile- :: LoggingFunction -- ^ Output of the process is streamed into this function.+readProcessWithOutputs+ :: Outputs -- ^ Names of the outputs produced by this process+ -> LoggingFunction -- ^ Output of the process is streamed into this function. -> FilePath -- ^ Working directory. Process is executed in this directory. -> CreateProcess -- ^ Parameters for the process to be executed.- -> IO (ExitCode, [String], [String], [String])-readProcessWithOutputFile l work_dir cp = do- old_env <- getCleanEnvironment+ -> IO (ExitCode, [String], [String], [(OutputName, Maybe [String])])+readProcessWithOutputs outputNames l work_dir cp = flip runContT return $ do+ old_env <- liftIO getCleanEnvironment+ output_files <- traverse (withOutput old_env) outputNames - withHieBiosOutput old_env $ \output_file -> do- -- Pipe stdout directly into the logger- let process = cp { env = Just- $ (hieBiosOutput, output_file)- : (fromMaybe old_env (env cp)),- cwd = Just work_dir- }+ let process = cp { env = Just $ output_files ++ fromMaybe old_env (env cp),+ cwd = Just work_dir+ } -- Windows line endings are not converted so you have to filter out `'r` characters- let loggingConduit = (C.decodeUtf8 C..| C.lines C..| C.filterE (/= '\r') C..| C.map T.unpack C..| C.iterM l C..| C.sinkList)- (ex, stdo, stde) <- sourceProcessWithStreams process mempty loggingConduit loggingConduit- res <- withFile output_file ReadMode $ \handle -> do- hSetBuffering handle LineBuffering- !res <- force <$> hGetContents handle- return res+ let loggingConduit = C.decodeUtf8 C..| C.lines C..| C.filterE (/= '\r') C..| C.map T.unpack C..| C.iterM l C..| C.sinkList+ (ex, stdo, stde) <- liftIO $ sourceProcessWithStreams process mempty loggingConduit loggingConduit - return (ex, stdo, stde, lines (filter (/= '\r') res))+ res <- forM output_files $ \(name,path) ->+ liftIO $ (name,) <$> readOutput path + return (ex, stdo, stde, res)+ where- withHieBiosOutput :: [(String,String)] -> (FilePath -> IO a) -> IO a- withHieBiosOutput env' action = do- let mbHieBiosOut = lookup hieBiosOutput env'- case mbHieBiosOut of- Just file@(_:_) -> action file- _ -> withSystemTempFile "hie-bios" $- \ file h -> hClose h >> action file+ readOutput :: FilePath -> IO (Maybe [String])+ readOutput path = do+ haveFile <- doesFileExist path+ if haveFile+ then withFile path ReadMode $ \handle -> do+ hSetBuffering handle LineBuffering+ !res <- force <$> hGetContents handle+ return $ Just $ lines $ filter (/= '\r') res+ else+ return Nothing - hieBiosOutput = "HIE_BIOS_OUTPUT"+ withOutput :: [(String,String)] -> OutputName -> ContT a IO (OutputName, String)+ withOutput env' name =+ case lookup name env' of+ Just file@(_:_) -> ContT $ \action -> do+ removeFileIfExists file+ action (name, file)+ _ -> ContT $ \action -> withSystemTempFile name $ \ file h -> do+ hClose h+ removeFileIfExists file+ action (name, file)++removeFileIfExists :: FilePath -> IO ()+removeFileIfExists f = do+ yes <- doesFileExist f+ when yes (removeFile f) makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> CradleLoadResult ComponentOptions makeCradleResult (ex, err, componentDir, gopts) deps =
src/HIE/Bios/Environment.hs view
@@ -309,5 +309,9 @@ anyToken = satisfy $ const True -- Used for clipping the trailing newlines on GHC output+-- Also only take the last line of output+-- (Stack's ghc output has a lot of preceding noise from 7zip etc) trim :: String -> String-trim = dropWhileEnd isSpace+trim s = case lines s of+ [] -> s+ ls -> dropWhileEnd isSpace $ last ls
tests/BiosTests.hs view
@@ -183,6 +183,7 @@ = [ testCaseSteps "simple-bios" $ testDirectory isBiosCradle "./tests/projects/simple-bios" "B.hs" , testCaseSteps "simple-bios-ghc" $ testDirectory isBiosCradle "./tests/projects/simple-bios-ghc" "B.hs" , testCaseSteps "simple-bios-deps" $ testLoadCradleDependencies isBiosCradle "./tests/projects/simple-bios" "B.hs" (assertEqual "dependencies" ["hie-bios.sh", "hie.yaml"])+ , testCaseSteps "simple-bios-deps-new" $ testLoadCradleDependencies isBiosCradle "./tests/projects/deps-bios-new" "B.hs" (assertEqual "dependencies" ["hie-bios.sh", "hie.yaml"]) ] | otherwise = []
+ tests/projects/deps-bios-new/A.hs view
@@ -0,0 +1,1 @@+module A where
+ tests/projects/deps-bios-new/B.hs view
@@ -0,0 +1,3 @@+module B where++import A
+ tests/projects/deps-bios-new/hie-bios.sh view
@@ -0,0 +1,5 @@+echo "-Wall" >> $HIE_BIOS_OUTPUT+echo "A" >> $HIE_BIOS_OUTPUT+echo "B" >> $HIE_BIOS_OUTPUT+echo "hie-bios.sh" >> $HIE_BIOS_DEPS+echo "hie.yaml" >> $HIE_BIOS_DEPS
+ tests/projects/deps-bios-new/hie.yaml view
@@ -0,0 +1,3 @@+cradle:+ bios:+ program: ./hie-bios.sh