Skip to content

Releases: vito/bass

v0.12.0: still bassy after all these years

18 Apr 05:10
3f1a34b
Compare
Choose a tag to compare

Hi! It's been a while.

This is a pretty big release - the first since November 2022!

All the major changes are included below, in no particular order.

bass 🤝 Dockerfiles

Bass can now (docker-build) Dockerfiles:

(use (.git (linux/alpine/git)))

(docker-build
  ; directory containing Dockerfile
  git:github/moby/buildkit/ref/master/
  ; platform to build
  {:os "linux"})

But also, Bass can now be used in a Dockerfile 🤯:

# syntax = basslang/frontend:0.12.0

(use (*dir*/bass/bass.bass))

(def dist
  (bass:dist *dir* "dev" "linux" "amd64"))

(-> (from (linux/alpine)
      ($ cp dist/bass /usr/local/bin/bass))
    (with-entrypoint ["bass"]))

This is all incredibly experimental and you'll need bleeding-edge versions of everything, but it's a fun proof of concept!

In general it's better to integrate with Dockerfiles than to pretend Bass exists in a world where it has somehow replaced them. It means you can use Bass anywhere you can use a Dockerfile, and it means you can be downstream of projects that use Dockerfiles.

ignore bustas with (glob)

You can now (glob) paths to prevent boring files from busting caches.

(glob *dir* ./**/*.go ./Makefile)
; => <host: .>/?[./**/*.go ./Makefile]

(glob *dir* ./**/*.go ./Makefile ! ./main.go ./std/*.bass)
; => <host: .>/?[./**/*.go ./Makefile ./std/*.bass]![./main.go]

; run tests only when *.go files change
(cd (glob *dir* ./**/*.go)
  ($ go test ./...))

This is a pretty huge feature in hindsight since it gives you total control over when things should rerun.

For example, Bass bundles a shim executable that needs to be built for each platform. It's slow to build and package, but changes infrequently. I had to resort to git specific trickery to scope its build to its own changes, but now I can just use (glob)!

it'll be all (write)

Bass can now (write) to host paths:

; write a thunk's output to disk
(write (from (linux/alpine) ($ echo "Hello!"))
       ./hello.txt)

; write a path to disk
(use (.git (linux/alpine/git)))
(write git:github/vito/bass/ref/main/README.md
       *dir*/hello.md)

After coming back to Bass I noticed I had a confusing blend of inter-dependent Bash and Bass scripts in my repo. Lots of Bass scripts expected you to pipe them to bass --export and direct that to disk, so a lot of Bass scripts had a corresponding Bash script for doing just that.

Now those Bash scripts are gone. 🎉 I was hesitant to allow this before, because I liked the idea of Bass being "pure" and isolated, never touching the host machine. But if it means writing less Bash, it seems worth it.

Note that you can only write to host paths that the script has access to, so Bass scripts are still somewhat "pure" in the sense that they can only write to explicit inputs. (*dir*/../ will yell at you.)

(publish) and (export) thunks

Bass can now (publish) a thunk directly to a container registry, or you can (export) a thunk to create a "virtual" OCI archive path that you can (write) to disk.

(def foo
  (from (linux/alpine)
    ($ touch ./foo)))

; publish to Docker Hub at vito/foo:latest
(publish foo "vito/foo:latest")
; => {:repository "docker.io/vito/foo" :tag "latest" :digest "sha256:60f786f7639880846f853388cd668d95f619749b0086b127ad030dd9fc7dd0a3"}

; write an OCI tarball to disk
(write (export foo) *dir*/image.tar)

; read it, because why not?
(next (read (export foo) :tar))
; => <fs>/blobs/

Similar to before, adding these allowed me to delete a few Bash scripts and write more Bass.

ENTRYPOINT & CMD gain some respect

Bass now has (with-entrypoint) and (with-default-args) for configuring a container image's ENTRYPOINT and CMD.

(-> (from (linux/alpine)
      ($ cp dist/bass /usr/local/bin/bass))
    (with-entrypoint ["bass"]))

Now that (publish) and (export) are directly part of the language, it seemed only right to also let you configure an ENTRYPOINT and CMD if you want to.

