summaryrefslogtreecommitdiff
path: root/Biz/Bild.hs
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2020-10-12 23:43:11 -0400
committerBen Sima <ben@bsima.me>2020-10-12 23:43:11 -0400
commit6bb5a5872018ec047ce090e8b8f0db279ebe0991 (patch)
tree1caf71f171da577219a7e25f2552207e163e58e4 /Biz/Bild.hs
parent170ca39ccee2826f7623858ad4426071fd3a0d61 (diff)
merge Biz/Bild.scm into Biz/Bild.hs
Diffstat (limited to 'Biz/Bild.hs')
-rw-r--r--Biz/Bild.hs149
1 files changed, 131 insertions, 18 deletions
diff --git a/Biz/Bild.hs b/Biz/Bild.hs
index 983f778..ee0d78a 100644
--- a/Biz/Bild.hs
+++ b/Biz/Bild.hs
@@ -3,10 +3,122 @@
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}
--- | A general purpose build tool.
---
--- - with a nix build, results are linked in _/bild/nix/<target>
--- - for a dev build, results are stored in _/bild/dev/<target>
+{- | A general purpose build tool.
+
+Not all of the below design is implemented. Currently:
+
+- with a nix build, results are linked in _/bild/nix/<target>
+- for a dev build, results are stored in _/bild/dev/<target>
+
+-----------------------------------------------------------------------------
+
+== Design constraints
+
+ * only input is a namespace, no subcommands, no packages
+
+ * no need to write specific build rules
+
+ * one rule for hs, one for rs, one for scm, and so on
+
+ * no need to distinguish between exe and lib, just have a single output
+
+ * never concerned with deployment/packaging - leave that to another tool
+ (scp? tar?)
+
+== Features
+
+ * namespace maps to filesystem
+
+ * no need for `bild -l` for listing available targets. Use `ls` or `tree`
+
+ * you build namespaces, not files/modules/packages/etc
+
+ * namespace maps to language modules
+
+ * build settings can be set in the file comments
+
+ * pwd is always considered the the source directory, no `src` vs `doc` etc.
+
+ * build methods automaticatly detected with file extensions
+
+ * flags modify the way to interact with the build, some ideas:
+
+ * -s = jump into a shell and/or repl
+
+ * -p = turn on profiling
+
+ * -t = limit build by type (file extension)
+
+ * -e = exclude some regex in the ns tree
+
+ * -o = optimize level
+
+== Example Commands
+
+> bild [-spt] <target..>
+
+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 `.` for the current directory. Build outputs will go
+into the _/bild directory in the root of the project.
+
+> bild a.b
+
+Or `bild a/b`. This shows building a file at ./a/b.hs, this will translate to
+something like `ghc --make A.B`.
+
+> bild -s <target>
+
+Starts a repl/shell for target.
+ - if target.hs, load ghci
+ - if target.scm, load scheme repl
+ - if target.clj, load a clojure repl
+ - if target.nix, load nix-shell
+ - and so on.
+
+> bild -p <target>
+
+build target with profiling (if available)
+
+> bild -t nix target
+
+only build target.nix, not target.hs and so on (in the case of multiple
+targets with the same name but different extension).
+
+== Build Metadata
+
+Metadata is set in the comments with a special syntax. For third-party deps,
+we list the deps in comments in the target file, like:
+
+> -- : dep aeson
+
+The output executable is named with:
+
+> -- : exe my-program
+
+or
+
+> -- : exe my-ap.js
+
+When multiple compilers are possible (e.g. ghc vs ghcjs) we chose ghcjs when
+the target exe ends in .js.
+
+This method of setting metadata in the module comments works pretty well,
+and really only needs to be done in the entrypoint module anyway.
+
+Local module deps are included by just giving the repo root to the compiler
+that bild calls out to.
+
+== Questions
+
+ * how to handle multiple output formats?
+
+ * e.g. that ghcjs and ghc take the same input files...
+
+ * say you have a .md file, you want to bild it to pdf, html, and more. What
+ do?
+
+-}
module Biz.Bild where
import Alpha hiding ((<.>), sym)
@@ -16,9 +128,9 @@ import qualified Data.Text as Text
import qualified System.Directory as Dir
import qualified System.Environment as Env
import qualified System.Exit as Exit
-import System.FilePath ((<.>), (</>))
+import System.FilePath ((</>))
import qualified System.Process as Process
-import Text.Regex.Applicative
+import qualified Text.Regex.Applicative as Regex
import qualified Prelude
main :: IO ()
@@ -55,10 +167,11 @@ analyze s = do
root <- Env.getEnv "BIZ_ROOT"
cwd <- Dir.getCurrentDirectory
-- this is a hack to support multiple file types. Ideally we would just detect
- -- which file extensions exist
+ -- which file extensions exist, then return [Target], which can then be built
+ -- in parallel
let path = cwd </> reps "." "/" s |> reps "/hs" ".hs" |> reps "/nix" ".nix"
content <- lines </ Prelude.readFile path
- let exe = content /> match metaExe |> catMaybes |> head |> require "exe"
+ let exe = content /> Regex.match metaExe |> catMaybes |> head |> require "exe"
return
Target
{ namespace =
@@ -69,8 +182,8 @@ analyze s = do
|> reps ".nix" ""
|> reps "/" "."
|> List.stripPrefix "."
- >>= match metaNamespace,
- deps = content /> match metaDep |> catMaybes,
+ >>= Regex.match metaNamespace,
+ deps = content /> Regex.match metaDep |> catMaybes,
compiler =
if ".hs" `List.isSuffixOf` path
then if ".js" `List.isSuffixOf` exe then Ghcjs else Ghc
@@ -133,19 +246,19 @@ build Target {..} = do
qualifiedTarget
]
-metaNamespace :: RE Char Namespace
-metaNamespace = name <> many (sym '.') <> name
+metaNamespace :: Regex.RE Char Namespace
+metaNamespace = name <> Regex.many (Regex.sym '.') <> name
where
- name = many (psym Char.isUpper) <> many (psym Char.isLower)
+ name = Regex.many (Regex.psym Char.isUpper) <> Regex.many (Regex.psym Char.isLower)
-metaDep :: RE Char Dep
-metaDep = string "-- : dep " *> many (psym Char.isAlpha)
+metaDep :: Regex.RE Char Dep
+metaDep = Regex.string "-- : dep " *> Regex.many (Regex.psym Char.isAlpha)
-metaExe :: RE Char Exe
-metaExe = string "-- : exe " *> many (psym (/= ' '))
+metaExe :: Regex.RE Char Exe
+metaExe = Regex.string "-- : exe " *> Regex.many (Regex.psym (/= ' '))
require :: Text -> Maybe a -> a
-require s (Just x) = x
+require _ (Just x) = x
require s Nothing = panic <| s <> " not found"
-- | Replace 'a' in 's' with 'b'.