From 27a631b2c94df80ac5da8c97b66a3e99e1813811 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Wed, 3 Aug 2022 14:11:18 -0400 Subject: Print bild JSON analysis as a dictionary instead of a stream --- Biz/Bild.hs | 130 ++++++++++++++++++++++++++++--------------------------- Biz/Bild.nix | 5 ++- Biz/Ide/repl | 6 +-- Biz/Namespace.hs | 5 +++ 4 files changed, 79 insertions(+), 67 deletions(-) diff --git a/Biz/Bild.hs b/Biz/Bild.hs index 06c102f..2b7a2e1 100644 --- a/Biz/Bild.hs +++ b/Biz/Bild.hs @@ -51,6 +51,10 @@ -- -- * -o = optimize level -- +-- * the build is planned out with an analysis, which can be viewed +-- beforehand with `--json`. The analysis includes compiler flags, which +-- can be used in `repl` for testing compilation locally. +-- -- == Example Commands -- -- > bild [opts] @@ -58,7 +62,8 @@ -- The general scheme is to build the things described by the targets. A target -- is a namespace. You can list as many as you want, but you must list at least -- one. It could just be `:!bild %` in vim to build whatever you're working on, --- or `bild **/*` to build everything. +-- or `bild **/*` to build everything, or `fd .hs -X bild` to build all Haskell +-- files. -- -- Build outputs will go into the `_` directory in the root of the project. -- @@ -136,8 +141,7 @@ main = Cli.main <| Cli.Plan help move test_ pure root <- Env.getEnv "BIZ_ROOT" let Just ns = Namespace.fromPath root "Biz/Bild.hs" analyze mempty ns - /> Map.elems - +> traverse (build False False) + +> build False False +> \case [Exit.ExitFailure _] -> Test.assertFailure "can't bild bild" @@ -157,18 +161,17 @@ move args = do /> catMaybes +> foldM analyze mempty /> Map.filter (namespace .> isBuildableNs) - /> Map.elems +> printOrBuild +> exitSummary where - printOrBuild :: [Target] -> IO [ExitCode] + printOrBuild :: Analysis -> IO [ExitCode] printOrBuild targets | args `Cli.has` Cli.longOption "json" = - Log.wipe >> traverse_ putJSON targets >> pure [Exit.ExitSuccess] + Log.wipe >> putJSON targets >> pure [Exit.ExitSuccess] | otherwise = do root <- Env.getEnv "BIZ_ROOT" createHier root - traverse (build isTest isLoud) targets + build isTest isLoud targets isTest = args `Cli.has` Cli.longOption "test" isLoud = args `Cli.has` Cli.longOption "loud" putJSON = Aeson.encode .> ByteString.toStrict .> Char8.putStrLn @@ -188,7 +191,7 @@ Usage: Options: --test Run tests on a target after building --loud Show all output from compiler - --json Only analyze and print as JSON, don't build + --json Print the build plan as JSON, don't build -h, --help Print this info |] @@ -596,62 +599,63 @@ test loud Target {..} = case compiler of >> Log.br >> pure Exit.ExitSuccess -build :: Bool -> Bool -> Target -> IO Exit.ExitCode -build andTest loud target@Target {..} = do +build :: Bool -> Bool -> Analysis -> IO [Exit.ExitCode] +build andTest loud analysis = do root <- Env.getEnv "BIZ_ROOT" - case compiler of - Gcc -> - Log.info ["bild", label, "gcc", nschunk namespace] - >> proc loud namespace "gcc" compilerFlags - where - label = case out of - Bin _ -> "bin" - _ -> "lib" - GhcExe -> do - Log.info ["bild", "dev", "ghc-exe", nschunk namespace] - exitcode <- proc loud namespace "ghc" compilerFlags - if andTest && isSuccess exitcode - then test loud target - else pure exitcode - GhcLib -> do - Log.info ["bild", "dev", "ghc-lib", nschunk namespace] - proc - loud - namespace - "ghc" - compilerFlags - Guile -> do - Log.info ["bild", "dev", "guile", nschunk namespace] - _ <- proc loud namespace "guild" compilerFlags - when (out /= None) <| do - writeFile - (root outdir out) - <| Text.pack - <| joinWith - "\n" - [ "#!/usr/bin/env bash", - "guile -C \"" - <> root intdir - <> "\" -e main " - <> "-s " - <> Namespace.toPath namespace - <> " \"$@\"" - ] - p <- Dir.getPermissions <| root outdir out - Dir.setPermissions (root outdir out) (Dir.setOwnerExecutable True p) - pure Exit.ExitSuccess - NixBuild -> do - Log.info ["bild", "nix", builder, nschunk namespace] - proc loud namespace "nix-build" compilerFlags - Copy -> do - Log.warn ["bild", "copy", "TODO", nschunk namespace] - pure Exit.ExitSuccess - Rustc -> do - Log.info ["bild", "dev", "rust", nschunk namespace] - proc loud namespace "rustc" compilerFlags - Sbcl -> do - Log.info ["bild", "dev", "lisp", nschunk namespace] - proc loud namespace "sbcl" compilerFlags + forM (Map.elems analysis) <| \target@Target {..} -> do + case compiler of + Gcc -> + Log.info ["bild", label, "gcc", nschunk namespace] + >> proc loud namespace "gcc" compilerFlags + where + label = case out of + Bin _ -> "bin" + _ -> "lib" + GhcExe -> do + Log.info ["bild", "dev", "ghc-exe", nschunk namespace] + exitcode <- proc loud namespace "ghc" compilerFlags + if andTest && isSuccess exitcode + then test loud target + else pure exitcode + GhcLib -> do + Log.info ["bild", "dev", "ghc-lib", nschunk namespace] + proc + loud + namespace + "ghc" + compilerFlags + Guile -> do + Log.info ["bild", "dev", "guile", nschunk namespace] + _ <- proc loud namespace "guild" compilerFlags + when (out /= None) <| do + writeFile + (root outdir out) + <| Text.pack + <| joinWith + "\n" + [ "#!/usr/bin/env bash", + "guile -C \"" + <> root intdir + <> "\" -e main " + <> "-s " + <> Namespace.toPath namespace + <> " \"$@\"" + ] + p <- Dir.getPermissions <| root outdir out + Dir.setPermissions (root outdir out) (Dir.setOwnerExecutable True p) + pure Exit.ExitSuccess + NixBuild -> do + Log.info ["bild", "nix", builder, nschunk namespace] + proc loud namespace "nix-build" compilerFlags + Copy -> do + Log.warn ["bild", "copy", "TODO", nschunk namespace] + pure Exit.ExitSuccess + Rustc -> do + Log.info ["bild", "dev", "rust", nschunk namespace] + proc loud namespace "rustc" compilerFlags + Sbcl -> do + Log.info ["bild", "dev", "lisp", nschunk namespace] + proc loud namespace "sbcl" compilerFlags data Proc = Proc { loud :: Bool, diff --git a/Biz/Bild.nix b/Biz/Bild.nix index ab120db..b6946c9 100644 --- a/Biz/Bild.nix +++ b/Biz/Bild.nix @@ -98,7 +98,10 @@ rec { # gather data needed for compiling by analyzing the main module analyze = main: - # builtins.head + let + path = lib.strings.removePrefix (builtins.getEnv "BIZ_ROOT" + "/") (toString main); + in + lib.attrsets.getAttrFromPath [path] (lib.trivial.importJSON (runBildAnalyze main + "/analysis.json")); diff --git a/Biz/Ide/repl b/Biz/Ide/repl index a8fc124..8f92fba 100755 --- a/Biz/Ide/repl +++ b/Biz/Ide/repl @@ -26,9 +26,9 @@ fi fi targets=${@:?} json=$(bild --json ${targets[@]}) - langdeps=$(jq --raw-output '.langdeps | join(" ")' <<< $json) - sysdeps=$(jq --raw-output '.sysdeps | join(" ")' <<< $json) - exts=$(jq --raw-output '.namespace.ext' <<< $json | sort | uniq) + langdeps=$(jq --raw-output '.[].langdeps | join(" ")' <<< $json) + sysdeps=$(jq --raw-output '.[].sysdeps | join(" ")' <<< $json) + exts=$(jq --raw-output '.[].namespace.ext' <<< $json | sort | uniq) BILD="(import $BIZ_ROOT/Biz/Bild.nix {})" for lib in ${sysdeps[@]}; do flags+=(--packages "$BILD.private.nixpkgs.${lib}") diff --git a/Biz/Namespace.hs b/Biz/Namespace.hs index cdc4464..72e3fa1 100644 --- a/Biz/Namespace.hs +++ b/Biz/Namespace.hs @@ -19,9 +19,11 @@ where import Alpha import qualified Data.Aeson as Aeson +import qualified Data.Aeson.Types as Aeson import qualified Data.Char as Char import qualified Data.List as List import qualified Data.List.Split as List +import qualified Data.Text as Text import qualified Text.Regex.Applicative as Regex data Ext @@ -43,6 +45,9 @@ data Ext data Namespace = Namespace {path :: [String], ext :: Ext} deriving (Eq, Show, Generic, Aeson.ToJSON, Ord) +instance Aeson.ToJSONKey Namespace where + toJSONKey = Aeson.toJSONKeyText (Text.pack <. toPath) + fromPath :: String -> String -> Maybe Namespace fromPath bizRoot absPath = List.stripPrefix bizRoot absPath -- cgit v1.2.3