diff --git a/README.md b/README.md index 54011f6..c11e383 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Table of Contents - [Adding unspecified dependencies](#adding-unspecified-dependencies) - [Adding additional/global NPM packages to a packaging process](#adding-additionalglobal-npm-packages-to-a-packaging-process) - [Disabling running NPM install](#disabling-running-npm-install) + - [Using private Git repositories](#using-private-git-repositories) - [API documentation](#api-documentation) - [License](#license) - [Acknowledgements](#acknowledgements) @@ -482,6 +483,51 @@ By overriding a package and setting the `dontNpmInstall` parameter to `true`, we skip the install step (which merely serves as a check). The generated expression is actually responsible for obtaining and extracting the dependencies. +Using private Git repositories +------------------------------ +In some development projects, it may be desired to deploy private Git +repositories as dependencies. The `fetchgit {}` function in Nixpkgs, however, +only supports public repositories. + +It is also possible to instruct the generator to use the `fetchgitPrivate {}` +function, that adds support for private repositories that can be reached with +SSH: + +```bash +node2nix --use-fetchgit-private +``` + +Before running the `node2nix` command shown above, you probably want to set +up `ssh-agent` first and use `ssh-add` to add a private key to the keychain to +prevent the generator from asking for passphrases. + +When deploying a project or package, you need to pass an additional parameter +that provides an SSH configuration file with a reference to an identify file. +The following SSH config file (e.g. `~/ssh_config`) suffices for me: + +``` +StrictHostKeyChecking=no +UserKnownHostsFile /dev/null +IdentityFile ~/id_rsa +``` + +When deploying a package with Nix, you must propagate the location of the SSH +config file as a parameter: + +```bash +$ nix-build -A package -I ssh-config-file=~/ssh_config +``` + +It is also possible to provide the location of the config file by adapting the +`NIX_PATH` environment variable, as opposed to using the `-I` parameter: + +```bash +$ export NIX_PATH=ssh-config-file=~/ssh_config:$NIX_PATH +``` + +The above approach also makes it possible to deploy a NPM package with private +dependencies as part of a NixOS, NixOps or Disnix configuration. + API documentation ================= This package includes API documentation, which can be generated with diff --git a/bin/node2nix.js b/bin/node2nix.js index 733f4a9..f963e19 100644 --- a/bin/node2nix.js +++ b/bin/node2nix.js @@ -25,7 +25,8 @@ var switches = [ ['--pkg-name NAME', 'Specifies the name of the Node.js package to use from Nixpkgs (defaults to: nodejs)'], ['--registry NAME', 'URL referring to the NPM packages registry. It defaults to the official NPM one, but can be overridden to support private registries'], ['--bypass-cache', 'Specifies that package builds need to bypass the content addressable cache (required for NPM 5.x)'], - ['--no-copy-node-env', 'Do not create a copy of the Nix expression that builds NPM packages'] + ['--no-copy-node-env', 'Do not create a copy of the Nix expression that builds NPM packages'], + ['--use-fetchgit-private', 'Use fetchGitPrivate instead of fetchgit in the generated Nix expressions'] ]; var parser = new optparse.OptionParser(switches); @@ -48,6 +49,7 @@ var registryURL = "http://registry.npmjs.org"; var nodePackage = "nodejs-4_x"; var noCopyNodeEnv = false; var bypassCache = false; +var useFetchGitPrivate = false; var executable; /* Define process rules for option parameters */ @@ -131,6 +133,10 @@ parser.on('no-copy-node-env', function(arg, value) { noCopyNodeEnv = true; }); +parser.on('use-fetchgit-private', function(arg, value) { + useFetchGitPrivate = true; +}); + /* Define process rules for non-option parameters */ parser.on(1, function(opt) { @@ -193,7 +199,7 @@ if(version) { } /* Perform the NPM to Nix conversion */ -node2nix.npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, supplementJSON, supplementNix, production, includePeerDependencies, flatten, nodePackage, registryURL, noCopyNodeEnv, bypassCache, function(err) { +node2nix.npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, supplementJSON, supplementNix, production, includePeerDependencies, flatten, nodePackage, registryURL, noCopyNodeEnv, bypassCache, useFetchGitPrivate, function(err) { if(err) { process.stderr.write(err + "\n"); process.exit(1); diff --git a/lib/expressions/CompositionExpression.js b/lib/expressions/CompositionExpression.js index 9809328..bbd1b5b 100644 --- a/lib/expressions/CompositionExpression.js +++ b/lib/expressions/CompositionExpression.js @@ -18,12 +18,29 @@ function composePathRelativeToCompositionExpression(compositionNix, exprNix) { return prefixRelativePath(path.relative(path.dirname(compositionNix), exprNix)); } -function CompositionExpression(compositionNix, nodePackage, nodeEnvNix, packagesNix, supplementNix, generateSupplement) { +/** + * Creates a new composition expression instance. + * + * @class CompositionExpression + * @extends NixASTNode + * @classdesc Represents an expression that composes NPM packages + * + * @constructor + * @param {String} compositionNix Path to which the generated composition expression is written + * @param {String} nodePackage Name of the Node.js package to use from Nixpkgs + * @param {String} nodeEnvNix Path to which the NPM package build expression is written + * @param {String} packagesNix Path to a Nix expression containing packages and sources + * @param {String} supplementNix Path to which the generated supplement expression is written + * @param {Boolean} generateSupplement Indicates whether we need a reference to a supplement Nix expression + * @param {Boolean} useFetchGitPrivate Indicates that the fetchgitPrivate function should be used instead of fetchgit + */ +function CompositionExpression(compositionNix, nodePackage, nodeEnvNix, packagesNix, supplementNix, generateSupplement, useFetchGitPrivate) { this.nodePackage = nodePackage; this.nodeEnvNixPath = composePathRelativeToCompositionExpression(compositionNix, nodeEnvNix); this.packagesNixPath = composePathRelativeToCompositionExpression(compositionNix, packagesNix); this.supplementNix = supplementNix; this.generateSupplement = generateSupplement; + this.useFetchGitPrivate = useFetchGitPrivate; } /* CompositionExpression inherits from NixASTNode */ @@ -34,6 +51,17 @@ inherit(nijs.NixASTNode, CompositionExpression); */ CompositionExpression.prototype.toNixAST = function() { var globalBuildInputs; + var fetchgitAttr; + + // Determine which fetchgit function to use + if(this.useFetchGitPrivate) { + fetchgitAttr = new nijs.NixAttrReference({ + attrSetExpr: new nijs.NixExpression("pkgs"), + refExpr: new nijs.NixExpression("fetchgitPrivate") + }); + } else { + fetchgitAttr = new nijs.NixInherit("pkgs"); + } if(this.generateSupplement) { var supplementNixPath = prefixRelativePath(this.supplementNix); @@ -45,7 +73,7 @@ CompositionExpression.prototype.toNixAST = function() { paramExpr: { nodeEnv: new nijs.NixInherit(), fetchurl: new nijs.NixInherit("pkgs"), - fetchgit: new nijs.NixInherit("pkgs") + fetchgit: fetchgitAttr } }) }); @@ -88,7 +116,7 @@ CompositionExpression.prototype.toNixAST = function() { funExpr: new nijs.NixImport(new nijs.NixFile({ value: this.packagesNixPath })), paramExpr: { fetchurl: new nijs.NixInherit("pkgs"), - fetchgit: new nijs.NixInherit("pkgs"), + fetchgit: fetchgitAttr, nodeEnv: new nijs.NixInherit(), globalBuildInputs: globalBuildInputs ? new nijs.NixInherit() : undefined } diff --git a/lib/node2nix.js b/lib/node2nix.js index dc8b19c..d2cc22e 100644 --- a/lib/node2nix.js +++ b/lib/node2nix.js @@ -42,7 +42,7 @@ function copyNodeEnvExpr(nodeEnvNix, callback) { */ exports.copyNodeEnvExpr = copyNodeEnvExpr; -function npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, supplementJSON, supplementNix, production, includePeerDependencies, flatten, nodePackage, registryURL, noCopyNodeEnv, bypassCache, callback) { +function npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, supplementJSON, supplementNix, production, includePeerDependencies, flatten, nodePackage, registryURL, noCopyNodeEnv, bypassCache, useFetchGitPrivate, callback) { var obj = JSON.parse(fs.readFileSync(inputJSON)); var version = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"))).version; var disclaimer = "# This file has been generated by node2nix " + version + ". Do not edit!\n\n"; @@ -121,7 +121,7 @@ function npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, su /* Generate and write a Nix composition expression to the specified output file */ function(callback) { - expr = new CompositionExpression(compositionNix, nodePackage, nodeEnvNix, outputNix, supplementNix, (supplementJSON !== undefined)); + expr = new CompositionExpression(compositionNix, nodePackage, nodeEnvNix, outputNix, supplementNix, (supplementJSON !== undefined), useFetchGitPrivate); fs.writeFile(compositionNix, disclaimer + nijs.jsToNix(expr, true), callback); }, @@ -154,6 +154,7 @@ function npmToNix(inputJSON, outputNix, compositionNix, nodeEnvNix, lockJSON, su * @param {String} registryURL URL of the NPM registry * @param {Boolean} noCopyNodeEnv Indicates that no copy of the NPM package build expression should be made * @param {Boolean} bypassCache Indicates that the content addressable cache should be bypassed + * @param {Boolean} useFetchGitPrivate Indicates that the fetchgitPrivate function should be used instead of fetchgit * @param {function(String, String)} callback Callback function that gets invoked when the work is done. * If an error occurs, the error parameter is set to contain the error * If the operation succeeds, it returns a string containing the registry expression containing the packages and all its dependencies