Bass will also automatically run the entrypoint for an image if no command is otherwise specified:

(linux/hello-world) ; now returns a thunk
(run (linux/hello-world))

Up until now, Bass has never respected a container's entrypoint or default command. You could (from) it to hop inside, but you couldn't just, you know, run it. Now it will run in scenarios where running is required and no command has been provided.

This change is backwards compatible. ($) still doesn't respect entrypoint, so thunks created using it work similar to Dockerfiles.

To run a command using the entrypoint, use ($$):

(run (from (linux/alpine/git) ($$ version)))

Dagger runtime: almost prime-time

The Dagger runtime is nearly feature-complete, and Bass will automatically use it if it detects one available (e.g. in dagger run).

  • Dagger now has Bass-style services, so now it can run service thunks.

  • Dagger can now run thunks loaded from OCI achives. The Buildkit runtime also has much better support for these.

  • Dagger can now run insecure! thunks (i.e. privileged builds).

  • Dagger now has a much better secrets implementation.

  • Thunk timestamps are now normalized to 1985, just like the Buildkit runtime.

  • Cache paths now support synchronization control in both the Dagger and Buildkit runtime.

The two remaining feature gaps are TLS and the niche capability to run commands from cache paths.

What's Changed

Breaking Changes ⚠️

  • redo (assert) for better error messages by @vito in #274
  • Add (glob), (only-globs), and (except-globs) for fine-grained caching via include/exclude glob patterns by @vito in #282

New Features ✨

  • use Buildkit's new OCI stores feature for image archives by @vito in #266
  • Dagger runtime: services, stable timestamps, locked cache access by @vito in #267
  • bump to Dagger v0.5.0 by @vito in #268
  • Dagger secrets by @vito in #269
  • Add (write), (publish), and (docker-build) by @vito in #270
  • add (export): returns a virtual OCI tarball file by @vito in #273
  • Support configuring ENTRYPOINT and CMD by @vito in #271
  • Dagger: auto-detect runtime, support loading OCI images by @vito in #276
  • (cache-dir) can set cache concurrency, now defaults to :shared by @vito in #275
  • Buildkit frontend by @vito in #272
  • Buildkit runtime: support loading Docker format tarballs by @vito in #278
  • add (refute); opposite of (assert) by @vito in #277
  • Dockerfiles: add Dagger support, stop respecting workdir by @vito in #279
  • Optimize OCI archive imports, fix up Bass's build by @vito in #281

Full Changelog: v0.11.0...v0.12.0

v0.11.0: this one goes to eleven

28 Nov 01:42
0d25150
Compare
Choose a tag to compare

Quick relevant life update: I work at Dagger now. 🥳

Dagger solves the same problems as Bass, but it's an API instead of a language. If you're interested in what Bass can do but you don't wanna learn a new language, Dagger might be a better fit. You can check the Dagger docs to see if there's already an SDK for your preferred language.

This release of Bass adds a Dagger runtime I've been building to dogfood the Dagger Go SDK and core API. There are a few pieces missing so it's not quite a drop-in replacement for the Buildkit runtime yet, but it's looking like a perfect fit!

Aside from all that, this release is a grab bag of assorted features:

  • 5 new bindings: concat, take-all, collect, assert, strings:length
  • 2 new protocols: :lines, :tar
  • 1 deprecated binding: append (replaced by concat)

...plus a few other fixes and tweaks. All the details are below.

See you next time!

What's Changed

New Features ✨

  • bass --runner reconnects when connection breaks by @vito in #247
  • add (take-all) for reading all values from a pipe source by @vito in #248
  • add :lines protocol by @vito in #249
  • duplicate concat as a replacement for append by @pfiaux in #242
  • introduce Custodians, refactor (read), add (assert) by @vito in #261
  • add (collect) by @vito in #263
  • add (strings:length) by @vito in #262
  • add tar protocol, use it to test runtime exporting by @vito in #264
  • add Dagger runtime by @vito in #259

Fixed Bugs 🐛

  • don't ignore caches for services by @vito in #244
  • auto-rotate expired TLS certs, refactor test setup by @vito in #260

Other Changes

New Contributors

Full Changelog: v0.10.0...v0.11.0

