Add option that makes it possible to skip the deployment of development dependencies even if they are included in composer.lock

This commit is contained in:
Sander van der Burg 2017-09-21 22:19:53 +02:00
parent 67805db37f
commit 4c20068b41
4 changed files with 104 additions and 57 deletions

View file

@ -182,14 +182,43 @@ Advanced features
=================
`composer2nix` supports a number of less commonly used advanced features.
Disabling the deployment of development dependencies
----------------------------------------------------
By default `composer` (and as a result, also `composer2nix`) will include all
development dependencies. However, in production environments you typically want
to exclude them to reduce the amount of disk space consumed and the deployment
times.
By overriding the expression (e.g. creating a file named: `override.nix`) and
appending the `noDev = true;` parameter, we can disable development
dependencies:
```nix
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem}:
let
phpPackage = import ./default.nix {
inherit pkgs system;
noDev = true; # Disable development dependencies
};
in
phpPackage
```
We can deploy the above package with the following command-line instruction:
$ nix-build override.nix
Running post installation instructions
--------------------------------------
For some packages, we may want to run additional command line instructions after
the packaging process completes, such as running unit tests.
By creating an override Nix expression (e.g. `override.nix`) that invokes the
generated build function and providing a `postInstall` hook, we can specify
additional command-line instructions to run:
By creating an override Nix expression that invokes the generated build function
and providing a `postInstall` hook, we can specify additional command-line
instructions to run:
```nix
{pkgs ? import <nixpkgs> {
@ -210,11 +239,6 @@ phpPackage.override {
In the above code fragment, we invoke `phpunit` to run all our unit tests.
We can deploy the above package (and run the corresponding tests) with the
following command-line instruction:
$ nix-build override.nix
Adding unspecified dependencies
-------------------------------
Some packages may also require non-PHP package dependencies. Since these

View file

@ -7,7 +7,8 @@ use Composer2Nix\Generator;
function displayHelp($command)
{
print("Usage: ".$command." [OPTION]\n\n");
print("Usage: ".$command." [OPTION]\n");
print(" or: ".$command." -p NAME [OPTION]\n\n");
echo <<<EOT
This executable can be used to generate Nix expressions from a composer.lock
(and a composer.json) file so that a package and all its dependencies can be
@ -18,7 +19,7 @@ Options:
composer.json)
--lock-file=FILE Path to the composer.lock file (defaults to:
composer.lock)
-p, --package Package to deploy as a command-line utility
-p, --package=NAME Name of a package to deploy as a command-line utility
--package-version Preferred version of the package to deploy (defaults
to the latest version)
--output=FILE Path to the Nix expression containing the generated
@ -29,7 +30,8 @@ Options:
packages (defaults to: composer-env.nix)
--prefer-source Forces installation from package sources when possible
--prefer-dist Forces installation from package dist
--no-dev Do not install the development packages
--no-dev Do not generate expressions for the development
packages
--name Name of the generated package (defaults to the name
provided in the composer.json file)
--executable Generate a Nix package for an executable as opposed to
@ -103,7 +105,6 @@ if(array_key_exists("lock-file", $options))
else
$lockFile = "composer.lock";
if(array_key_exists("output", $options))
$outputFile = $options["output"];
else
@ -133,7 +134,7 @@ else
$noCopyComposerEnv = array_key_exists("no-copy-composer-env", $options);
$preferredInstall = "dist"; // TODO: consult composer.json's preferred-install property. defaults to: auto
$preferredInstall = "dist";
if(array_key_exists("prefer-source", $options))
$preferredInstall = "source";

View file

@ -46,13 +46,8 @@ class Generator
return "./".$target;
}
private static function generatePackagesExpression(array $config, $outputFile, $name, $preferredInstall, array $packages, $executable, $symlinkDependencies)
private static function generatePackagesAttrSet(array $packages, $preferredInstall)
{
$handle = fopen($outputFile, "w");
if($handle === false)
throw new Exception("Cannot write to: ".$outputFile);
$dependencies = array();
foreach($packages as $package)
@ -136,6 +131,19 @@ class Generator
$dependencies[$package["name"]] = $dependency;
}
return new NixAttrSet($dependencies);
}
private static function generatePackagesExpression(array $config, $outputFile, $name, $preferredInstall, array $packages, array $devPackages, $executable, $symlinkDependencies)
{
$handle = fopen($outputFile, "w");
if($handle === false)
throw new Exception("Cannot write to: ".$outputFile);
$packagesAttrSet = Generator::generatePackagesAttrSet($packages, $preferredInstall);
$devpackagesAttrSet = Generator::generatePackagesAttrSet($devPackages, $preferredInstall);
/* Compose meta properties */
$meta = array();
@ -162,14 +170,18 @@ class Generator
"fetchurl" => new NixNoDefault(),
"fetchgit" => null,
"fetchhg" => null,
"fetchsvn" => null
"fetchsvn" => null,
"noDev" => false
), new NixLet(array(
"dependencies" => new NixAttrSet($dependencies)
"packages" => $packagesAttrSet,
"devPackages" => $devpackagesAttrSet
), new NixFunInvocation(new NixExpression("composerEnv.buildPackage"), array(
"name" => $name,
"src" => new NixFile("./."),
"executable" => $executable,
"dependencies" => new NixInherit(),
"packages" => new NixInherit(),
"devPackages" => new NixInherit(),
"noDev" => new NixInherit(),
"symlinkDependencies" => $symlinkDependencies,
"meta" => new NixAttrSet($meta)
))));
@ -190,7 +202,8 @@ class Generator
"pkgs" => new NixFunInvocation(new NixImport(new NixExpression("<nixpkgs>")), array(
"system" => new NixInherit()
)),
"system" => new NixAttrReference(new NixExpression("builtins"), new NixExpression("currentSystem"))
"system" => new NixAttrReference(new NixExpression("builtins"), new NixExpression("currentSystem")),
"noDev" => false
), new NixLet(array(
"composerEnv" => new NixFunInvocation(new NixImport(new NixFile(Generator::prefixRelativePath($composerEnvFile))), array(
"stdenv" => new NixInherit("pkgs"),
@ -201,6 +214,7 @@ class Generator
))
), new NixFunInvocation(new NixImport(new NixFile(Generator::prefixRelativePath($outputFile))), array(
"composerEnv" => new NixInherit(),
"noDev" => new NixInherit(),
"fetchurl" => new NixInherit("pkgs"),
"fetchgit" => new NixInherit("pkgs"),
"fetchhg" => new NixInherit("pkgs"),
@ -253,16 +267,18 @@ class Generator
$packages = array();
if(!$noDev && array_key_exists("packages-dev", $lockConfig))
{
foreach($lockConfig["packages-dev"] as $identifier => $devPackage)
$packages[$identifier] = $devPackage;
}
$devPackages = $lockConfig["packages-dev"];
else
$devPackages = array();
}
else
{
$packages = array();
$devPackages = array();
}
/* Generate packages expression */
Generator::generatePackagesExpression($config, $outputFile, $name, $preferredInstall, $packages, $executable, $symlinkDependencies);
Generator::generatePackagesExpression($config, $outputFile, $name, $preferredInstall, $packages, $devPackages, $executable, $symlinkDependencies);
/* Generate composition expression */
Generator::generateCompositionExpression($compositionFile, $outputFile, $composerEnvFile);

View file

@ -49,7 +49,7 @@ rec {
'';
};
buildPackage = { name, src, dependencies ? [], symlinkDependencies ? false, executable ? false, removeComposerArtifacts ? false, postInstall ? "", ...}@args:
buildPackage = { name, src, packages ? {}, devPackages ? {}, symlinkDependencies ? false, executable ? false, removeComposerArtifacts ? false, postInstall ? "", noDev ? false, ...}@args:
let
reconstructInstalled = writeTextFile {
name = "reconstructinstalled.php";
@ -75,8 +75,10 @@ rec {
else
$allPackages = array();
${stdenv.lib.optionalString (!noDev) ''
if(array_key_exists("packages-dev", $config))
$allPackages = array_merge($allPackages, $config["packages-dev"]);
''}
$packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
print($packagesStr);
@ -121,8 +123,33 @@ rec {
?>
'';
};
bundleDependencies = dependencies:
stdenv.lib.concatMapStrings (dependencyName:
let
dependency = dependencies.${dependencyName};
in
stdenv.lib.makeOverridable stdenv.mkDerivation (builtins.removeAttrs args [ "dependencies" ] // {
''
${if dependency.targetDir == "" then ''
vendorDir="$(dirname ${dependencyName})"
mkdir -p "$vendorDir"
${if symlinkDependencies then
''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
else
''cp -av "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
}
'' else ''
namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")"
mkdir -p "$namespaceDir"
${if symlinkDependencies then
''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
else
''cp -av "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
}
''}
'') (builtins.attrNames dependencies);
in
stdenv.lib.makeOverridable stdenv.mkDerivation (builtins.removeAttrs args [ "packages" "devPackages" ] // {
buildInputs = [ php composer ] ++ args.buildInputs or [];
buildCommand = ''
${if executable then ''
@ -150,38 +177,17 @@ rec {
# Copy or symlink the provided dependencies
cd vendor
${stdenv.lib.concatMapStrings (dependencyName:
let
dependency = dependencies.${dependencyName};
in
''
${if dependency.targetDir == "" then ''
vendorDir="$(dirname ${dependencyName})"
mkdir -p "$vendorDir"
${if symlinkDependencies then
''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
else
''cp -av "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
}
'' else ''
namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")"
mkdir -p "$namespaceDir"
${if symlinkDependencies then
''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
else
''cp -av "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
}
''}
'') (builtins.attrNames dependencies)}
${bundleDependencies packages}
${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)}
cd ..
# Reconstruct autoload scripts
# We use the optimize feature because Nix packages cannot change after they have been built
# Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload.
composer dump-autoload --optimize
composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"}
# Run the install step as a validation to confirm that everything works out as expected
composer install --optimize-autoloader
composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"}
${stdenv.lib.optionalString executable ''
${constructBin} composer.json