• Stars
    star
    9
  • Rank 1,878,280 (Top 39 %)
  • Language
    Nix
  • License
    MIT License
  • Created almost 3 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fetch Composer dependencies using Nix

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:

  • Either lockFile containing an explicit path to composer.lock file, or src, 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 by c4.fetchComposerDeps.
  • composerRoot – when the composer.json/composer.lock files are not in sourceRoot, then the optional composerRoot is used to specify the PHP project’s root directory relative to sourceRoot.

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.