v0.10.0, at your service

29 Aug 21:26
Compare
Choose a tag to compare

This is a big release that overhauls the networking stack and adds a new kind of value: a thunk addr.

thunk ports & addrs

Thunks can now provide TCP ports using with-port which can be referenced with addr to construct a thunk addr:

(def srv
  (-> ($ python -m http.server "80")
      (with-image (linux/python))
      (with-port :http 80)))

(-> ($ wget (addr srv :http "http://$host:$port"))
    (with-image (linux/alpine))
    run)

A thunk addr is a lot like a thunk path except it represents an address to another concurrently running thunk's port, instead of a completed thunk's filesystem path.

When using a thunk addr you don't need to worry about managing the lifecycle of the service that the thunk represents. The service will be run lazily, de-duplicated across multiple Bass runs, and stopped when all clients go away.

The advantage of this approach over traditional service lifecycle management parallels the advantages of using thunk paths instead of managing state in a local filesystem. It allows thunks that depend on services provided by other thunks to remain reproducible, just like thunks that depend on files created by other thunks.

bridge networking & DNS

To prevent port collisions, thunks no longer run in the host network. Instead they run in a bridge network where each thunk has its own IP and reaches other thunks using DNS.

Using DNS is important because IPs are not reproducible. If thunks reached each other using direct container IPs then caches would be busted every time a service runs.

Now that thunks run in their own network, you can't use Bass to run and expose services to the host machine. This may be added in a future release via port forwarding. Alternatively you could take the path-name (a bit of a misnomer) of the thunk and reverse-proxy to its container port using the same DNS server that thunks use.

automatic TLS

Thunks may also use TLS. A unique "bass" certificate authority is generated by the runtime and automaticaly trusted by all thunks that it runs.

To generate a certificate for a thunk, use with-tls:

(def registry-mirror
  (let [config {:version "0.1"
                :http {:addr "0.0.0.0:5000"
                :tls {:certificate "/registry.crt"
                :key "/registry.key"}}
                :storage {:filesystem {:rootdirectory "/var/lib/registry"}}
                :proxy {:remoteurl "https://registry-1.docker.io"}}]
    (-> ($ registry serve (mkfile ./config.yml (json config)))
        (with-image (linux/registry))
        (with-tls /registry.crt /registry.key)
        (with-port :http 5000))))

(defn main []
  (-> (from (linux/alpine)
        ($ apk add curl)
        ($ curl (addr registry-mirror :http "https://$host:$port/v2/")))
      run))

Generating TLS certs is a necessary piece of the puzzle because thunks use their own hash as their hostname and DNS entry. It would be impossible to generate a cert ahead of time and pass it to the thunk because doing so would change the hash!

What's Changed

Breaking Changes ⚠️

  • (with-env) is additive, null values act as tombstones by @vito in #228
  • bridge networking by @vito in #229

New Features ✨

  • add services via thunk addrs by @vito in #225
  • support multiple .locks in bass --bump, + backwards compat. fixes by @vito in #226
  • use DNS for thunk addresses by @vito in #231
  • reap zombies by @vito in #234
  • automatic TLS by @vito in #236

Fixed Bugs 🐛

Other Changes

New Contributors

Full Changelog: v0.9.0...v0.10.0

v0.9.0

22 Jul 19:11
Compare
Choose a tag to compare

Press r to rave. This release was published while recording Ship It! #64. 🎉

rave-demo

What's Changed

New Features ✨

  • rework TUI, now on by default, add rave mode by @vito in #222

Fixed Bugs 🐛

  • fix exporting thunk images again by @vito in #221

Full Changelog: v0.8.1...v0.9.0

v0.8.1

11 Jul 01:56
Compare
Choose a tag to compare

A very quick fix for using Docker credential helpers.

What's Changed

Fixed Bugs 🐛

  • disable clearing system env for now by @vito in #218

Full Changelog: v0.8.0...v0.8.1

v0.8.0: easier setup

11 Jul 01:22
Compare
Choose a tag to compare

This release makes it easier to get started with Bass.

You don't need to set up Buildkit anymore. Bass will start its own Buildkit in Docker instead, a technique yoinked from Dagger. If you already have Buildkit set up you can keep using it. This change just lowers the barrier to entry.

