Home

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?

  1. Pass the output of c4.fetchComposerDeps as composerDeps to derivation.
  2. 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:

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):

What are the limitations?

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.