Cheddar now needs to be passed the --about-filter flag to toggle the
behaviour for rendering Markdown into HTML.
By default Markdown will be highlighted like normal source code (i.e.
cgit source-filtering is the default behaviour).
This advice is potentially defined before the autoloads for telega
have run, which means that the macro-expansion fails and
`telega-ins-fmt` is looked up as a function.
With this setup the initialisation works as expected.
The lambda that acts as the sentinel for building SBCL with packages
needs to be able to capture variables if lexical binding is enabled,
which is made possible by the lexical-let form.
Adds a function that can launch Sly with a pre-configured SBCL for a
Lisp derivation in the depot.
This makes it convenient to spin up development environments for Lisp
libraries and programs by simply calling `M-x nix/sly-from-depot RET
tools.something`.
This relies on `nix-depot-path` being configured currently as I have
not yet reliably added the depot to my NIX_PATH on all machines.
Sets up Lisp modes in Sly REPL and points at the local hyperspec
checkout.
In fact the Hyperspec bit should probably be managed by Nix, but one
step at a time.
Implements support for tagging paragraphs that begin with a callout
word (TODO, WARNING, QUESTION, TIP) with an additional `cheddar-*`
class that makes it possible to render these callouts specially.
This is currently not the nicest implementation, but it works.
Since I am going down the path of adding additional Markdown
extensions it makes sense to avoid letting `format_markdown` turn into
a giant beast of a function.
Therefore this commit extracts the logic for rendering code blocks via
syntect and changes the innards of `format_markdown` to instead
provide arbitrary AST value replacements.
Instead of splitting below and moving the target buffer into the new
split, split and move the buffer into the active window.
The other way around does (for some reason I don't fully understand)
not work because `split-window-below` may return invalid windows.
Configures edwina using `s-w` as the key prefix (in line with my other
EXWM-related commands).
An additional function is added that switches to a buffer (borrowing
the implementation from `ivy-switch-buffer`) but splitting it into a
new window instead.
Implements fully static (i.e. no JavaScript!) highlighting of code
blocks when rendering Markdown.
This works by walking through the Comrak AST and replacing any code
blocks with pre-rendered HTML blocks.
Syntaxes are chosen based on the "block info", which is the string
users put after the block's opening fence. This can either be
a (case-insensitive) name of a syntax, or alternatively a file
extension associated with the desired syntax.
The theme is set to one that imitates GitHub.
Renders any ".md" file by pushing it through the Comrak rendering
pipeline.
This does not yet implement syntax highlighting of fenced blocks, but
we're getting there.
Generalises the two bits of the program that will be required either
way (extension parsing and syntax loading).
A dependency on Comrak is introduced as I think GitHub-flavoured
Markdown (with all its fancy extensions) is desirable!
This uses Nix to inject the path to the syntax highlighting assets
that ship with the bat source code into the cheddar build at compile
time, where the Rust compiler then inserts it into the binary via
macros.
bat has a lot of custom syntax highlighting definitions that they
collected from all over the place (including for languages like Nix!)
and this makes them accessible to cheddar.
Also if you're reading this, can you just take a moment to appreciate
how incredible it is that Nix just lets us do something like this?!
The first step with this tool will be to use it as a source-filter for
cgit. The second step is to use it as the Markdown renderer by
depending on one of the Markdown libraries, with integration for
rendering code snippets directly.
This moves the various projects from "type-based" folders (such as
"services" or "tools") into more appropriate semantic folders (such as
"nix", "ops" or "web").
Deprecated projects (nixcon-demo & gotest) which only existed for
testing/demonstration purposes have been removed.
(Note: *all* builds are broken with this commit)
Packages the telega-server binary and adds the required mode into
Emacs.
Unread message count is displayed in the modeline, which is neat.
Probably need to figure out some key bindings for this.
Adds an Emacs library with so far a grand total of one helper function
that can prefetch and insert a git repository at point.
This is very useful for the various Go repo imports I am doing at the
moment.
This makes it possible to quickly adjust the size of text in all
frames using one keyboard shortcut. Each of these functions
understands a prefix argument to mean "please only operate on the
current buffer", hence the following bindings and effects:
Global:
* `C-=`: Increase the global font size (chosen because `+` lies on the
`=` key)
* `C--`: Decrease the global font size
* `C-x C-0`: Restore the global default font size
Local:
* `C-u C-=`: Increase the local font size
* `C-u C--`: Decrease the local font size
* `C-u C-x C-0`: Restore the local default font size
This function makes it possible to build an Emacs instance that,
instead of launching an Emacs built by Nix, configures an Emacs
already present on the system to use the packages built by Nix.
This **requires** that the versions of the two Emacsen (i.e. the one
used by Nix to build and the one used to run the packages) are kept in
sync, otherwise byte-code incompatibilities may lead to undefined
behaviour.
Exposes an `overrideEmacs` which can take a package function that
receives the current package list and can make arbitrary modifications
to it.
This makes it possible for me to maintain a private overlay for e.g.
work purposes with packages that should not be visible in my public
repos.
This was set to my old home directory name from a different machine
and I had low-key been wondering why it didn't work, but not enough to
go do something about it.
This incredible package provides a fully functional, libvterm based
terminal emulator inside of Emacs.
Killer feature: It's possible to switch the buffer into a full Emacs
text mode (read-only) for selections and such.
Adds a "do what I mean" multiple-cursor selection with the logic that
I find most useful:
* If there is no active region, mark the next line (or lines, based on
prefix argument)
* If there is an active region that spans multiple lines, call
`mc/edit-lines`
* If there is an active region on a single line, trigger a custom
selection hydra with functionality equivalent to
`mc/mark-more-like-this-extended` but a slightly improved user
experience
Hopefully this will make it easier to get into the habit of actually
using multiple-cursors without calling the mc commands via M-x
This enables usage of __dispatch.sh from anywhere, even outside of the
depot.
Specifically this means I can add `~/depot/bin` to my $PATH and all
the registered tools work from anywhere.
Configures Emacs' `customize` to write directly to my Emacs
configuration. This comes with the caveat that the new config will
only be loaded if my Emacs is rebuilt.
Builds an Emacs that is not only configured with the required packages
but with the entire Emacs configuration for my personal setup.
This means that `nix-env -iA tools.emacs` will install a
fully-configured Emacs that can be launched as the window manager from
my ~/.xsession.
This is not the final layout yet, but makes it so that my top-level
attribute set is no longer overlaid into nixpkgs itself.
This is useful for other people who are importing my monorepo.
This gets rid of the package called "server" and instead moves
everything into the project root, such that Go actually builds us a
binary called `nixery`.
This is the first step towards factoring out CLI-based functionality
for Nixery.
The previous logic failed because single meta-packages such as
"nixery.dev/shell" would not end up removing the meta-package itself
from the list of packages passed to Nix, causing a build failure.
This was a regression introduced in 827468a.
This is a tiny program that does nothing but exists to demonstrate
pkgs.buildGo by building a program that depends on a local library as
well as a protobuf definition.
Broadly speaking, the following things are included:
* there is now a uniform `args` struct that is passed to all
derivations, package headers have been changed appropriately
* overrides are now loaded from a separate `override` folder just
using read-tree.nix
* third-party packages have moved into the `third_party` attribute set
Nixery itself is built with the buildLayeredImage system, which takes
some time to create large numbers of layers.
This adjusts the default number of image layers from 96 to 20.
Additionally Nixery's image is often loaded with `docker load -i`,
which ignores layer cache hits anyways.
Additionaly the CI build is configured to use only 1, which speeds up
CI runs.
Imports the package set twice in the builder expression: Once
configured for the target system, once configured for the native
system.
This makes it possible to fetch the actual image contents for the
required architecture, but use local tools to assemble the symlink
layer and metadata.
Specifying this meta-package toggles support for ARM64 images, for
example:
# Pull a default x86_64 image
docker pull nixery.dev/hello
# Pull an ARM64 image
docker pull nixery.dev/arm64/hello
Adds an implementation of popcount that, instead of realising
derivations locally, just queries the cache's narinfo files.
The downside of this is that calculating popularity for arbitrary Nix
package sets is not possible with this implementation. The upside is
that calculating the popularity for an entire Nix channel can now be
done in ~10 seconds[0].
This fixes#65.
[0]: Assuming a /fast/ internet connection.
This case should not be possible unless something manually constructs
a logrus entry with a non-error value in the log.ErrorKey field, but
it's better to be safe than sorry.
Previously background contexts where created where necessary (e.g. in
GCS interactions). Should I begin to use request timeouts or other
context-dependent things in the future, it's useful to have the actual
HTTP request context around.
This threads the request context through the application to all places
that need it.
The point at which files are moved happens to also (initially) be the
point where the `layers` directory is created. For this reason
renaming must ensure that all path components exist, which this commit
takes care of.
The filesystem storage backend can be enabled by setting
`NIXERY_STORAGE_BACKEND` to `filesystem` and `STORAGE_PATH` to a disk
location from which Nixery can serve files.
This abstracts over the functionality of Google Cloud Storage and
other potential underlying storage backends to make it possible to
replace these in Nixery.
The GCS backend is not yet reimplemented.
The JSON file generated for service account keys already contains the
required information for signing URLs in GCS, thus the environment
variables for toggling signing behaviour have been removed.
Signing is now enabled automatically in the presence of service
account credentials (i.e. `GOOGLE_APPLICATION_CREDENTIALS`).
Some Nix download mechanisms will add a second hash in the store path,
which had been added to the source hash output (breaking argument
interpolation).
Instead of compressing & decompressing again to get the underlying tar
hash, use a similar mechanism as for store path layers for the symlink
layer and only compress it once while uploading.
Docker expects hashes of compressed tarballs in the manifest (as these
are used to fetch from the content-addressable layer store), but for
some reason it expects hashes in the configuration layer to be of
uncompressed tarballs.
To achieve this an additional SHA256 hash is calculcated while
creating the layer tarballs, but before passing them to the gzip
writer.
In the current constellation the symlink layer is first compressed and
then decompressed again to calculate its hash. This can be refactored
in a future change.
This has become an issue recently with changes such as GZIP
compression, where CI runs no longer work because they conflict with
the production bucket for the public instance.
Makes use of the `.WithError` and `.WithField` convenience functions
in logrus to simplify log statement construction.
This has the added benefit of making it easier to correctly log
errors.
This rewrites all existing log statements into the structured logrus
format. For consistency, all errors are always logged separately from
the primary message in a field called `error`.
Only the "info", "error" and "warn" severities are used.
Uses a hash of Nixery's sources as the version displayed when Nixery
launches or logs an error. This makes it possible to distinguish
between errors logged from different versions.
The source hashes should be reproducible between different checkouts
of the same source tree.
This formatter has basic support for the Stackdriver Error Reporting
format, but several things are still lacking:
* the service version (preferably git commit?) needs to be included in
the server somehow
* log streams should be split between stdout/stderr as that is how
AppEngine (and several other GCP services?) seemingly differentiate
between info/error logs
These two packages almost always end up being required by programs,
but people don't necessarily consider them.
They will now always be added and their popularity is artificially
inflated to ensure they end up at the top of the layer list.
Image layers in manifests are now sorted in a stable (descending)
order based on their merge rating, meaning that layers more likely to
be shared between images come first.
The reason for this change is Docker's handling of image layers on
overlayfs2: Images are condensed into a single representation on disk
after downloading.
Due to this Docker will constantly redownload all layers that are
applied in a different order in different images (layer order matters
in imperatively created images), based on something it calls the
'ChainID'.
Sorting the layers this way raises the likelihood of a long chain of
matching layers at the beginning of an image.
This relates to #39.
Implements a local manifest cache that uses the temporary directory to
cache manifest builds.
This is necessary due to the size of manifests: Keeping them entirely
in-memory would quickly balloon the memory usage of Nixery, unless
some mechanism for cache eviction is implemented.
The functions used for layer creation are now easier to follow and
have clear points at which the layer cache is checked and populated.
This relates to #50.
MD5 hash checking is no longer performed by Nixery (it does not seem
to be necessary), hence the layer cache now only keeps the SHA256 hash
and size in the form of the manifest entry.
This makes it possible to restructure the builder code to perform
cache-fetching and cache-populating for layers in the same place.
The new builder now caches and reads cached manifests to/from GCS. The
in-memory cache is disabled, as manifests are no longer written to
local file and the caching of file paths does not work (unless we
reintroduce reading/writing from temp files as part of the local
cache).
This cache is no longer required as it is implicit because the layer
cache (mapping store path hashes to layer hashes) implies that a layer
has been seen.
Implements the new build process to the point where it can actually
construct and serve image manifests.
It is worth noting that this build process works even if the Nix
sandbox is enabled!
It is also worth nothing that none of the caching functionality that
the new build process enables (such as per-layer build caching) is
actually in use yet, hence running Nixery at this commit is prone to
doing more work than previously.
This relates to #50.
The new manifest package creates image manifests and their
configuration. This previously happened in Nix, but is now part of the
server's workload.
This relates to #50.
The new build process can now call out to Nix to create layers and
upload them to the bucket if necessary.
The layer cache is populated, but not yet used.
The state type contains things such as the bucket handle and Nixery's
configuration which need to be passed around in the builder.
This is only added for convenience.
This cache is going to be used for looking up whether a layer build
has taken place already (based on a hash of the layer contents).
See the caching section in the updated documentation for details.
Relates to #50.
This introduces a new Nix derivation that, given an attribute set of
layer hashes mapped to store paths, will create a layer tarball for
each of the store paths.
This is going to be used by the builder to create layers that are not
present in the cache.
Relates to #50.
Refactors the layer grouping package (which previously compiled to a
separate binary) to expose the layer grouping logic via a function
instead.
This is the next step towards creating layers inside of the server
component instead of in Nix.
Relates to #50.
Simplifies the wrapper script used to invoke Nix builds from Nixery to
just contain the essentials, since the layer grouping logic is moving
into the server itself.
This is the first step towards a more granular build process where
some of the build responsibility moves into the server component.
Rather than assembling all layers inside of Nix, it will only create
the symlink forest and return information about the runtime paths
required by the image.
The server is then responsible for grouping these paths into layers,
and assembling the layers themselves.
Relates to #50.
Fixes two launch script compatibility issues with other container
runtimes (such as gvisor):
* don't fail if /tmp already exists
* don't fail if the environment becomes unset
Instead of dumping all Nix output as one at the end of the build
process, stream it live as the lines come in.
This is a lot more useful for debugging stuff like where manifest
retrievals get stuck.
Caches manifests under `manifests/$cacheKey` in the GCS bucket and
introduces two-tiered retrieval of manifests from the caches (local
first, bucket second).
There is some cleanup to be done in this code, but the initial version
works.
Use the PackageSource.CacheKey function introduced in the previous
commit to determine the key at which a manifest should be cached in
the local cache.
Due to this change, manifests for moving target sources are no longer
cached and the recency threshold logic has been removed.
Introduces three new types representing each of the possible package
sources and moves the logic for specifying the package source to the
server.
Concrete changes:
* Determining whether a specified git reference is a commit vs. a
branch/tag is now done in the server, and is done more precisely by
using a regular expression.
* Package sources now have a new `CacheKey` function which can be used
to retrieve a key under which a build manifest can be cached *if*
the package source is not a moving target (i.e. a full git commit
hash of either nixpkgs or a private repository).
This function is not yet used.
* Users *must* now specify a package source, Nixery no longer defaults
to anything and will fail to launch if no source is configured.
Adds a shell script that supports a subset of the 'pass' interface for
compatibility with kontemplate, and wraps kontemplate in a script that
places this version on the PATH.
This makes it possible to use Cloud KMS encrypted secrets with kontemplate.
Adds a NIX_TIMEOUT environment variable which can be set to a number
of seconds that is the maximum allowed time each Nix builder can run.
By default this is set to 60 seconds, which should be plenty for most
use-cases as Nixery is not expected to be performing builds of
uncached binaries in most production cases.
Currently the errors Nix throws on a build timeout are not separated
from other types of errors, meaning that users will see a generic 500
server error in case of a timeout.
This fixes#47
Moves the relevant parts of the customisation layer construction from
dockerTools.mkCustomisationLayer into the Nixery code base.
The version in dockerTools builds additional files (including via
hashing of potentially large files) which are not required when
serving an image over the registry protocol.
This package is used by a variety of programs that users may want to
embed into Nixery in addition, for example cachix, but those packages
don't refer to it explicitly.
This is required by git in cases where Nixery is configured with a
custom git repository.
I've also added a shell back into the image to make debugging a
running Nixery easier. It turns out some of the dependencies already
pull in bash anyways, so this is just surfacing it to $PATH.
Before this change, Nixery would pass on the image name unmodified to
Nix which would lead it to cache-bust the manifest and configuration
layers for images that are content-identical but have different
package ordering.
This fixes#38.
This test, after performing the usual Nixery build, loads the built
image into Docker, runs it, pulls an image from Nixery and runs that
image.
To make this work, there is some configuration on the Travis side.
Most importantly, the following environment variables have special
values:
* `GOOGLE_KEY`: This is set to a base64-encoded service account key to
be used in the test.
* `GCS_SIGNING_PEM`: This is set to a base64-encoded signing key (in
PEM) that is used for signing URLs.
Both of these are available to all branches in the Nixery repository.
Implements a cache that keeps track of:
a) Manifests that have already been built (for up to 6 hours)
b) Layers that have already been seen (and uploaded to GCS)
This significantly speeds up response times for images that are full
or partial matches with previous images served by an instance.
Some upcoming changes might require the Nix build to be split into
multiple separate nix-build invocations of different expressions, thus
splitting this out is useful.
It also fixes an issue where `build-image/default.nix` might be called
in an environment where no Nix channels are configured.
ALl the ones except for build-image.nix are considered trivial. On the
latter, nixfmt makes some useful changes but by-and-large it is not
ready for that code yet.
Removes usage of the old layering algorithm and replaces it with the
new one.
Apart from the new layer layout this means that each layer is now
built in a separate derivation, which hopefully leads to better
cacheability.
Instead of requiring the server component to be made aware of the
location of the Nix builder via environment variables, this commit
introduces a wrapper script for the builder that can simply exist on
the builders $PATH.
This is one step towards a slightly nicer out-of-the-box experience
when using `nix-build -A nixery-bin`.
This commit adds the actual logic for extracting layer groupings and
merging them until the layer budget is satisfied.
The implementation conforms to the design doc as of the time of this
commit.
This script generates an entry in a text file for each time a
derivation is referred to by another in nixpkgs.
For initial testing, this output can be turned into group-layers
compatible JSON with this *trivial* invocation:
cat output | awk '{ print "{\"" $2 "\":" $1 "}"}' | jq -s '. | add | with_entries(.key |= sub("/nix/store/[a-z0-9]+-";""))' > test-data.json
As described in the design document, this adds considerations for
closure size and popularity. All closures meeting a certain threshold
for either value will have an extra edge from the image root to
themselves inserted in the graph, which will cause them to be
considered for inclusion in a separate layer.
This is preliminary because popularity is considered as a boolean
toggle (the input I generated only contains the top ~200 most popular
packages), but it should be using either absolute popularity values or
percentiles (needs some experimentation).
This uses a significantly larger percentage of the total available
layers (125) than before, which means that cache hits for layers
become more likely between images.
This page describes the various steps that Nixery goes through when
"procuring" an image.
The intention is to give users some more visibility into what is going
on and to make it clear that this is not just an image storage
service.
Executes the previously added mdBook on the previously added book
source to yield a directory that can be served by Nixery on its index
page.
This is one of those 'I <3 Nix' things due to how easy it is to do.
Uses mdBook[1] to generate a documentation overview page instead of
the previous HTML site.
This makes it possible to add more elaborate documentation without
having to deal with finicky markup.
[1]: https://github.com/rust-lang-nursery/mdBook
As described in issue #14, the registry API does not allow image names
with uppercase-characters in them.
However, the Nix package set has several top-level keys with uppercase
characters in them which could previously not be retrieved using
Nixery.
This change implements a method for retrieving those keys, but it is
explicitly only working for the top-level package set as nested
sets (such as `haskellPackages`) often contain packages that differ in
case only.
Google Cloud Storage supports granting access to protected objects via
time-restricted URLs that are cryptographically signed.
This makes it possible to store private data in buckets and to
distribute it to eligible clients without having to make those clients
aware of GCS authentication methods.
Nixery now uses this feature to sign URLs for GCS buckets when
returning layer URLs to clients on image pulls. This means that a
private Nixery instance can run a bucket with restricted access just
fine.
Under the hood Nixery uses a key provided via environment
variables to sign the URL with a 5 minute expiration time.
This can be set up by adding the following two environment variables:
* GCS_SIGNING_KEY: Path to the PEM file containing the signing key.
* GCS_SIGNING_ACCOUNT: Account ("e-mail" address) to use for signing.
If the variables are not set, the previous behaviour is not modified.
Previously the acknowledgement calls from Docker were receiving a
404 (which apparently doesn't bother it?!). This corrects the URL,
which meant that acknowledgement had to move inside of the
registryHandler.
Shiny, new domain is much better and eliminates the TLS redirect issue
because there is a HSTS preload for the entire .dev TLD (which, by the
way, is awesome!)
This might not yet be the final version, but it's going in the right
direction.
Additionally the favicon has been reduced to just the coloured Nix
logo, because details are pretty much invisible at that size anyways.
People should not start depending on the demo instance. There have
been discussions around making a NixOS-official instance, but the
project needs to mature a little bit first.
The MD5 sum is used for verifying contents in the layer cache before
accidentally re-uploading, but the syntax of the hash invocation was
incorrect leading to a cache-bust on the manifest layer on every
single build (even for identical images).
Uses the structured errors feature introduced in the Nix code to
return more sensible errors to clients. For now this is quite limited,
but already a lot better than before:
* packages that could not be found result in 404s
* all other errors result in 500s
This way the registry clients will not attempt to interpret the
returned garbage data/empty response as something useful.
Changes the return format of Nixery's build procedure to return a JSON
structure that can indicate which errors have occured.
The server can use this information to send appropriate status codes
back to clients.
Adds environment variables with which users can configure the package
set source to use. Not setting a source lets Nix default to a recent
NixOS channel (currently nixos-19.03).
This extends the package set import mechanism in
build-registry-image.nix with several different options:
1. Importing a nixpkgs channel from Github (the default, pinned to
nixos-19.03)
2. Importing a custom Nix git repository. This uses builtins.fetchGit
and can thus rely on git/SSH configuration in the environment (such
as keys)
3. Importing a local filesystem path
As long as the repository pointed at is either a checkout of nixpkgs,
or nixpkgs overlaid with custom packages this will work.
A special syntax has been defined for how these three options are
passed in, but users should not need to concern themselves with it as
it will be taken care of by the server component.
This relates to #3.
Adds git & SSH as part of the Nixery image, which are required to use
Nix's builtins.fetchGit.
The dependency on interactive tools is dropped, as it was only
required during development when debugging the image building process
itself.
Introduce an empty runtime configuration object in each built layer.
This is required because Kubernetes expects the configuration to be
present (even if it's just empty values).
Providing an empty configuration will make Docker's API return a full
configuration struct with default (i.e. empty) values rather than
`null`, which works for Kubernetes.
This fixes issue #1. See the issue for additional details.