Skip to content

Commit 78783e4

Browse files
authored
Merge branch 'main' into darwin-sandbox
2 parents c3fad23 + d53b643 commit 78783e4

28 files changed

Lines changed: 873 additions & 960 deletions

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
uses: actions/checkout@v2
1717
- name: Run all tests
1818
run: |
19-
make test
19+
make ci_test
2020
# for your debugging needs
2121
# - name: Setup tmate session
2222
# uses: mxschmitt/action-tmate@v3

Makefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@
33
test: go_test \
44
integration_test
55

6-
go_test: install
6+
ci_test: go_ci_test \
7+
integration_ci_test
8+
9+
gotestsum:
10+
go get gotest.tools/gotestsum
11+
12+
go_ci_test: gotestsum
13+
gotestsum -- -race -v ./...
14+
15+
go_test:
716
go test -race -v ./...
817

918
# just use LICENSE as a file we can harmlessly "touch" and use as a cache marker
@@ -14,6 +23,9 @@ LICENSE: main.go pkg/*/*.go
1423

1524
install: LICENSE
1625

26+
integration_ci_test: install gotestsum
27+
env BRAMBLE_INTEGRATION_TEST=truthy gotestsum -- -v ./pkg/bramble/
28+
1729
integration_test: install
1830
env BRAMBLE_INTEGRATION_TEST=truthy go test -v ./pkg/bramble/
1931

go.mod

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
module github.com/maxmcd/bramble
22

3-
go 1.15
3+
go 1.16
44

55
require (
66
github.com/BurntSushi/toml v0.3.1
77
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054
88
github.com/containerd/console v1.0.0
99
github.com/creack/pty v1.1.11
10+
github.com/davecgh/go-spew v1.1.1
11+
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23
1012
github.com/fsouza/go-dockerclient v1.6.5
11-
github.com/go-git/go-git/v5 v5.2.0
12-
github.com/hashicorp/terraform v0.14.4
13+
github.com/go-git/go-git/v5 v5.3.0
1314
github.com/jaguilar/vt100 v0.0.0-20201024211400-81de19cb81a4
15+
github.com/maxmcd/dag v0.0.0-20210316172417-f02e4b03c6e9
1416
github.com/mholt/archiver/v3 v3.3.1-0.20200626164424-d44471c49aa7
15-
github.com/moby/moby v1.13.1
17+
github.com/minio/sha256-simd v1.0.0
1618
github.com/morikuni/aec v1.0.0
1719
github.com/peterbourgon/ff/v3 v3.0.0
1820
github.com/pkg/errors v0.9.1
@@ -22,6 +24,7 @@ require (
2224
go.uber.org/zap v1.10.0
2325
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
2426
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b
27+
golang.org/x/sys v0.0.0-20210324051608-47abb6519492
2528
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
2629
)
2730

go.sum

Lines changed: 43 additions & 451 deletions
Large diffs are not rendered by default.

lib/default.bramble

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -26,61 +26,15 @@ def zig():
2626
def busybox():
2727
b = std.fetch_url("https://brmbl.s3.amazonaws.com/busybox-x86_64.tar.gz")
2828

29-
commands = """
30-
[, [[, acpid, add-shell, addgroup, adduser, adjtimex, arch, arp, arping, ash, awk,
31-
base64, basename, bc, beep, blkdiscard, blkid, blockdev, bootchartd, brctl, bunzip2,
32-
bzcat, bzip2, cal, cat, chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot,
33-
chrt, chvt, cksum, clear, cmp, comm, conspy, cp, cpio, crond, crontab, cryptpw,
34-
cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df,
35-
dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, dpkg, dpkg-deb, du,
36-
dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, ether-wake,
37-
expand, expr, factor, fakeidentd, fallocate, false, fatattr, fbset, fbsplash, fdflush,
38-
fdformat, fdisk, fgconsole, fgrep, find, findfs, flock, fold, free, freeramdisk, fsck,
39-
fsck.minix, fsfreeze, fstrim, fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep,
40-
groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hexedit, hostid, hostname, httpd,
41-
hush, hwclock, i2cdetect, i2cdump, i2cget, i2cset, i2ctransfer, id, ifconfig, ifdown,
42-
ifenslave, ifplugd, ifup, inetd, init, insmod, install, ionice, iostat, ip, ipaddr,
43-
ipcalc, ipcrm, ipcs, iplink, ipneigh, iproute, iprule, iptunnel, kbd_mode, kill,
44-
killall, killall5, klogd, last, less, link, linux32, linux64, linuxrc, ln, loadfont,
45-
loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod,
46-
lsof, lspci, lsscsi, lsusb, lzcat, lzma, lzop, makedevs, makemime, man, md5sum, mdev,
47-
mesg, microcom, mkdir, mkdosfs, mke2fs, mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat, mknod,
48-
mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mountpoint, mpstat, mt, mv,
49-
nameif, nanddump, nandwrite, nbd-client, nc, netstat, nice, nl, nmeter, nohup, nologin,
50-
nproc, nsenter, nslookup, ntpd, nuke, od, openvt, partprobe, passwd, paste, patch,
51-
pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir, poweroff,
52-
powertop, printenv, printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, rdev,
53-
readahead, readlink, readprofile, realpath, reboot, reformime, remove-shell, renice,
54-
reset, resize, resume, rev, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run-init,
55-
run-parts, runlevel, runsv, runsvdir, rx, script, scriptreplay, sed, sendmail, seq,
56-
setarch, setconsole, setfattr, setfont, setkeycodes, setlogcons, setpriv, setserial,
57-
setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum, sha512sum, showkey, shred, shuf,
58-
slattach, sleep, smemcap, softlimit, sort, split, ssl_client, start-stop-daemon, stat,
59-
strings, stty, su, sulogin, sum, sv, svc, svlogd, svok, swapoff, swapon, switch_root,
60-
sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tcpsvd, tee, telnet, telnetd, test,
61-
tftp, tftpd, time, timeout, top, touch, tr, traceroute, traceroute6, true, truncate, ts,
62-
tty, ttysize, tunctl, ubiattach, ubidetach, ubimkvol, ubirename, ubirmvol, ubirsvol,
63-
ubiupdatevol, udhcpc, udhcpc6, udhcpd, udpsvd, uevent, umount, uname, unexpand, uniq,
64-
unix2dos, unlink, unlzma, unshare, unxz, unzip, uptime, users, usleep, uudecode,
65-
uuencode, vconfig, vi, vlock, volname, w, wall, watch, watchdog, wc, wget, which, who,
66-
whoami, whois, xargs, xxd, xz, xzcat, yes, zcat, zcip
67-
"""
68-
69-
command_list = " ".join(commands.strip().split("\n")).split(", ")
70-
command_list.remove("ln")
71-
command_symlinks = "\n".join([("./ln -s busybox %s" % c) for c in command_list])
72-
command_symlinks
73-
script = (
74-
"""
29+
script = """
7530
set -e
7631
$busybox_download/busybox-x86_64 mkdir $out/bin
7732
$busybox_download/busybox-x86_64 cp $busybox_download/busybox-x86_64 $out/bin/busybox
7833
cd $out/bin
79-
./busybox ln -s busybox ln
80-
%s
34+
for command in $(./busybox --list); do
35+
./busybox ln -s busybox $command
36+
done
8137
"""
82-
% command_symlinks
83-
)
8438

8539
return derivation(
8640
name="busybox",

lib/go/default.bramble

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ load(nix_seed="github.com/maxmcd/bramble/lib/nix-seed")
33
load("github.com/maxmcd/bramble/lib")
44

55

6-
def _bootstrap():
6+
def bootstrap():
77
go1_4 = std.fetch_url("https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz")
88
path = "%s/bin:%s/bin" % (nix_seed.stdenv(), lib.busybox())
99
return derivation(

notes/22-gc.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GC
2+
3+
We want to clean up files we don't need any more. Easiest way to do this is to enumerate all files that we do need and then delete everything else.
4+
5+
For the first version of GC, let's just keep everything we could possibly use?
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/golang/go/issues/30058
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Nix handles early cutoff with fixed output derivations. These must be manually kept up to date.
2+
3+
Because the dependency graph in Bramble is (currently) constructed using the hash of input derivations any change to build input will result in a full rebuild.
4+
5+
I think it's important when thinking about a solution here to remember that all build inputs are either filesystem files or `fetch` derivations, so don't get too creative about storing build state.
6+
7+
### Always use the build output as the derivation hash
8+
9+
When currently injecting a derivation into a child derivation we use a format like this: `{{ tmb75glr3iqxaso2gn27ytrmr4ufkv6d-.drv:out }}`. Alternatively we could replace that with the hash of the output.
10+
11+
I think this is what the steps would look like with this approach:
12+
13+
1. Calculate the entire derivation graph. If we already have build outputs computed use them as the named hash.
14+
2. Find the first derivation that needs to be built. Build it, replace all the child derivations derivation hashes with the output hash. Continue building.
15+
16+
What's the cost here? We wouldn't know the derivations we're going to build without building them, this only means that we don't know in advance which things we're going to have to build. This seems fine (and I think is mandatory for this feature).

notes/25-dynamic-dependencies.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
## Dynamic Dependencies
2+
3+
Nix and Bazel don't allow dynamic dependencies. I think there is an argument to be made that this is the reason their ergonomics are so poor. Nix libs that are intended to build arbitrary projects in a given language rely heavily on code generation. Arguably this is a type of dynamic dependencies.
4+
5+
I think it would be interesting to explore first class support for dynamic dependencies in Bramble. Maybe if they are easy to use and set up we can limit the amount of derivations that need network access. If you can generate arbitrary calls to `fetch_url` within a derivation, then maybe you can get away with just that.
6+
7+
One Idea:
8+
9+
There is a specific type of derivation that outputs starlark code. It is a different color than regular derivations (so we can detect it statically), and only outputs starlark code. This starlark code is run once the derivation is done building. We would need to update the dependency graph as we build.
10+
11+
This has some weird implications because we would still need to reference the build output. Do we just need to ensure that the generated code just outputs a single derivation?
12+
13+
So let's think about numpy.
14+
15+
```python
16+
def foo():
17+
pip_install("numpy")
18+
```
19+
20+
There is no real way to do this because numpy will need to download its own dependencies. So we could either:
21+
22+
1. Download them within the derivations using the network, but then other depedencies might generate their own independent depedencies, which would be duplicated and might conflict.
23+
2. Generate code for each dependency, which totally works, but dosn't have first class support.
24+
25+
26+
```python
27+
def foo():
28+
pip_install("numpy")
29+
30+
def pip_install(name):
31+
deps = fetch_url("dependency_finder.gov/"+name)
32+
derivation(script="""
33+
out = ""
34+
for dep in deps:
35+
out += "fetch_url(dep)\n"
36+
return out
37+
""")
38+
```
39+
40+
Terrible pseudo-code, but basically this derivation returns starlark code with the deps we need to download.
41+
42+
If we go this route, we would need to be able to check if we've generated this derivation on the fly. I think if we don't do that, it would be very hard to do things like: validating current url hashes, without actually building.
43+
44+
We could just stick the outputted starlark into the store somewhere, but it might be better to generate code and keep it in the source of the project. If the interface is just like in the example above `fetch_url("numpy")` then what if a new version of numpy is published? Any time there was a rebuild the url hash would mismatch. I think ideally if we want to replicate something like a Cargo.lock we would need the output of the code generating derivation to be placed within the project tree. That way, that generated file could reference very specific versions of software to fetch. If the end user wanted to fetch a new version they would simply delete the generated file.
45+
46+
This doesn't really remove the need for derivations that access the network. The code generating derivation would still need to make a request for the `numpy` source in order to calculate dependencies.
47+
48+
This kind of thing would mean that you could truly write a derivation like `pip_install("numpy")` without code generation that would require certain setup.
49+
50+
We could also prevent code generated by a code generating derivation from calling another code generating derivation, at least at the start, to limit all kinds gnarly behavior.
51+
52+
----
53+
54+
More thoughts.
55+
56+
This might actually be a good idea. We could then move forward with limiting network functionality only to derivations that use the network. That way we could be sure that after we've processed all derivations initially we can proceed from there without ever using the network.
57+
58+
One complication here is that bramble libraries could use this as well, so we can't generate bramble code and then store it next to the initial source file. Generate code could also depend on passed parmeters, so we wouldn't be able to check a file's lock file just by analyzing the source of that file, we'd need to be sure we were testing it with whatever parmeters were passed to functions in that file.
59+
60+
wait, maybe not, the generating function will always be called without arguments. so maybe we just put the code in the project next to the file that calls the function.
61+
62+
Ok, either way, that needs to be sorted out, and we might want to consider just adding generated code to the lockfile.
63+

0 commit comments

Comments
 (0)