Awesome
Composition C-4
This is a lightweight library that allows downloading Composer dependencies using Nix. It falls under lockfile-based tools in nmattia’s typology.
Warning: backwards compatibility is not guaranteed, pin this repo if you want to avoid breakage.
How to use?
- Pass the output of
c4.fetchComposerDeps
ascomposerDeps
to derivation. - Add
c4.composerSetupHook
as derivation’s dependency.
{
stdenv,
fetchFromGitHub,
php,
c4,
}:
stdenv.mkDerivation rec {
pname = "grav";
version = "1.7.15";
src = fetchFromGitHub {
owner = "getgrav";
repo = "grav";
rev = version;
sha256 = "4PUs+6RFQwNmCeEkyZnW6HAgiRtP22RtkhiYetsrk7Q=";
};
composerDeps = c4.fetchComposerDeps {
inherit src;
};
nativeBuildInputs = [
php.packages.composer
c4.composerSetupHook
];
installPhase = ''
runHook preInstall
composer --no-ansi install
cp -r . $out
runHook postInstall
'';
}
With Nix flakes
Warning: Nix flakes are experimental technology, use it only if you are willing to accept that you might need to change your code in the future.
Add this repository to the inputs
in your flake.nix
’s:
inputs = {
…
c4.url = "github:fossar/composition-c4";
};
then, add the overlay to your Nixpkgs instance. outputs
, you will be able to access our utilities under c4
namespace.
outputs = { self, nixpkgs, c4, ... }:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [ c4.overlay ];
};
in
{
packages.x86_64-linux.grav = pkgs.callPackage ./grav.nix { };
};
What is the complete API?
c4.fetchComposerDeps
This is a function that, for given source, returns a derivation with a Composer repository containing the packages listed by the Composer lock file in the source directory. It takes the following arguments:
- Either
lockFile
containing an explicit path tocomposer.lock
file, orsrc
, which is the source directory/derivation containing the file.
c4.composerSetupHook
This is a setup hook. By adding it to nativeBuildInputs
of a Nixpkgs derivation, the following hooks will be automatically enabled.
composerSetupPreConfigureHook
This hook will run before configurePhase
. Its goal is configuring the Composer project to use the repository created by c4.fetchComposerDeps
for fetching packages, instead of Packagist.
It is controlled by the following environment variables (pass them to the derivation so that they are available in the builder):
composerDeps
– the derivation produced byc4.fetchComposerDeps
.composerRoot
– when thecomposer.json
/composer.lock
files are not insourceRoot
, then the optionalcomposerRoot
is used to specify the PHP project’s root directory relative tosourceRoot
.
What are the limitations?
- It requires
composer.lock
to exist. - It currently only supports downloading packages from Git.
- When the lockfile comes from a source derivation rather then a local repository, Nix’s import from derivation mechanism will be used, inheriting all problems of IFD. Notably, it cannot be used in Nixpkgs.
- We download the sources at evaluation time so it will block evaluation, this is especially painful since Nix currently does not support parallel evaluation.
- Nix’s fetchers will fetch the full Git ref, which will take a long time for heavy repos like https://github.com/phpstan/phpstan.
- It might be somewhat slower than generated Nix files (e.g. composer2nix) since the Nix values need to be constructed from scratch every time.
For more information look at Nicolas’s An overview of language support in Nix presentation from NixCon 2019.
How does it work?
composer.lock
does not usually contain hashes of packages because they usually come from GitHub-generated tarballs, which are unstable. There is proposal for hashing the archive contents but there has not been a progress so far. This is a problem for Nix since without a hash, it cannot create a fixed-output derivation.
Fortunately, most packages come from git repositories and Nix can actually fetch git trees for commits without output hash using builtins.fetchGit
(at least when not in restricted-eval mode). This allows us to download individual packages.
We then create a Composer repository and using the setup hook, we point Composer to it so it can install packages from there.
Prior art and inspiration
There is Sander’s composer2nix but that follows the generator approach, which is not always convenient.
stephank’s composer-plugin-nixify also opts for the generator route but it hooks into Composer so the generated file is always in sync with composer.lock
(even for developers not using Nix).
We decided to use lockfile-based approach inspired by Nicolas’s napalm, a similar tool for npm (JavaScript). The hook design was based on rustPlatform.cargoSetupHook
and rustPlatform.fetchCargoTarball
from Nixpkgs.
License
The contents of this project is distributed under the MIT license.