summaryrefslogtreecommitdiff
path: root/Biz
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2023-08-02 10:38:22 -0400
committerBen Sima <ben@bsima.me>2023-08-02 10:42:54 -0400
commitb154d6b3be99a4a9f5907c84645ca569183bb40e (patch)
treee23c313e1e83495a36159647a20c4c2ec4976707 /Biz
parent4cb9f2fbfbb124b38f19c72059620f25b71f92b7 (diff)
Factor out nix builder into Haskell.nix
This also fixed a bug where every dependency would get pulled into the Haskell target while searching for transitive dependencies.
Diffstat (limited to 'Biz')
-rw-r--r--Biz/Bild.hs163
-rw-r--r--Biz/Bild/Example.hs6
-rw-r--r--Biz/Bild/Haskell.nix36
-rw-r--r--Biz/Log.hs2
-rw-r--r--Biz/Packages.nix2
5 files changed, 114 insertions, 95 deletions
diff --git a/Biz/Bild.hs b/Biz/Bild.hs
index 96203a4..f0b829d 100644
--- a/Biz/Bild.hs
+++ b/Biz/Bild.hs
@@ -109,7 +109,6 @@ import qualified Biz.Cli as Cli
import qualified Biz.Log as Log
import Biz.Namespace (Namespace (..))
import qualified Biz.Namespace as Namespace
-import Biz.Test ((@?=))
import qualified Biz.Test as Test
import qualified Conduit
import qualified Control.Concurrent.Async as Async
@@ -127,7 +126,6 @@ import qualified Data.Set as Set
import qualified Data.String as String
import qualified Data.Text as Text
import qualified Data.Text.IO as Text.IO
-import qualified NeatInterpolation
import qualified System.Directory as Dir
import qualified System.Environment as Env
import qualified System.Exit as Exit
@@ -156,7 +154,6 @@ main = Cli.main <| Cli.Plan help move test_ pure
Test.assertFailure "can't bild bild"
_ ->
pure ()
- -- test_toNixExpr
]
move :: Cli.Arguments -> IO ()
@@ -266,40 +263,6 @@ data Target = Target
}
deriving (Show, Generic, Aeson.ToJSON)
-toNixExpr :: String -> Target -> Text
-toNixExpr root (Target {..}) =
- [NeatInterpolation.trimming|
-with import $troot/Biz/Bild.nix {};
-with builtins;
-let
- skip = ["_" ".direnv"];
- filter = name: type:
- if elem (baseNameOf name) skip then false
- # TODO: this means any new directory will cause a rebuild. this bad.
- # i should recurse into the directory and match against the srcFiles
- else if type == "directory" then true
- else if type == "regular" then builtins.elem name [$srcFiles]
- else false;
-in stdenv.mkDerivation {
- name = "$outname_";
- src = lib.sources.cleanSourceWith {inherit filter; src = lib.sources.cleanSource ./.;};
- buildInputs = [ (private.ghcWith (p: with p; [$nixLangdeps])) ];
- buildPhase = "$compilerCommand $compilerArgs";
- installPhase = "mkdir -p $$out/bin && cp $outname_ $$out/bin";
-}|]
- where
- troot, compilerCommand, compilerArgs, nixLangdeps, outname_, srcFiles :: Text
- troot = Text.pack root
- compilerCommand = compilerExe compiler
- compilerArgs = str <| unwords compilerFlags
- nixLangdeps = str <| String.unwords <| Set.toList langdeps
- outname_ = str <| outname out
- srcFiles =
- ((root </> path) : Set.toList srcs)
- |> map (\p -> "\"" <> p <> "\"\n")
- |> String.unwords
- |> str
-
-- | Use this to just get a target to play with at the repl.
dev_getTarget :: IO Target
dev_getTarget = do
@@ -315,16 +278,6 @@ dev_getTarget = do
Nothing -> panic "Could not retrieve target from analysis"
Just t -> t
-test_toNixExpr :: Test.Tree
-test_toNixExpr =
- Test.group
- "toNixExpr"
- [ Test.unit "produces corect result" <| do
- root <- Env.getEnv "BIZ_ROOT"
- t <- dev_getTarget
- toNixExpr root t @?= [NeatInterpolation.trimming|TODO|]
- ]
-
data Builder
= -- | Local <user>
Local Text
@@ -489,37 +442,39 @@ analyze hmap ns = case Map.lookup ns hmap of
|> Just
|> pure
Namespace.Hs ->
- Meta.detectOut (Meta.out "--") contentLines |> \out -> do
- (langdeps, srcs) <- detectHaskellImports hmap contentLines
- Target
- { builder = Local user,
- wrapper = Nothing,
- compiler = Ghc,
- compilerFlags =
- [ "-Werror",
- "-i$src",
- "-odir",
- ".",
- "-hidir",
- ".",
- "--make",
- "$src" </> path
- ]
- ++ case out of
- Meta.Bin o ->
- [ "-main-is",
- Namespace.toHaskellModule namespace,
- "-o",
- o
- ]
- _ -> []
- |> map Text.pack,
- sysdeps = Meta.detect (Meta.sys "--") contentLines,
- outPath = outToPath out,
- ..
- }
- |> Just
- |> pure
+ contentLines
+ |> Meta.detectOut (Meta.out "--")
+ |> \out ->
+ detectHaskellImports hmap contentLines +> \(langdeps, srcs) ->
+ Target
+ { builder = Local user,
+ wrapper = Nothing,
+ compiler = Ghc,
+ compilerFlags =
+ [ "-Werror",
+ "-i$src",
+ "-odir",
+ ".",
+ "-hidir",
+ ".",
+ "--make",
+ "$src" </> path
+ ]
+ ++ case out of
+ Meta.Bin o ->
+ [ "-main-is",
+ Namespace.toHaskellModule namespace,
+ "-o",
+ o
+ ]
+ _ -> []
+ |> map Text.pack,
+ sysdeps = Meta.detect (Meta.sys "--") contentLines,
+ outPath = outToPath out,
+ ..
+ }
+ |> Just
+ |> pure
Namespace.Lisp ->
Meta.detectOut (Meta.out ";;") contentLines |> \out -> do
langdeps <- detectLispImports contentLines
@@ -628,10 +583,13 @@ detectHaskellImports hmap contentLines =
|> catMaybes
|> \imports ->
foldM ghcPkgFindModule Set.empty imports
- +> \pkgs -> do
- a <- filepaths imports
- b <- deps root imports
- pure (b <> pkgs, Set.fromList a)
+ +> \pkgs ->
+ filepaths imports
+ +> \files ->
+ findDeps root files
+ +> \deps ->
+ (pkgs <> deps, Set.fromList files)
+ |> pure
where
filepaths :: [String] -> IO [FilePath]
filepaths imports =
@@ -640,20 +598,22 @@ detectHaskellImports hmap contentLines =
|> map Namespace.toPath
|> traverse Dir.makeAbsolute
+> filterM Dir.doesFileExist
- deps :: String -> [String] -> IO (Set Meta.Dep)
- deps root imports =
- filepaths imports
- +> traverse (pure <. Namespace.fromPath root)
+ findDeps :: String -> [FilePath] -> IO (Set Meta.Dep)
+ findDeps root fps =
+ fps
+ |> traverse (pure <. Namespace.fromPath root)
/> catMaybes
-- this is still an inefficiency, because this recurses before the
-- hmap is updated by the fold, transitive imports will be
-- re-visited. you can see this with `TERM=dumb bild`. to fix this i
-- need shared state instead of a fold, or figure out how to do a
-- breadth-first search instead of depth-first.
- +> foldM analyze hmap
+ +> foldM analyze (onlyHaskell hmap)
/> Map.elems
/> map langdeps
/> mconcat
+ onlyHaskell :: Analysis -> Analysis
+ onlyHaskell = Map.filterWithKey (\ns _ -> ext ns == Namespace.Hs)
detectLispImports :: [Text] -> IO (Set Meta.Dep)
detectLispImports contentLines =
@@ -761,7 +721,8 @@ data Proc = Proc
-- | Run a subprocess, streaming output if --loud is set.
run :: Proc -> IO (Exit.ExitCode, ByteString)
-run Proc {..} =
+run Proc {..} = do
+ loud ?| Log.info ["proc", unwords <| map str <| cmd : args] >> Log.br
Conduit.proc cmd args
|> Conduit.streamingProcess
+> \(Conduit.UseProvidedHandle, stdout_, stderr_, hdl) ->
@@ -769,8 +730,6 @@ run Proc {..} =
+> \output ->
Async.Concurrently (loud ?: (puts stdout_, logs ns stdout_))
*> Async.Concurrently (loud ?: (puts stderr_, logs ns stderr_))
- *> Async.Concurrently (putsToTmp stdout_ "/tmp/bild-log.out")
- *> Async.Concurrently (putsToTmp stderr_ "/tmp/bild-log.err")
*> Async.Concurrently (Conduit.waitForStreamingProcess hdl)
|> Async.runConcurrently
+> \case
@@ -848,7 +807,7 @@ lispRequires =
isQuote c = c `elem` ['\'', ':']
nixBuild :: Bool -> Target -> IO (Exit.ExitCode, ByteString)
-nixBuild loud target@(Target {..}) =
+nixBuild loud Target {..} =
Env.getEnv "BIZ_ROOT" +> \root ->
instantiate root |> run +> \case
(Exit.ExitSuccess, drv) ->
@@ -861,12 +820,32 @@ nixBuild loud target@(Target {..}) =
>> run symlink
x -> pure x
where
+ argstr :: Text -> Text -> [Text]
+ argstr n v = ["--argstr", n, v]
instantiate root =
Proc
{ loud = loud,
ns = namespace,
cmd = "nix-instantiate",
- args = map Text.unpack ["--expr", toNixExpr root target],
+ -- Getting the args quoted correctly is harder than it should be. This
+ -- is tightly coupled with the code in the nix builder and there's no
+ -- way around that, methinks.
+ args =
+ [ argstr "srcs" <| unwords <| map str <| (root </> path) : Set.toList srcs,
+ argstr "root" <| str root,
+ argstr "packageSet" "ghcWith"
+ ]
+ ++ (langdeps == mempty)
+ ?: ( [],
+ [argstr "langDeps" <| unwords <| map str <| Set.toList langdeps]
+ )
+ ++ [ argstr "name" <| str <| outname out,
+ argstr "main" <| str path,
+ argstr "mainIs" <| str <| Namespace.toHaskellModule namespace,
+ [str <| root </> "Biz/Bild/Haskell.nix"]
+ ]
+ |> mconcat
+ |> map Text.unpack,
onFailure = Log.fail ["bild", "instantiate", nschunk namespace] >> Log.br,
onSuccess = pure ()
}
diff --git a/Biz/Bild/Example.hs b/Biz/Bild/Example.hs
index f812707..87472bb 100644
--- a/Biz/Bild/Example.hs
+++ b/Biz/Bild/Example.hs
@@ -1,5 +1,9 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
-- : out example
module Biz.Bild.Example where
+import Alpha
+
main :: IO ()
-main = print "hi"
+main = putStrLn "Hello world"
diff --git a/Biz/Bild/Haskell.nix b/Biz/Bild/Haskell.nix
new file mode 100644
index 0000000..24b6686
--- /dev/null
+++ b/Biz/Bild/Haskell.nix
@@ -0,0 +1,36 @@
+{ srcs # list of files
+, root # path to git root
+, packageSet # name mapped to private.${packageSet}, e.g. 'ghcWith'
+, langDeps ? null # list of deps (as a string), split and passed to packageSet
+, name # exe name
+, main # entrypoint file
+, mainIs # entrypoint module name
+}:
+with import (/. + root + "/Biz/Bild.nix") {};
+with builtins;
+let
+ srcs_ = lib.strings.splitString " " srcs;
+ skip = ["_" ".direnv"];
+ filter = file: type:
+ if elem (baseNameOf file) skip then false
+ # TODO: this means any new directory will cause a rebuild. this bad.
+ # i should recurse into the directory and match against the srcsr
+ else if type == "directory" then true
+ else if type == "regular" then builtins.elem file srcs_
+ else false;
+ deps = pkgset:
+ if langDeps != null then
+ private.selectAttrs (lib.strings.splitString " " langDeps) pkgset
+ else
+ [];
+in stdenv.mkDerivation {
+ inherit name;
+ buildInputs = [ (private.${packageSet} deps) ];
+ src = lib.sources.cleanSourceWith {inherit filter; src = lib.sources.cleanSource root;};
+ buildPhase = ''
+ ghc -Werror -i$src -odir. -hidir. --make $src/${main} -main-is "${mainIs}" -o ${name}
+ '';
+ installPhase = ''
+ mkdir -p $out/bin && cp ${name} $out/bin
+ '';
+}
diff --git a/Biz/Log.hs b/Biz/Log.hs
index d398f4b..86db272 100644
--- a/Biz/Log.hs
+++ b/Biz/Log.hs
@@ -102,7 +102,7 @@ mark label val =
-- mark label val = val ~& label
-- @
(~&) :: Show a => a -> Text -> a
-(~&) val label = mark label val
+val ~& label = mark label val
-- | Conditional mark.
(~?) :: Show a => a -> (a -> Bool) -> Text -> a
diff --git a/Biz/Packages.nix b/Biz/Packages.nix
index 58235d3..d04dfc3 100644
--- a/Biz/Packages.nix
+++ b/Biz/Packages.nix
@@ -8,7 +8,7 @@ with pkgs;
environment.systemPackages = [
file
fd
- gitAndTools.gitFull
+ gitAndTools.gitMinimal
htop
openssl
ranger