Flakes – Proposed mechanism to package Nix expressions into composable entities
github.com
github.com
Flakes would allow package definitions from different sources play well with each other. This means a bunch of things:
1) Nixpkgs could be broken up into several package sets for better scalability. Eg, haskelPackages and pythonPackages could be broken out into separate repositories.
2) Package authors could provide package definitions along with the source.
3) Companies could have a flake for internal packages without having to patch or overlay nixpkgs.
4) Alternatives to nixpkgs can get started without having to supply all the packages that a user might need.
5) You could even create libraries of nix functions that supply no packages at all, but get used by other flakes to define packages. For example, the machinery for composing a python environment.
While this could happen, it's exactly what I hope won't happen, because in my opinion the idea that haskell or python packages are fundamentally different and can live in their own world is a fallacy. I spend quite a bit of my time fixing python packages on nixpkgs master and the number of times the fix actually involves making a tweak to a non-python library means I would forever have to be playing games synchronizing repositories. Also, gone would be the ability to make atomic changes across these boundaries.
Viva la monorepo.
Absolutely. Look at edolstra take on this though https://github.com/NixOS/rfcs/pull/49#discussion_r305450668
This is why I'm scared of this change.
If pythonPackages were broken out into a separate repository (which I'm not advocating, it was just an example), you'd fix a python package by importing the upstream library from the nixpkgs flake, tweaking it locally and then using the local version as buildInput to the python package. Sometimes it would make sense to submit the fix upstream, and sometimes not.
At the same time, we really have run into scaling issues—automatically importing all of Stackage into nixpkgs was killing us for a while there.
Regardless of whether nixpkgs remains a monorepo or not, I think 2) is actually the most exciting thing about the flakes proposal. Package authors being unable to supply nix packaging within the package repository is a big impediment to the adoption of nix.
If you follow the rabbit-hole: `default.nix` -> `lib.nix`, etc, you can see that I pin nixpkgs, have an update script that updates the nixpkgs revs I build against, it supports building against a custom, local `~/code/nixpkgs` if it exists, and I have my machine config abstracted out to where I can build a "GNOME instance of my machine" or by default, my machine with Sway and sway related packages installed. Much of this should be easier with flakes, as I understand it.
It's not the cleanest config, the README needs love, but maybe it can be inspiration in the meantime. :) My latest trick was figuring out how to get the new Mesa Intel Iris Gallium driver enabled without rebuilding the world, and I extracted it to what I call a "mixin" that anyone can copy and just use: https://github.com/colemickens/nixcfg/blob/master/modules/mi...
(And technically I still use mozilla/nixpkgs-mozilla to pull the latest Firefox Nightly which is impure and thus not always perfectly, perfectly reproducable. I do however pin the overlays themselves also - like my nixpkgs-wayland overlay that packages HEAD versions of Sway and other Wayland related tools!)
I periodically update the version of nixpkgs it uses, but since it's pinned, I get exactly the same outputs when building.
let
nixpkgs = builtins.fetchTarball {
name = "nixpkgs-upstream";
url = https://github.com/NixOS/nixpkgs/archive/a835adc10cb813d214a9069361d94a2a3f8eb3a5.tar.gz;
sha256 = "0h4lacvqmk356ihc7gnb44dni6m5qza23vlgl6w6jdhr9pjcmdcm";
};
overlay = self: super: {
# customizations
};
in import nixpkgs { overlays = [ overlay ]; }
This isn't even simplified. I just cut out the contents of the overlay. For more on how overlays work take a look at these references; they were really helpful to get me started.https://nixos.org/nixpkgs/manual/#chap-overlays
https://blog.flyingcircus.io/2017/11/07/nixos-the-dos-and-do...
That said, it’s hard enough to even run an old model 2 years later let alone reproduce to significant digits. I’d be happy enough to solve the former and get “close enough” training results
Of course, it is better than languages with lots of brackets, but still not good enough.
[1] https://github.com/edolstra/nixpkgs/blob/release-19.03/flake...
First of all, "attractive" is simply your way to say "familiar to me".
Then, a language need to be just powerful enough to express it's semantic and no more.
This critique is quite hollow and noisy.
Nixpkgs itself does a lot of funky things, especially around overrides and whatnot, but those are features of Nixpkgs, not of Nix the language.
Haha yes, I mean clearly this means it's Nix's fault. Has anyone ever considered using you as some kind of "overengineering divining rod" where they can just wave something in front of your nose and go back to the drawing board if it doesn't pass?
Well you might be right, but I find Nix and NixOS to be great. Honestly the language isn’t the issue, it’s just that it isn’t nearly as well supported as more popular distros like Ubuntu, so for example my VMWare Workstation license has been sitting dormant for a while now... (Which is mostly OK. I’ve been using libvirt for everything and pleasantly surprised at what it can do.)
The language takes some getting used to, and I am not really 100% sold on pure functional, but it works and my systems are much more reliable now.
(Yes, I know, JSON is not a language, but people do sometimes use it for things approximately as long and as complicated as a Nix expression.)
But why isn't there an ML with the good parts of YAML, but without the bad parts?
AFAIK, one can not subset YAML and get something coherent. But one can start from scratch and use its concepts. I imagine the languages are not there just because nobody got the time to do them.
{ pkgs ? import <nixpkgs> {}}:
with pkgs;
python3Packages.buildPythonApplication rec {
name = "quicktill";
src = ./.;
doCheck = false;
propagatedBuildInputs = with python3Packages; [
dateutil pyyaml
sqlalchemy psycopg2
pycups reportlab
requests_oauthlib
pygobject3
];
nativeBuildInputs = [ wrapGAppsHook ];
buildInputs = [ gobjectIntrospection gtk3 ];
}
The only big things here are the fact that this is defined as a function that takes the package repository as an argument to access dependencies (the first line), and the "with" expressions that allow me to skip having to type "pkgs." and "pkgs.python3Packages." for every package I depend on. rec {
name = "quicktill";
src = ./.;
doCheck = false;
propagatedBuildInputs = with python3Packages; [
dateutil pyyaml
sqlalchemy psycopg2
pycups reportlab
requests_oauthlib
pygobject3
];
nativeBuildInputs = [ wrapGAppsHook ];
buildInputs = [ gobjectIntrospection gtk3 ];
}
Is that any better? It looks an awful lot like some dialect of something JSON-like to me - there's some different symbols used and array values are separated with spaces rather than commas, but aside from that it's just a record of key-value pairs.From there, the first line in the original example says "the following expression is a function that is called with this parameter", and the parameter is an object containing a key called "pkgs", which is defaulted to the result of "import <nixpkgs> {}". This is explained in more detail in a handful of lines in the language manual.
Functions are called just by referencing the function and then the arguments separated with spaces, like Ruby or Haskell - so python3Packages.buildPythonApplication is a function that is called with the object above.
Finally, "with foo;" just means "every key in foo can be accessed without typing foo. in the next expression".
The result is basically: this file defines a function which takes an object containing the package repository as the "pkgs" key, and returns the result of calling pkgs.python3Packages.buildPythonApplication with the object defined in the rest of the file.
It's a lot more derived from the syntax of functional languages than C-like ones, but that's not necessarily a bad thing. Also: this is basically the entire language. There's a couple of different string syntaxes and some stuff for merging objects together, and also a mechanism for temporarily naming things that aren't part of an object, but in general... there's not a lot more to it. Most of the complexity is in the domain itself - what's the difference between a propagated, native and regular build input, how do you manage plugins and options for a package, etc.
What's your preferred packaging DSL?
But your example looks nothing like Json.
Nix is great in concept but the language or idioms make it really difficult to use.
Regarding syntax, I would prefer something like this:
DEPENDS_ON python 3.5.1, python/dateutil 1.2.3, ...
BUILD_TOOL bash 1.2.3
BUILD_SCRIPT ./build.sh
In practice, the default set is expected to be somewhat internally consistent, so that you can just use the package names to refer to the "most recent consistent set". But if need arises, you can also override individual packages to pin them at a different version than the upstream-provided one.
To me it seems like a really complicated technical solution to a social problem(the monorepo approach doesn't scale).
If more people are needed to maintain the nixpkgs repo why instead not focus on ways to increase the community size.
Missing docs have been a problem for NixOS for a long time, most awesome features are lost on some proficient users tweets. Having better docs would do wonders for the community.
I think if NixOS wants to copy some of Rust strengths, quality docs should be its first priority.
Citation needed.
I view corporate interest as a good sign for the continued health of the ecosystem. As long as they don't "take over" the project there's no harm. And in particular, publishing an RFC like this shows that they're doing things the right way and cooperating with the community.