github.com/warpfork
twitter.com/warpfork
slides.com/warpfork
# I want...
# I want...
# I want...
# I want...
I want to Build Anything
and
I want to Install Anywhere.
warpforge tools
intervene here
warpsys conventions
have hints here
# I want...
it shouldn't be
it is
# I want...
a fundamentally unscientific process
# I want...
it shouldn't be
it is
and god help you when it comes to pursuing reproducibility...
because current tools sure won't help you.
i try to build unigraph from source...
i need to install gcc for one part...
there's a makefile that tries to get jemalloc...
it asks for root??
if you apt install it ahead of time, it's fine
(but this isn't really documented or clear -- you just peek-and-poke try shit and hope)
and i need
i try to build unigraph from source...
and i need .... in addition to the source ...
*(p.s. i'm not picking on unigraph -- it's a super cool project. this is unfortunately _normal_.)
# I want...
it shouldn't be
it is
let's take a practical walk through real experiences...
i try to install emacs on ubuntu...
and then i find either...
apt can give me an outdated version...
or flatpack can give me something...
but it's in weird sandboxes that i didn't ask for and don't want...
or i can install a ppa...
from some random person...
and then actually that doesn't work anyway...
also it somehow broke my apt?? oh wow okay, guess i'll reinstall, holy @#$% cool
okay so maybe i'll use guix, that's declarative and should be good right?
first i'll learn a lisp dialect...
then i will CRASH AND BURN and FAIL TO BOOT
because there aren't even placeholder graphics drivers for any of the hardware i have, lol...
(i appreciate the freedom-maxi attitudes but sometimes they really are not helpful, and yes, i gave up guix bc of this, i'm sorry, i really am)
and i try to find solutions on the mailing list...
and they are all deleted and surpressed...
because it would involve discussion of non-free software...
Why can't I just install things?
Why is this harder than unpacking a tarball?
Why are all these install systems trying to own my whole host and be my whole world?
we need
# I want...
.... but I don't think any of them really did.
# I want...
.... but I don't think any of them really did.
There's a difference between
{trying to make everything fit into your pocket universe}
vs
{trying to make things anyone can use in any universe}.
Distros generally do the former.
I want the latter.
# Everything Sucks
# Everything Sucks
Having a clean room is great.
Building a clean room, then getting a bucket of mud from outside the door, and upending the whole thing on the floor...
...defeats the purpose.
Containers
and i'm sorry, that doesn't really work for me
are totally uncomposable as an install story.
(at least as they have been mass-popularized, so far)
(unless the thing you're installing is a microservice connected only by networking)
we need
Docker -- but not
Warpforge uses containers.
But it allows granular and flexible constructions -- not just big unwieldy monolithic images.
(And it doesn't try to centralize your image storage.)
Bazel -- but not
Warpforge is a build sandbox.
Warpforge is also always hermetic, and it has a lot of tools for sharing snapshots -- both of data and build instructions. Even if you don't have a monorepo! And lets you choose to build or fetch.
Nix -- but not
Warpforge is for functional, declarative builds.
Warpforge is JSON APIs. (If you want a language: Warpforge supports Starlark!)
Warpforge is content-addressed.
# COMPARE
(let's just get this out of the way...)
# Obligatory XKCD Diffusal
XKCD#927 is nice and all.
But sometimes we try to make things better, anyway.
# THE OFFER
A tool for building.
A style for packaging.
and
# THE OFFER
Solves "build anything" and "version together"
and
Solves "install anywhere" and "composable systems"
# THE OFFER
Both. At the same time.
(There's a reason for this, which will become clear shortly.)
# CHAPTER 2
Let's talk about builds, first.
That means: Warpforge.
Let's see it go!
# GOALS
# GOALS
formulas
}
}
}
catalogs
plots
}
replays
# GOALS
formulas
}
}
}
catalogs
plots
}
replays
}
and a fractal of "don't fuck up"
(also, warpsys conventions)
}
# GOALS
# GOALS
... due credit to every other project in this general space:
even if you don't pick all of those, it's a LOT of goals. This work is HARD work.
Formula
RunRecord
Plot
Catalog, Release
Replay
(your templating here)
Starlark
Whatever
# WFAPI
Warpforge API Layers
... are probably the best way to understand it.
<- Simple ---- Fun ->
Formulas
# WFAPI:L1
an API concept for
hashes->build->hashes
Formulas
{
"formula": {
"inputs": {
"/": "ware:tar:57j2Ee9HEtDxRLE6uHA1xvmNB2LgqL3HeT5pCXr7EcXkjcoYiGHSBkFyKqQuHFyGPN"
},
"action": {
"script": {
"interpreter": "/bin/sh",
"contents": [
"mkdir /out && echo 'heyy' > /out/log"
"echo done!"
]
}
},
"outputs": {
"yourlabel": {"from": "/out", "packtype": "tar"},
}
},
"context": {
"warehouses": {
"tar:57j2Ee9HEtDxRLE6uHA1xvmNB2LgqL3HeT5pCXr7EcXkjcoYiGHSBkFyKqQuHFyGPN": "https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/alpine-minirootfs-3.15.0-x86_64.tar.gz"
}
}
}
# WFAPI:L1
Formulas: you run them
# WFAPI:L1
Formulas -> RunRecord
{
"guid": "2fa27e0a-63ab-4924-9b8a-6e2740b983a6",
"time": 1652997810,
"formulaID": "zM5K3SBybw7WHvL8sgFNu8NbL67Qh9nEv7u7C22grAiF4QhriUUK8UMEHjesYW14XrHwywL",
"exitcode": 0,
"results": {
"out": "ware:tar:5bv6aKWCUrYzyCzjXKqzT4VkPwwnhadWP1ZMWXvSFKpZGxgZFGvfaHsVEvkgmWzQD"
}
}
# WFAPI:L1
The "results" map has keys according to your formula's output section.
Some timestamps make each runrecord unique.
(This uniqueness is useful if you want to, for example, store many of them, to use as evidence of reproducibility.
You can find these also in the
`.warpforge/memos` dir,
indexed by formulaID!
Formulas -> RunRecord
# WFAPI:L1
Formulas and RunRecords are always going to be at the bottom of everything you do in Warpforge.
That means everything you do is:
1) introspectable
2) repeatable
3) easy to check for determinism & reproducibility
Where did that run?
# WFAPI:L1
We used containers here!
> I thought you said containers are lame?
No, monolithic images are lame.
Containers are great!
We gave containers a composable input system.
Formulas: one step at a time
# WFAPI:L1
Formulas are the atom of reproducibility and of action in this system.
They're also verbose and limited:
So we need another layer of abstraction to get work done...
# WFAPI:L*
sidenote: about being API driven:
Plots
# WFAPI:L2
for when you need
multiple steps, related by pipes
Plots
# WFAPI:L2
Plots do both.
(and a bit more)
((ingests))
Plots
{
"inputs": {
"thingy": "ware:tar:qwerasdf"
},
"steps": {
"one": {"protoformula": {
"inputs": {
"/": "pipe::thingy"
},
"action": {
"exec": {"command": ["/bin/echo", "hi"]}
},
"outputs": {
"stuff": {"from": "/", "packtype": "tar"}
}
}},
"two": {"protoformula": {
"inputs": {
"/": "pipe::thingy"
"/prev": "pipe:one:stuff"
},
"action": {
"exec": {"command": ["/bin/echo", "hi"]}
},
"outputs": {
"stuff": {"from": "/", "packtype": "tar"}
}
}}
},
"outputs": {
"foo": "pipe:one:stuff"
"bar": "pipe:two:stuff"
}
}
# WFAPI:L2
... provide graphs and pipes:
Plots: you run them
# WFAPI:L2
Plots: you run them
# WFAPI:L2
shown above: output of first step used as input to second step -- see the same hash?
Plots
{
"inputs": {
"localname": "ware:tar:9fttDVHncJnoU9gLHdRybpz9eSw12xau9AsJzZTNoQamxFNjX6s6HNTj7a8wmYjCvg"
},
# WFAPI:L2
... can import from catalog refs:
Our first plot example still used wareIDs:
But you can also use human readable names!
This uses the "catalog" system (more on that shortly):
{
"inputs": {
"localname": "catalog:warpsys.org/glibc:v2.35:ld-amd64"
},
Plots
{
"inputs": {
"localname": "ware:tar:9fttDVHncJnoU9gLHdRybpz9eSw12xau9AsJzZTNoQamxFNjX6s6HNTj7a8wmYjCvg",
"othername": "catalog:warpsys.org/glibc:v2.35:ld-amd64"
},
# WFAPI:L2
... can use ingests (!!):
Now we've seen wareIDs and catalog lookups...
Plots can also ingest data from the host context:
{
"inputs": {
"veryhandy": "ingest:git:.:HEAD"
},
This will get converted to WareID, just like everything else.
...it's time to handle the communication parts!
harken back to our goals slide:
formulas
}
}
}
catalogs
plots
}
replays
Catalogs
# WFAPI:L2
for communicating releases!
a plot's best friend
Catalogs
# WFAPI:L2
Catalogs do all this.
Catalogs
# WFAPI:L2
{
"name": "warpsys.org/python",
"releases": {
"v3.10.2": "bafyrgqg6ckjrdt4d4duvdyzz2yz2gdsupo4isplfyy36yd6zfinucp2o7ixcwpbhlzlndrvaa2i6kzavliqpb3v7fmbkrazbcfwvmjx3e4awk"
},
"metadata": {}
}
Catalogs
# WFAPI:L2
{
"name": "v3.10.2",
"items": {
"src": "tar:3JnLd5GX5S4ndghJvKAxghhLiheCap7X4dkEDW9FTH17cM1GuDAJRWpEgmPKCQqHbZ",
"amd64": "tar:6iZRkZrFzkTzV7VxkH6bjNrEcjv7scL9Co24Z1eHg8mSvVWBhJyFUs5DJVrJuWGTkg"
},
"metadata": {
"replay": "bafyrgqfn5pn46zswpq57qseoon7xwwa3shhbtbszdccnxgkox7tfyelb5opwtpvwymzvajkojcwf2ibfciniiqgtmk4gthbfztbn5uibl7s44"
}
}
(we'll come back to replays in a moment)
Catalogs
# WFAPI:L2
{
"byWare": {
"tar:3JnLd5GX5S4ndghJvKAxghhLiheCap7X4dkEDW9FTH17cM1GuDAJRWpEgmPKCQqHbZ": [
"https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tar.xz"
]
}
}
boring, but practical.
Plots Using Catalogs
# WFAPI:L2
So remember seeing catalog references in plots?
Now you can see how those are looked up.
{
"inputs": {
"localname": "catalog:warpsys.org/glibc:v2.35:ld-amd64"
},
Each part of the "catalog:name:version:label" string turns into one step of lookup in this structure.
Catalogs on the filesystem
# WFAPI:L2
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/releases
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/releases/v2.38.json
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/replays
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/replays/v2.38.json
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/module.json
./.warpforge/catalogs/warpsys/warpsys.org/python
./.warpforge/catalogs/warpsys/warpsys.org/python/module.json
./.warpforge/catalogs/warpsys/warpsys.org/python/replays
./.warpforge/catalogs/warpsys/warpsys.org/python/replays/v3.10.2.json
./.warpforge/catalogs/warpsys/warpsys.org/python/mirrors.json
./.warpforge/catalogs/warpsys/warpsys.org/python/releases
./.warpforge/catalogs/warpsys/warpsys.org/python/releases/v3.10.2.json
Straightforward.
Easy to put in, say, a git repo.
(Also has its own canonical merklehash.)
Catalogs from existing data
# WFAPI:L2
Getting existing stuff into the warpforge universe is important -- and easy.
Gadgets like `warpforge catalog ingest-git-tags` help:
Recap so far...
# WFAPI:L2
Replays
# WFAPI:L2
when you want to explain what you did
or do it again
and again
and again
and again
Replays
# WFAPI:L2
Replays (stuffed in a Catalog) do this.
Replays: we already had them
# WFAPI:L2
This is kinda cheating: we already had this.
Our original build instructions -- the plot format -- are the replay instructions.
Replays: we already had them
# WFAPI:L2
This is kinda cheating: we already had this.
Sorta.
Replays: we already had them
# WFAPI:L2
{
"inputs": {
"rootfs": "catalog:warpsys.org/debian-bootstrap:bullseye-1646092800:amd64",
"src": "ingest:git:.:HEAD",
"glibc": "catalog:warpsys.org/glibc:v2.35:amd64",
"ld": "catalog:warpsys.org/glibc:v2.35:ld-amd64",
"ldshim": "catalog:warpsys.org/ldshim:v1.0:amd64"
},
"steps": {
// ...
},
"outputs": {
"src": "pipe::src"
"amd64": "pipe:build:out"
}
}
{
"inputs": {
"rootfs": "catalog:warpsys.org/debian-bootstrap:bullseye-1646092800:amd64",
"src": "catalog:example.org/this:v3.10.4:src",
"glibc": "catalog:warpsys.org/glibc:v2.35:amd64",
"ld": "catalog:warpsys.org/glibc:v2.35:ld-amd64",
"ldshim": "catalog:warpsys.org/ldshim:v1.0:amd64"
},
"steps": {
// ...
},
"outputs": {
"src": "pipe::src"
"amd64": "pipe:build:out"
}
}
⇨
Can even handle ingests by rewriting them to a self-reference.
Replays on the filesystem
# WFAPI:L2
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/releases
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/releases/v2.38.json
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/replays
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/replays/v2.38.json
./.warpforge/catalogs/warpsys/warpsys.org/gnu/binutils/module.json
./.warpforge/catalogs/warpsys/warpsys.org/python
./.warpforge/catalogs/warpsys/warpsys.org/python/module.json
./.warpforge/catalogs/warpsys/warpsys.org/python/replays
./.warpforge/catalogs/warpsys/warpsys.org/python/replays/v3.10.2.json
./.warpforge/catalogs/warpsys/warpsys.org/python/mirrors.json
./.warpforge/catalogs/warpsys/warpsys.org/python/releases
./.warpforge/catalogs/warpsys/warpsys.org/python/releases/v3.10.2.json
You already saw where replays go, in catalogs:
The hash of the replay is also in the release metadata.
Replays: multiroutes fine
# WFAPI:L2
Notice that replays contain the whole plot...including its inputs, including if they're catalog references.
Impact?
We can do "recursive explain" of how something (and its dependencies, and granddeps, etc) are built...
... and it's defined, even if there's more than one way to produce the same content.
Replays
# WFAPI:L2
...mean you can ask for recursive build
If you `wf run`, and the required inputs aren't local, and can't be fetched...
If there's a replay? No problem, we can just
`wf run -r`
It'll rebuild the required inputs from the replay instructions.
Workspaces
# WFAPI:WORKSPACES
The scope in which stuff happens!
Workspaces
# WFAPI:WORKSPACES
sharing is important
being able to have separation, even locally,
is important too
The scope in which stuff happens!
Workspaces
# WFAPI:WORKSPACES
Workspaces
# WFAPI:WORKSPACES
Workspaces (shown by `status`)
# WFAPI:WORKSPACES
$ wf status
Module "warpsys.org/python":
Plot has 5 inputs, 2 steps, and 1 outputs.
Plot contains 5 catalog inputs.
5/5 catalog inputs resolved successfully.
Workspace:
/projects/warpsys/python (pwd, module)
/projects/warpsys (root workspace, git repo)
# WFAPI:WORKSPACES
Workspaces vs Source Control
# WFAPI:L3+
going further:
yes, you probably want to do LOTS of builds
yes, you'll probably want to hammer the keyboard less --
so, you want templating systems,
and ways to compose content logically
so...
Yes, you probably want another layer, yet.
Something that generates these graphs.
# WFAPI:L3+
going further:
yes, you probably want to do LOTS of builds
yes, you'll probably want to hammer the keyboard less --
so, you want templating systems,
and ways to compose content logically
so...
Yes, you probably want another layer, yet.
Bring your own.
These objects are easy to generate.
Templating
# WFAPI:L3+
it's time for templating
(there can be more than one right answer here)
((but we're going to provide at least one))
Larks
# WFAPI:L3+
Larks
# WFAPI:L3+
Integrated starlark features are a work-in-progress.
create_plot("warpsys.org/example/thingy", wfapi.Plot(_={
inputs: #...
outputs: #...
})
+ mylib.partial_plot(...)
+ mylib.other_stuff(...)
)
def reusable_stuff(patchme)
return patchme.action.script.append("/some/hook --do-stuff")
# much to evolve here
Might look a bit like this?
(Check back soon.)
Formula
RunRecord
Plot
Catalog, Release
Replay
(your templating here)
Starlark
Whatever
# WFAPI
(api layers recap)
Formula
RunRecord
Plot
Catalog, Release
Replay
(your templating here)
Starlark
Whatever
# WFAPI
(api layers recap)
do stuff
...graphs of it
...however you want!
# WARPFORGE ROCKS
# WARPFORGE ROCKS
tl;dr: it's a mode for quick, cheap, interactive containers. For play!
# WARPFORGE ROCKS
tl;dr: this functionality comes "for free" once the whole plot and ingests system was done...
but gosh is it handy
{{no picture found}}
{{ask for demo later}}
# WARPFORGE ROCKS
Did I mention every time we're invoking containers, they're rootless containers?
You can run `warpforge` without ever invoking sudo.
# THE OFFER
A tool for building.
A style for packaging.
Next: time for some words on packaging...
# CHAPTER 3
Both. At the same time.
Yes, we are starting to package things...
# PACKAGING
We don't actually care much...
Except for one thing:
# PACKAGING
# Everything Sucks
not builders.
not users.
# Everything Sucks
not builders.
not users.
<-
let's fix this
# Everything Sucks
Removing the global variables of library paths...
Library paths are a global variable.
As a global variable, they're a source of contentions and collisions.
These contentions result in distros
-- inevitably, no matter how much they might value collaboration --
trending towards balkanization.
Fixes this.
It lets us collaborate again.
It restores balance to the force.
Also, practical confession...
We want the above style of input assembly to be easy.
"Put stuff in whatever path you want"
just makes sense.
{
"formula": {
"inputs": {
"/app/gawk": "ware:tar:1xvmNB2LgqL3HeT5pC57j2Ee9HEtDxRLE6uHAXr7EcXkjcoYiGHSBkFyKqQuHFyGPN"
"/app/gcc": "ware:tar:57j2EL3HeT5pCXr7EcXkjcoYiGHSBkFe9HEtDxRLE6uHA1xvmNB2LgqyKqQuHFyGPN"
"/app/python": "ware:tar:RLE657j2Ee9HEtDxuHA1xvmNXkjcoYiGHSBkFyB2LgqL3HeT5pCXr7EcKqQuHFyGPN"
},
"action": {
"script": {
"interpreter": "/bin/sh",
"contents": [
"export PATH=/app/*/bin/"
"awk # should work"
"gcc # should work"
"python # should work"
]
"path agnostic"
"path agnostic"
tar xf pagno-python.tgz
mv python /opt/python
/opt/python/bin/python # WORKS
mv python /media/my-jump-drive/
/media/my-jump-drive/bin/python # WORKS
mount /ipfs/
/ipfs/QmREL6gfCuZrTyUftfxPyfwPjyGANrZRBSXJGjhRXFHoFQ/bin/python # WORKS
Literally...
"path agnostic"
tar xf pagno-python.tgz
mv python /opt/python
/opt/python/bin/python # WORKS
mv python /media/my-jump-drive/
/media/my-jump-drive/bin/python # WORKS
mount /ipfs/
/ipfs/QmREL6gfCuZrTyUftfxPyfwPjyGANrZRBSXJGjhRXFHoFQ/bin/python # WORKS
Deeply convenient for users.
Also: helps an awful lot if you want to
use path prefixes with content hashes.
(^ Flat out Impossible otherwise!)
"path agnostic"
Why is this hard?
Long story short: dynamic linking...
and how ELF headers work in linux.
Briefly:
More info: http://warpforge.io -> then nav to the ecosystem conventions pages about linking!
More info: https://github.com/ericevenchick/ldshim
Static linking has limitations.
This this pagno technique, based on "rpath $ORIGIN", is easier to deploy -- works in more scenarios, with less patching.
You can also find out more about this in a talk entirely about Path Agnostic Binaries at ASG2018 !
(Yes, I've been harping about this for a while)
How do we get a useful $PATH, when each application is mounted its own dir tree?
`linkwarp` tool.
It produces a symlink farm.
Foreach executable in `*/bin/*`:
make a symlink to it in `../megabin/`;
add `megabin` to your $PATH.
Done.
# PACKAGING
That's it.
That's all the opinions we really have.
Packaging should be simple.
# Formulas
Overall:
Pounding in the tentpoles.
Trying to create a rendevous space --
where more people can gather to build a bigger system.
We have usable tools --
but that's only the start.
# Future Work
1. Starlark! Tighter integration; packages of reusable templating conventions?
2. Better tools for catalog sharing.
3. More packages! More, more more.
4. Autobumpers for dependency versioning.
5. ???
# Future Work
Yes, this slowly trends towards building a new distro.
We're currently resisting that.
Ideally, warpforge becomes the seed for a new genre of un-distro:
(barely.)
# Future Work
Your packages are welcome!
Your transport plugins are welcome!
Your execution sandbox plugins are welcome!
Your PRs with better helptext are welcome!
It will take a village to build this!
# PACE LAYERING
Cultural shift!~
Reproducible builds won't become prevalent until they're
Warpforge is meant to produce those conditions.
# PACE LAYERING
Cultural shift to reproducible builds, as a baseline expectation, everywhere.
Computers become easier to use,
because they're built out of more composable systems.
Everyone can use the same tools -- small projects, distros, companies -- so we can get more done, together.
# WHERETO
https://matrix.to/#/#warpforge:matrix.org
or #warpforge on libera.chat !
overflow slides
and
probable Q&A topics
# PACE LAYERING
I pulled in a repo that a collaborator pushed gcc build plots into...
... I launched `warpforge run`...
and I went to the bar.
When I came back, I had a working gcc... And because i had done `wf run -r` on some examples, those were built too!
# PACE LAYERING
Build graph with a cycle in it.
(N.b. warpforge can represent this! Most can't!)
Now join two cycles. Then more.
High power solution to Trusting Trust:
what kind of adversary can get a viral quine farther back in history... than you can stitch together Ouroborous Mesh?
# Langpkgs?
Hypothesis: language package managers aren't reused because:
We might be able to shift the ROI curves. Worth a shot?
# Langpkgs?
LPMs do approx 4 things:
Notice how warpforge has set its boundaries very carefully: it only does the last two -- where being opinionated/special has low/no value.
# Formulas
When you're doing science, you write a Standard Operating Procedure ("SOP") first; then you execute it.
Warpforge is like that! You write a formula first; then, you execute it.
When you're doing science, you write a Standard Operating Procedure ("SOP") first; then you execute it.
Repeatedly.
# Q&A: dynamic graph?
Not really.
You can do it at the L3/"templating" layers, though.
(The focus on having outlines of computations before starting to operate is necessary for having a feasible replay system (and thence the explain and audit features around it) -- so this is not a design choice made lightly.)
(iiuc, this is roughly the same choice bazel makes)
“we want to set someone up to become a hero if they put some business process inside warpforge... and just hand tarballs off to their downstream consumers and colleagues.”
(That means not just emitting tarballs, but also having a strategy for making their contents...
you know, work.)
# Y U No X?
First of all: yes, it's close!
However:
# Y U No X?
way too many primitives.
.... and this didn't even get to the file fetching ones!
# Y U No X?
First of all: yes, it's got heart in the right place!
However:
Holistically: maybe a new project with slightly different choices will be able to reach better UX and more adoption faster.
# Y U No X?
Holistically: maybe a new project with slightly different choices will be able to reach better UX and more adoption faster.
# Y U No X?
Both have too many primitives...
...and an ingest instruction can appear almost anywhere.
Even someplace deep in a callstack.
(I think bazel can at least analyze this; I'm not sure Nix can.)
Contrast: Warpforge ingests are syntactically extremely obvious.
(And usually, you don't have them at all, because catalogs.)
crap slides
# Everything Sucks
All of these things
and i'm sorry, that doesn't really work for me
are trying to
(flatpack,snap,nix,guix,ubuntu,everyotherdistro,etc,etc,etc)
Formulas (and their limits)
# WFAPI:L1
A bit like like one “RUN” line in a dockerfile ...
We're only producing outputs at the end of this; it's all one execution cycle.
So: we'll want something to let us compose multiple steps. Up next: Plots!
# PACKAGING
1. Spiritually: lack of pagno dynamic linking conventions is a (foolish, avoidable) wedge which drives distros apart. We should not let it waste our time and obstruct our ability to share.
2. Practically: I really want my assembly config...
... to work, and be easy to get joy out of.
"/mount/here": "ware:tar:qwerutoeirt"
"/other/things": "ware:git:12345678abcd"
"/yet/more": "ware:tar:zbkweitguFHgjeek"
selfcontained packages:
sort of obvious, right?
MacOS has been like this for years
chromeOS is similar (i've heard)
things that work and get adoption are working and being adopted because they are moving this way.
selfcontained packages:
AppImage and friends do this too: bundle everything. It works!
they just do a more heavyweight intervention:
they use squashfs and mount it.
works. but dedup is impossible.