Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fossar/composition-c4

Fetch Composer dependencies using Nix
https://github.com/fossar/composition-c4

Last synced: about 1 month ago
JSON representation

Fetch Composer dependencies using Nix

Awesome Lists containing this project

README

        

# Composition C-4

This is a lightweight library that allows downloading [Composer](https://getcomposer.org/) dependencies using [Nix](https://nixos.org/). It falls under lockfile-based tools in [nmattia’s typology][nixcon-language-support-overview].

> **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.

```nix
{
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:

```nix
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.

```nix
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](https://nixos.org/manual/nixpkgs/stable/#ssec-setup-hooks). By adding it to `nativeBuildInputs` of a Nixpkgs derivation, the following hooks will be automatically enabled.

#### `composerSetupPreConfigureHook`

This hook will run before [`configurePhase`](https://nixos.org/manual/nixpkgs/unstable/#ssec-configure-phase). 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](https://nixos.wiki/wiki/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][nixcon-language-support-overview]_ 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](https://github.com/composer/composer/issues/2540) 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](https://github.com/NixOS/nix/issues/3469)). This allows us to download individual packages.

We then create a [Composer repository](https://getcomposer.org/doc/05-repositories.md) 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](https://github.com/stephank/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](https://github.com/nmattia/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](LICENSE.md).

[nixcon-language-support-overview]: https://www.nmattia.com/posts/2019-11-12-language-support-overview-nixcon.html
[composer2nix]: https://github.com/svanderburg/composer2nix