summaryrefslogtreecommitdiff
path: root/Biz/Bild.scm
blob: 1fcae964c2713c8c5565c425c489f4ccdbdef3ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
;;
;; bild - a simple build tool
;;
;;; Notice:
;;
;; This is under active development. For now this is just a convenience wrapper
;; around `nix build`. The below commentary describes how this tool *should*
;; work.
;;
;;; Commentary:
;;
;; 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
;;   - -s = jump into a shell and/or repl
;;   - -p = turn on profiling
;;   - -t = limit build by type
;;   - -e = exclude some regex in the ns tree
;;   - -o = optimize level
;;
;; Example Commands
;;
;;     bild [-rpt] <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 biz.web
;;
;; Or `bild biz/web`. This shows building a file at ./biz/web.hs, this will
;; translate to something like `ghc --make Biz.Web`.
;;
;;     bild -r <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).
;;
;; Here is an example integration with GHC. Given the following command-line
;; invocation to compile the namespace 'com.simatime.bild' which depends on
;; 'com.simatime.lib':
;;
;;     ghc com/simatime/bild.hs -i com/simatime/lib.hs -o _bild/bild -v \
;;         -main-is Biz.Bild.main
;;
;; The general template of which is:
;;
;;     ghc <source> -i <deps..> -o <target> -main-is <target>.main
;;
;; Some definitions:
;;
;; - <source> is some source file
;; - <deps..> is the stack of dependencies
;; - <target> is the target namespace, indicated by 'bild <target>'
;;
;; To fill out the build template, we can parse the file for known
;; namespaces. The general recipe is:
;;
;; 1. Create a list of namespaces in my git repo. This can be cached, or I can
;;    integrate with git somehow.
;; 2. Read the <source> file corresponding to <target>
;; 3. Look for 'import <namespace>', where <namespace> is a namespace in the
;;    aforementioned cache.
;; 4. If found, then save current build as a continuation and compile
;;    <namespace>. Result gets put on the dependency stack
;; 5. When finished, return to building <target>
;;
;; Once the build command template is filled out, we can create the nix expression.
;;
;; Questions
;;
;; - how to import (third-party) dependencies?
;;   1 just don't have them...? yeah right
;;   2 the target.nix could be the build description for target.hs
;;   3 just use a default.nix for the com.whatever
;;   4 have a deps.nix file
;;   5 list them in the file with other settings. Starting with Haskell,
;;     have comments like `{-: PACKAGE base <5.0.0.0 :-}' or `-- : PACKAGE base <5.0.0.0'.
;;     Other languages could use `#:` for the special prefix, basically just
;;     a comment plus colon.
;; - 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?
;;   - i guess the nix file could return a set of drvs instead of a single drv
;;
;; TODO
;; - stream output from 'nix build' subprocess
;; - get rid of guile notes during execution
;; - ns<->path macro
;; - support list (scheme namespace) in ns<->path fns
;;
;;; Code:

(define-module (Biz Bild)
  #:use-module ((ice-9 popen) #:prefix popen/)
  #:use-module ((ice-9 format) #:select (format))
  #:use-module ((ice-9 rdelim) #:prefix rdelim/)
  #:use-module ((Alpha Core) #:select (fmt))
  #:use-module ((Alpha Shell) #:prefix sh/)
  #:use-module ((Alpha String) #:prefix string/)
  #:export (ns?
            ns->path
            path->ns
            main))

(define (main args)
  (let* ((root (sh/exec "git rev-parse --show-toplevel"))
         (target (cadr args))
         (path (ns->path target)))
    (display (fmt ":: bild ~a...\r" target))
    (sh/exec (fmt "nix build -f ~a/default.nix ~a"
                  root target))
    (display (fmt ":: bilt ~a" target))))

(define ns? symbol?)

(define (ns->path ns)
  (let ((to-path (lambda (s) (string/replace-char s #\. #\/))))
    (cond
     ((symbol? ns) (to-path (symbol->string ns)))
     ((string? ns) (to-path ns))
     (else (error "ns should be a string or symbol")))))

(define (path->ns path)
  (let ((to-ns (lambda (s) (string/replace-char s #\/ #\.))))
    (cond
     ((symbol? path) (to-ns (symbol->string path)))
     ((string? path) (to-ns path))
     (else (error "path should be a string or symbol")))))