Also: bass --runner (used for Bass Loop) will now display the remote host key and prompt whether to save it instead of erroring out. Huzzah!

What's Changed

New Features ✨

  • auto-start buildkitd in Docker if not configured by @vito in #212
  • add --debug flag, default log level to info by @vito in #213
  • add bass --run for running thunk JSON passed on stdin by @vito in #215
  • bass --runner prompts to add to known_hosts by @vito in #216

Fixed Bugs 🐛

  • fix exporting thunk images by @vito in #214

Other Changes

New Contributors

Full Changelog: v0.7.0...v0.8.0

v0.7.0

04 Jul 23:51
Compare
Choose a tag to compare

More tweaks and polish on the path towards stability.

What's Changed

Breaking Changes ⚠️

  • (start) calls handler with error combiner instead by @vito in #197
  • add distinct type for cache paths by @vito in #202

New Features ✨

  • leverage caching for rendering traces by @vito in #198
  • nicer error for no runtimes available by @vito in #199
  • switch from sha256 to xxh3 by @vito in #203
  • cache fs/thunk paths to more useful filenames by @vito in #204
  • add (when test & body) by @vito in #207
  • add (binds? scope sym) by @vito in #206
  • running bass scripts waits on any concurrently started thunks by @vito in #209

Fixed Bugs 🐛

  • fix randomized bass.lock formatting by @vito in #201

Documentation 📖

  • lazy docs building, more noticeable code autolinks by @vito in #200

Other Changes

  • guide: fix announcement link for bass-loop by @srenatus in #194
  • support configuring session root scope by @vito in #205
  • switch to new github-hook calling convention by @vito in #208

New Contributors

Full Changelog: v0.6.1...v0.7.0

v0.6.1

14 Jun 03:40
Compare
Choose a tag to compare

A couple loose ends tidied up after a bit of dogfooding.

What's Changed

Fixed Bugs 🐛

  • split Run into Run and Read to ensure logs are captured by @vito in #190
  • add (path-stem), restore (path-name) semantics by @vito in #191

Full Changelog: v0.6.0...v0.6.1

v0.6.0: loop!

13 Jun 02:36
Compare
Choose a tag to compare

This release marks a major milestone: 🎉 Bass now runs its own CI! The GitHub Actions stack has been replaced with Bass Loop (www, repo). See the Bass Loop announcement for more details.

There are a few breaking changes to Bass itself, most of them a long time coming. This effort forced the issue on a lot of tentative decisions made in Bass's past, bringing it that much closer to stability. Be sure to check #186 for extended notes.

What's Changed

Breaking Changes ⚠️

  • remaster: a reckoning of weird ideas (+ add gRPC runtime service) by @vito in #186

New Features ✨

  • run git fetch origin REF before git checkout by @vito in #164
  • richer paths: (read)able host paths, generalize annotation paths by @vito in #176
  • add bass --runner for serving runtimes through SSH by @vito in #180

Other Changes

  • add code of conduct by @vito in #166
  • (memo) supports and caches any Readable type by @vito in #177
  • stop relying on /../ hack for host paths by @vito in #179
  • add Close() to runtime interface by @vito in #181
  • support tracking (start)s, show runner connections in progress UI by @vito in #182
  • better error handling by @vito in #188

Full Changelog: v0.5.0...v0.6.0

v0.5.0: a nu (start)

07 May 21:48
Compare
Choose a tag to compare

This release includes a handful of new features and refinements, plus a couple of breaking changes. Check out each PR for details!

What's Changed

Breaking Changes ⚠️

  • structured (log) and (error), remove (logf) and (errorf) by @vito in #156

New Features ✨

  • binding {binds} by @vito in #146
  • add --input (-i) flag for passing inputs on stdin by @vito in #147
  • add (across) and (for), for consuming/looping over streams in parallel by @vito in #148
  • swap bind destructuring order: {foo :foo} -> {:foo foo} by @vito in #152
  • add (start) primitive beneath (run) and (succeeds?) by @vito in #155

Documentation 📖

Other Changes

Full Changelog: v0.4.0...v0.5.0