Skip to content

v0.12.0: still bassy after all these years

Latest
Compare
Choose a tag to compare
@vito vito released this 18 Apr 05:10
3f1a34b

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