{"id":13614804,"url":"https://github.com/maxmcd/bramble","last_synced_at":"2025-03-15T14:30:51.683Z","repository":{"id":39853301,"uuid":"272861057","full_name":"maxmcd/bramble","owner":"maxmcd","description":"Purely functional build system and package manager","archived":false,"fork":false,"pushed_at":"2023-03-29T14:47:53.000Z","size":2034,"stargazers_count":191,"open_issues_count":16,"forks_count":5,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-08T19:47:31.247Z","etag":null,"topics":["bramble","build-system","golang","package-manager","reproducibility","starlark"],"latest_commit_sha":null,"homepage":"https://bramble.run/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxmcd.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-06-17T02:39:10.000Z","updated_at":"2025-02-19T18:42:35.000Z","dependencies_parsed_at":"2024-01-17T00:18:52.022Z","dependency_job_id":"d503b6b2-a320-4d7e-a9a4-9e7ba2003694","html_url":"https://github.com/maxmcd/bramble","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmcd%2Fbramble","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmcd%2Fbramble/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmcd%2Fbramble/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxmcd%2Fbramble/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxmcd","download_url":"https://codeload.github.com/maxmcd/bramble/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243742688,"owners_count":20340687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bramble","build-system","golang","package-manager","reproducibility","starlark"],"created_at":"2024-08-01T20:01:05.826Z","updated_at":"2025-03-15T14:30:51.090Z","avatar_url":"https://github.com/maxmcd.png","language":"Go","funding_links":[],"categories":["Go","Users"],"sub_categories":[],"readme":"![](./notes/animated.svg)\n\n\u003ch1 align=\"center\"\u003eBramble\u003c/h1\u003e\n\n- [Project Status](#project-status)\n  - [Feature Status](#feature-status)\n- [Installation](#installation)\n  - [Linux](#linux)\n- [Hello World](#hello-world)\n- [Spec](#spec)\n  - [Introduction](#introduction)\n  - [Project configuration](#project-configuration)\n    - [Package metadata](#package-metadata)\n    - [bramble.lock](#bramblelock)\n  - [Command Line](#command-line)\n    - [`bramble build`](#bramble-build)\n    - [`bramble run`](#bramble-run)\n    - [`bramble ls`](#bramble-ls)\n    - [`bramble repl`](#bramble-repl)\n    - [`bramble shell`](#bramble-shell)\n    - [`bramble gc`](#bramble-gc)\n  - [Dependencies](#dependencies)\n  - [Config language](#config-language)\n    - [.bramble, default.bramble and the load() statement](#bramble-defaultbramble-and-the-load-statement)\n    - [derivation()](#derivation)\n    - [run()](#run)\n    - [test()](#test)\n    - [Sys module](#sys-module)\n    - [Assert module](#assert-module)\n    - [Files builtin](#files-builtin)\n    - [Dependencies](#dependencies-1)\n  - [Builds](#builds)\n    - [Derivations that output derivations](#derivations-that-output-derivations)\n    - [URL Fetcher](#url-fetcher)\n    - [Git Fetcher](#git-fetcher)\n    - [The build sandbox](#the-build-sandbox)\n\u003chr\u003e\n\nBramble is a work-in-progress functional build system inspired by [Nix](https://nixos.org/).\n\nBramble is a functional build system that intends to be a user-friendly, robust, and reliable way to build software. Here are some if the ideas behind it:\n\n- **Project Based**: Every project has a `bramble.toml` and `bramble.lock` file that track dependencies and other metadata needed to build the project reliably.\n- **Reproducible**: All builds are assumed to be reproducible. Every build must consistently return the same output given the same input. You can write builds that aren't reproducible but they'll likely break things.\n- **Rootless First:**: Where possible, no root permissions are required to run. For sandboxing, user namespaces are used on Linux and `sandbox-exec` is used on macOS. Unclear how this will work beyond Linux and macOS.\n- **Daemonless**: Builds are executed directly and not handed off to a daemon.\n- **Sandboxed**: All builds are sandboxed, running software with Bramble will be sandboxed by default. Builds also take as little input as possible (no args, no environment variables, no network). Some of these might be relaxed as the project evolves, but things will hopefully stay locked down.\n- **Dependencies**: Dependencies are stored in repositories. You might reference them with `load(\"github.com/maxmcd/busybox\")` in a build file or `bramble build bitbucket.org/maxm/foo:foo` from the command line. Dependencies are project specific.\n- **Content-Addressable Store**: Build outputs and build inputs are stored in directories that are named with the hash of their contents. This ensured build output can be verified and\n- **Remote Build**: Future support for remote build execution.\n- **Starlark**: The configuration language [starlark](https://github.com/google/starlark-go) is used to define builds.\n- **Diverse Build Environment Support**: Will have first class support for all major operating systems and potentially even support for the browser, webassembly, FAAS, and others. (Bramble is Linux-only at the moment).\n\n## Project Status\n\nMany things are broken, would not expect this to work or be useful yet. The list of features seems to be solidifying so hopefully things will be more organized soon. If you have ideas or would like to contribute please open an issue.\n\n### Feature Status\n\n- [x] Basic Build Functionality\n- [x] Store Content Relocation\n- [ ] Sandboxing\n    - [x] Linux\n    - [ ] OSX\n- [x] \"Fetch\" Build Rules\n    - [x] Fetch URL\n    - [x] Fetch Git Repo\n- [x] Remote Dependencies\n- [ ] Remote Builds\n- [ ] Recursive Builds\n- [ ] Documentation Generation\n- [ ] Docker/OCI Container Build Output\n\n## Installation\n\nInstall with `go get github.com/maxmcd/bramble` or download a recent binary release. Linux is the only supported OS at the moment. macOS support should be coming soon, others much later.\n\n### Linux\n\nIn order for rootless/userspace sandboxing to work \"User Namespaces\" must be compiled and enabled in your kernel:\n\n- Confirm `CONFIG_USER_NS=y` is set in your kernel configuration (normally found in `/proc/config.gz`)\n  ```bash\n  $ cat /proc/config.gz | gzip -d | grep CONFIG_USER_NS\n  CONFIG_USER_NS=y\n  ```\n- Arch/Debian: `echo 1 \u003e /proc/sys/kernel/unprivileged_userns_clone`\n- RHEL/CentOS 7: `echo 28633 \u003e /proc/sys/user/max_user_namespaces`\n\n## Hello World\n\nHere's an example project that downloads busybox and uses it to create a script that says \"Hello world!\".\n\n**./bramble.toml**\n```toml\n[package]\nname = \"github.com/maxmcd/hello-example\"\nversion = \"0.0.1\"\n```\n\n**./default.bramble**\n```python\ndef fetch_url(url):\n    \"\"\"\n    fetch_url is a handy wrapper around the built-in fetch_url builder. It just\n    takes the url you want to fetch.\n    \"\"\"\n    return derivation(name=\"fetch-url\", builder=\"fetch_url\", env={\"url\": url})\n\n\ndef fetch_busybox():\n    return fetch_url(\"https://brmbl.s3.amazonaws.com/busybox-x86_64.tar.gz\")\n\n\ndef busybox():\n    \"\"\"\n    busybox downloads the busybox binary and copies it to an output directory.\n    Symlinks are then created for every command busybox supports.\n    \"\"\"\n    return derivation(\n        name=\"busybox\",\n        builder=fetch_busybox().out + \"/busybox-x86_64\",\n        args=[\"sh\", \"./script.sh\"],\n        sources=files([\"./script.sh\"]),\n        env={\"busybox_download\": fetch_busybox()},\n    )\n\n\ndef hello_world():\n    bb = busybox()\n    PATH = \"{}/bin\".format(bb.out)\n\n    return derivation(\n        \"say_hello_world\",\n        builder=bb.out + \"/bin/sh\",\n        env=dict(PATH=PATH, busybox=bb.out),\n        args=[\n            \"-c\",\n            \"\"\"set -e\n\n        mkdir -p $out/bin\n        touch $out/bin/say-hello-world\n        chmod +x $out/bin/say-hello-world\n\n        echo \"#!$busybox/bin/sh\" \u003e $out/bin/say-hello-world\n        echo \"$busybox/bin/echo Hello World!\" \u003e\u003e $out/bin/say-hello-world\n\n        # try it out\n        $out/bin/say-hello-world\n        \"\"\",\n        ],\n    )\n```\n\n**./script.sh**\n```bash\nset -e\n$busybox_download/busybox-x86_64 mkdir $out/bin\n$busybox_download/busybox-x86_64 cp $busybox_download/busybox-x86_64 $out/bin/busybox\ncd $out/bin\nfor command in $(./busybox --list); do\n\t./busybox ln -s busybox $command\ndone\n```\n\nIf you copy these files into a directory you can build it like so:\n```\n$ bramble build ./:hello_world\nbramble path directory doesn't exist, creating\n✔ busybox-x86_64.tar.gz - 332.830943ms\n✔ busybox - 88.136237ms\n✔ url_fetcher.tar.gz - 424.225793ms\n✔ url_fetcher - 46.129651ms\n✔ fetch-url - 313.461369ms\n✔ busybox - 152.799168ms\n✔ say_hello_world - 29.742436ms\n```\n\nHuh, what's confusing. What are all these builds in our output? Bramble needs to pull some dependencies itself in order to fetch and unpack the url provided. This is so that you can pin the internal functionality of bramble to a specific version. This isn't all hooked up yet, but for the moment you can see the internals being built in the build output.\n\nNow that the build is complete you'll see that a `bramble.toml` file has been written to the project directory.\n\n**./bramble.lock**\n```toml\n[URLHashes]\n  \"basic_fetch_url https://brmbl.s3.amazonaws.com/busybox-x86_64.tar.gz\" = \"uw5ichj6dhcccmcts6p7jq6etzlh5baf\"\n  \"basic_fetch_url https://brmbl.s3.amazonaws.com/url_fetcher.tar.gz\" = \"p2vbvabkdqckjlm43rf7bfccdseizych\"\n  \"fetch_url https://brmbl.s3.amazonaws.com/busybox-x86_64.tar.gz\" = \"uw5ichj6dhcccmcts6p7jq6etzlh5baf\"\n```\n\nThese are the three archives we had to download in order for the build to run. This will ensure that if we ever download these files again, the contents will match what we expect them to.\n\nWe can use `bramble run` to run the resulting script.\n```\n$ bramble run ./:hello_world say-hello-world\nHello World!\n```\n\nThat's it! Your first build and run of a Bramble derivation.\n\n\n## Spec\n\nThis is a reference manual for Bramble. Bramble is a work-in-progress. I started writing this spec to solidify the major design decisions, but everything is still very much in flux. There are scattered notes in the [notes folder](./notes) as well.\n\n### Introduction\n\nBramble is a functional build system and package manager. Bramble is project-based, when you run a build or run a build output it must always be done in the context of a project.\n\nHere are three example use-cases that Bramble hopes to support and support well.\n\n1. **Running a build or a command related to a project**. Often, code repositories want to explain how to build or run their software. Bramble aims to be one of the safest and most reliable ways to do that. A `bramble build` or `bramble run` within a project will use the `bramble.toml`, `bramble.lock` and source files to fetch dependencies from a cache or build them from source. Additionally `bramble run` commands are sandboxed by default, so Bramble should be a good choice to run unfamiliar software.\n2. **Running arbitrary software from the internet**. Running `bramble run github.com/username/project:function binary` will pull down software from that repo, build it, and run it within a sandbox on a local system. `bramble run` is sandboxed by default and aims to provide a safe and reproducible way to run arbitrary software on your system.\n3. **Build a Docker/OCI container**. Any `bramble run` call can be packaged up into a container containing only the bare-minimum dependencies for that program to run.\n4. **Future use-cases**. Support for WASM build environments, support for running builds in a browser. Tight integration with IDEs.\n\n### Project configuration\n\nEvery Project has a `bramble.toml` file that includes configuration information and a `bramble.lock` file that includes hashes and other metadata that are used to ensure that the project can be built reproducibly.\n\n#### Package metadata\n\n```toml\n[package]\nname = \"github.com/maxmcd/bramble\"\n```\n\nA project must include a module name. If it's expected that this project is going to be importable as a module then the module name must match the location of the repository where the module is stored.\n\n#### bramble.lock\n\n```toml\n[URLHashes]\n  \"https://brmbl.s3.amazonaws.com/busybox-x86_64.tar.gz\" = \"2ae410370b8e9113968ffa6e52f38eea7f17df5f436bd6a69cc41c6ca01541a1\"\n```\n\nThe `bramble.lock` file stores hashes so that \"fetch\" builders like \"fetch_url\" and \"fetch_git\" can ensure the contents they are downloading have the expected content. This file will also include various hashes to ensure dependencies and sub-dependencies can be reliably re-assembled.\n\n### Command Line\n\n#### `bramble build`\n\n```\nbramble build [options] \u003cmodule or path\u003e:\u003cfunction\u003e\nbramble build [options] \u003cpath or path\u003e\nbramble build [options] \u003cpath\u003e/...\n```\n\nThe `build` command is used to build derivations returned by bramble functions. Calling `build` with a module location and function will call that function, take any derivations that are returned, and build that derivation and its dependencies.\n\nHere are some examples:\n```\nbramble build ./tests/basic:self_reference\nbramble build github.com/maxmcd/bramble:all github.com/maxmcd/bramble:bash\nbramble build github.com/username/repo/subdirectory:all\nbramble build github.com/maxmcd/bramble/lib\nbramble build github.com/maxmcd/bramble/...\nbramble build github.com/maxmcd/bramble/tests/...\nbramble build ./...\n```\n\n#### `bramble run`\n\n```\nbramble run [options] \u003cmodule or path\u003e:\u003cfunction\u003e [args...]\n```\n\n#### `bramble ls`\n\n```\nbramble ls \u003cpath\u003e\n```\n\nCalls to `ls` will search the current directory for bramble files and print their public functions with documentation. If an immediate subdirectory has a `default.bramble` documentation will be printed for those functions as well.\n\n```\n$ bramble ls\nModule: github.com/maxmcd/bramble/\n\n    def print_simple()\n\n    def bash()\n\n    def all()\n\n\nModule: github.com/maxmcd/bramble/lib\n\"\"\"\nLib provides various derivations to help build stuff\n\"\"\"\n\n    def cacerts()\n        \"\"\"cacerts provides known certificate authority certificates to verify TLS connections\"\"\"\n\n    def git()\n\n    def git_fetcher()\n\n    def git_test()\n\n    def zig()\n\n    def busybox()\n```\n\n#### `bramble repl`\n\n`repl` opens up a read-eval-print-loop for interacting with the bramble [config language](#config-language). You can make derivations and call other built-in functions. The repl has limited use because you can't build anything that you create, but it's a good place to get familiar with how the built-in modules and functions work.\n\n#### `bramble shell`\n\n`shell` takes the same arguments as `bramble build` but instead of building the final derivation it opens up a terminal into the build environment within a build directory with environment variables and dependencies populated. This is a good way to debug a derivation that you're building.\n\n#### `bramble gc`\n\n`gc` searches for all known projects (TODO: link to what \"known projects\" means), runs all of their public functions and calculates what derivations and configuration they need to run. All other information is deleted from the store and project configurations.\n\n### Dependencies\n\n\n\n### Config language\n\nBramble uses [starlark](https://github.com/google/starlark-go) for its configuration language. Starlark generally a superset of Python, but has some differences that might trip up more experienced Python users. When in doubt would be sure to check out the [lamnguage spec](https://github.com/google/starlark-go/blob/master/doc/spec.md).\n\nHere is a typical bramble file:\n\n```python\n# Load statements\nload(\"github.com/maxmcd/bramble/lib/stdenv\")\nload(\"github.com/maxmcd/bramble/lib\")\nload(\"github.com/maxmcd/bramble/lib/std\")\n\n\ndef fetch_a_url():\n    return std.fetch_url(\"https://maxmcd.com/\")\n\n\ndef step_1():\n    bash = \"%s/bin/bash\" % stdenv.stdenv()\n    # A derivation, the basic building block of our builds\n    return derivation(\n        \"step_1\",\n        builder=bash,\n        env=dict(bash=bash),\n        # Use of the `files()` builtin\n        sources=files([\"./step1.sh\"]),\n        args=[\"./step1.sh\"],\n    )\n```\n\n#### .bramble, default.bramble and the load() statement\n\nBramble source files are stored in files with a `.bramble` file extension. Files can reference other bramble files by using their module names. This project has the module name `github.com/maxmcd/bramble` so if I want to access a file at `./tests/basic.bramble` I can import it with `load(\"github.com/maxmcd/bramble/tests/basic\")`. Relative imports aren't supported.\n\nThe `default.bramble` filename is special. If a directory has a `default.bramble` in it then we can import that directory as a package and all functions in the `default.bramble`. In the above example, if the file was called `default.bramble` instead of `basic.bramble` we could import it with `load(\"github.com/maxmcd/bramble/tests\")`.\n\nIf you call `load(\"github.com/maxmcd/bramble/tests\")` at the top of a bramble file a new global variable named `tests` will be loaded into the program context. `tests` will have an attribute for all global variables in the `default.bramble` file unless they begin with an underscore.\n\n```python\n# ./tests/default.bramble\ndef foo():\n  print(\"hi\")\ndef _bar():\n  print(\"hello\")\n```\n\n```python\n# In a `bramble repl`\n\u003e\u003e\u003e load(\"github.com/maxmcd/bramble/tests\")\n\u003e\u003e\u003e tests\n\u003cmodule \"github.com/maxmcd/bramble/tests\"\u003e\n\u003e\u003e\u003e dir(tests)\n[\"foo\"]\n\u003e\u003e\u003e tests.foo()\nhi\n\u003e\u003e\u003e tests._bar()\nTraceback (most recent call last):\n  \u003cstdin\u003e:1:6: in \u003cexpr\u003e\nError: module has no ._bar field or method\n```\n\n#### derivation()\n\n```python\nderivation(name, builder, args=[], sources=[], env={}, outputs=[\"out\"], platform=sys.platform)\n```\n\nDerivations are the basic building block of a bramble build. Every build is a graph of derivations. Everything that is built has a derivation and has dependencies that are derivations.\n\nA derivation `name` is required to help with visibility and debugging. It's helpful to have derivation names be unique in a project, but this is not an enforced requirement.\n\nA `builder` can be on of the default built-ins: `[\"fetch_url\", \"fetch_git\", \"derivation_output\"]` or it can point to an executable that will be used to build files.\n\n\n`args` are the arguments that as passed to the builder. `env` defines environment variables that are set within the build environment. Bramble detects dependencies by scanning for derivations referenced within a derivation. `builder`, `args` and `env` are the only parameters that can reference other derivations, so you can be sure that if a derivation isn't referenced in one of those parameters that it won't be available to the build.\n\n`sources` contains references to source files needed for this derivation. Use the `files` builtin to populate sources for a given derivation.\n\n`outputs` defines this Derivation's outputs. The default is for a derivation to have a single output called \"out\", but you can have one or more output with any name. After a derivation is created, you can reference it's outputs as attributes. If you cast a derivation to a string it returns a reference to the default output.\n\n```python\n\u003e\u003e\u003e b = derivation(\"hi\", \"ho\")\n\u003e\u003e\u003e b\n{{ soen6obfffrahna6ojyc2cgxjx7jcmhv:out }}\n\u003e\u003e\u003e b.out\n\"{{ soen6obfffrahna6ojyc2cgxjx7jcmhv:out }}\"\n\u003e\u003e\u003e c = derivation(\"hi\", \"ho\", outputs=[\"a\", \"b\", \"c\"])\n\u003e\u003e\u003e c\n{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:a }}\n\u003e\u003e\u003e c.a\n\"{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:a }}\"\n\u003e\u003e\u003e c.b\n\"{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:b }}\"\n\u003e\u003e\u003e c.c\n\"{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:c }}\"\n\u003e\u003e\u003e \"{}/bin/bash\".format(c)\n\"{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:a }}/bin/bash\"\n\u003e\u003e\u003e \"{}/bin/bash\".format(c.b)\n\"{{ lvliebpnk6lcalc3sdsvfbrzwlamb4qo:b }}/bin/bash\"\n```\n\n`platform` denotes what platform this derivation can be built on. If the specific platform is available on the current system the derivation will be built.\n\n#### run()\n\nThe run function defines the attributes for running a program from a derivation output. If a call to a bramble function returns a run command that run command and parameters will be executed.\n\n```python\nrun(derivation, cmd, args=[], paths=[], read_only_paths=[], hidden_paths=[], network=False)\n```\n\n#### test()\n\nThe test command creates a test. Any call to the test function will register a test that can be run later. Calls to `bramble test` will run all tests in that directory and it's children. Calls to a specific bramble function like `bramble test ./tests:first` will run any test functions that are called during the function call.\n\n```python\ntest(derivation, args=[])\n```\n\n\n#### Sys module\n\n```python\n\u003e\u003e\u003e sys\n\u003cmodule \"sys\"\u003e\n\u003e\u003e\u003e dir(sys)\n[\"arch\", \"os\", \"platform\"]\n\u003e\u003e\u003e sys.arch\n\"amd64\"\n\u003e\u003e\u003e sys.os\n\"linux\"\n\u003e\u003e\u003e sys.platform\n\"linux-amd64\"\n```\n\n\n#### Assert module\n\n```python\n\u003e\u003e\u003e dir(assert)\n[\"contains\", \"eq\", \"fail\", \"fails\", \"lt\", \"ne\", \"true\"]\n\u003e\u003e\u003e assert.contains(\"hihihi\", \"hi\")\n\u003e\u003e\u003e assert.contains(\"hihihi\", \"how\")\nTraceback (most recent call last):\n  \u003cstdin\u003e:1:16: in \u003cexpr\u003e\n  assert.star:30:14: in _contains\nError: hihihi does not contain how\n```\n\n#### Files builtin\n\n```python\nfiles(include, exclude=[], exclude_directories=True, allow_empty=True)\n```\n\n`files` searches for source files and returns a mutable list.\n\n\n#### Dependencies\n\n### Builds\n\nBramble builds all derivations within a sandbox. There are OS-specific sandboxes that try and provide similar functionality.\n\nA tree of derivations is assembled to build. The tree is walked, compiling dependencies first, until all derivations are built. If a derivation has already been built (TODO: or is available in a remote store) it is skipped.\n\nWhen building a specific derivation the steps are as follows:\n\n1. Create a build directory. These are stored in the store (TODO: why?). They typically look something like this `/home/maxm/bramble/bramble_store_padding/bramble_/bramble_build_directory941760171`.\n2. Copy any file sources needed for this build into the build directory.\n3. Create folders for each output. They look something like this: `/home/maxm/bramble/bramble_store_padding/bramble_/bramble_build_directory451318742/`.\n4. If the derivation has a \"fetch\" builder then that specific builder is run to fetch files using the variables that have been passed.\n5. If the regular builder is used the derivation has to be prepared to be built. Paths in the derivation will reference a fixed known store path `/home/bramble/bramble/bramble_store_padding/bramb/`, so we must replace it with the store path (of equal length) used in this system.\n6. Once the derivation is ready to build the `builder`, `args`, and `env` attributes are taken and used to run a sandbox. The `builder` program is run and `args` are passed to that program. `env` values are loaded as environment variables in alphabetical order.\n7. The output folder locations are loaded by name into the environment variables as well. The value `$out` might have value `/home/maxm/bramble/bramble_store_padding/bramble_/bramble_build_directory451318742/`.\n8. The bramble store is mounted to the sandbox so that the build can access any store values that it needs for a build. All store outputs are read-only, but the build directory and all the outputs directories can be written to. (TODO: should we block access to other store directories?)\n9. If the build exits with a non-zero exit code it's assumed that the build has failed.\n10. Once the build is complete all output directories are hashed so that they can be placed in a folder that is a hash of their contents. Outputs are also searched for any references to dependencies so that the runtime dependencies can be noted. The hashing steps are as follows.\n   1. The build output is tarred up into an archive.\n   2. The mod times and user ids are stripped from the archive.\n   3. References to the build directory are replaced with with a fixed known value so the random number isn't injected into builds. Files from this folder are discarded at the end of the build, so it's ok if we break references.\n   4. The archive is copied for hashing. The copy is scanned for this system's store path and replaced with the reference store path `/home/bramble/bramble/bramble_store_padding/bramb/`. This helps ensure outputs hash the same on different systems.\n   5. References to the output path in the copy are replaced with null bytes.\n   6. The copy is hashed and a folder is created with the hash as the name.\n   7. References to the output folder name are replaced with the hash name.\n   8. The original archive is expanded into the hash-name folder.\n11. The build output hash is added to the derivation (along with all dependency output hashes) before being written to disk.\n12. The output folder locations and final derivation are returned.\n\n#### Derivations that output derivations\n\nThe `derivation_output` derivation outputs a new derivation graph. This graph will be merged with the existing build graph and the build will continue. There are two rules with this builder:\n\n1. No recursive `derivation_output`. If a derivation uses the builder `derivation_output` it must not output any derivations that use that builder. This will likely be supported in the future but is currently disallowed out of caution.\n2. A `derivation_output` must only have the default output \"out\" and the updated derivation graph must also only have a single outputted derivation that has a single default output. When `derivation_output` is built it replaces a node in the build graph with a new graph. Any references to that old node must be overwritten with references to the new output derivation. In order to ensure that replacement is trivial we must ensure that the old node and the new node have identical output structure.\n\nWhen a `derivation_output` is called the resulting derivation graph is written to `bramble.lock` so that the output is not rebuilt on other systems.\n\n#### URL Fetcher\n#### Git Fetcher\n\n\n#### The build sandbox\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxmcd%2Fbramble","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxmcd%2Fbramble","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxmcd%2Fbramble/lists"}