UNPKG

4.7 kBJavaScriptView Raw
1#!/usr/bin/env node
2const fs = require('fs');
3const path = require('path');
4const child_process = require('child_process');
5const _ = require('lodash');
6
7const exec = function (cmd, args) {
8 return new Promise(function (resolve, reject) {
9 // Execute command
10 const child = child_process.exec(cmd, {
11 cwd: process.cwd(),
12 env: process.env,
13 });
14
15 // Pass stdout and stderr
16 child.stdout.on('data', function (data) {
17 process.stdout.write(data.toString());
18 });
19 child.stderr.on('data', function (data) {
20 process.stderr.write(data.toString());
21 });
22 // Handle result
23 child.on('exit', function (code) {
24 if (code) reject(code);
25 else resolve();
26 });
27 child.on('error', reject);
28 });
29};
30
31const CWD = process.cwd();
32const POSTINSTALL_BUILD_CWD = process.env.POSTINSTALL_BUILD_CWD;
33
34// If we didn't have this check, then we'd be stuck in an infinite `postinstall`
35// loop, since we run `npm install --only=dev` below, triggering another
36// `postinstall`. We can't use `--ignore-scripts` because that ignores scripts
37// on all the modules that get installed, too, which would break stuff. So
38// instead, we set an environment variable, `POSTINSTALL_BUILD_CWD`, that keeps
39// track of what we're installing. It's more than just a yes/no flag because
40// the dev dependencies we're installing might use `postinstall-build` too, and
41// we don't want the flag to prevent them from running.
42if (POSTINSTALL_BUILD_CWD !== CWD) {
43 const BUILD_ARTIFACT = process.argv[2];
44 const BUILD_COMMAND = process.argv[3];
45
46 fs.stat(BUILD_ARTIFACT, function (err, stats) {
47 if (err || !(stats.isFile() || stats.isDirectory())) {
48 // This script will run again after we run `npm install` below. Set an
49 // environment variable to tell it to skip the check. Really we just want
50 // the execSync's `env` to be modified, but it's easier just modify and
51 // pass along the entire `process.env`.
52 process.env.POSTINSTALL_BUILD_CWD = CWD;
53 // We already have prod dependencies, that's what triggered `postinstall`
54 // in the first place. So only install dev.
55
56 // Fetch package.json
57 const pkgJson = require(path.join(CWD, 'package.json'));
58 const devDeps = pkgJson.devDependencies;
59 // Values listed under `buildDependencies` contain the dependency names
60 // that are required for `lib` building.
61 const buildDependencies = _.pick(devDeps, pkgJson.buildDependencies);
62
63 // Proceed only if there is something to install
64 if (!_.isEmpty(buildDependencies)) {
65 const opts = { env: process.env, stdio: 'inherit' };
66
67 console.log('Building Knex.js');
68
69 // Map all key (dependency) value (semver) pairs to
70 // "dependency@semver dependency@semver ..." string that can be used
71 // for `npm install` command
72 const installArgs = _(buildDependencies)
73 .pickBy(function (semver, dep) {
74 // Check if the dependency is already installed
75 try {
76 require(dep);
77 return false;
78 } catch (err) {
79 return true;
80 }
81 })
82 .map(function (semver, dep) {
83 // Format installable dependencies
84 return dep + '@' + semver;
85 })
86 .value()
87 .join(' ');
88 const needsDepInstallation = !_.isEmpty(installArgs);
89 const dependenciesInstalledQ = needsDepInstallation
90 ? exec('npm install ' + installArgs, opts)
91 : Promise.resolve();
92 dependenciesInstalledQ
93 .then(function () {
94 console.log('✓');
95 // Don't need the flag anymore as `postinstall` was already run.
96 // Change it back so the environment is minimally changed for the
97 // remaining commands.
98 process.env.POSTINSTALL_BUILD_CWD = POSTINSTALL_BUILD_CWD;
99 console.log('Building compiled files (' + BUILD_COMMAND + ')');
100 return exec(BUILD_COMMAND, opts);
101 })
102 .catch(function (err) {
103 console.error(err);
104 process.exit(1);
105 })
106 .then(function () {
107 if (process.env.NODE_ENV === 'production') {
108 console.log('✓');
109 console.log('Pruning dev dependencies for production build');
110 return exec('npm prune --production', opts);
111 } else {
112 console.log('Skipping npm prune');
113 }
114 })
115 .then(function () {
116 console.log('✓');
117 })
118 .catch(function (err) {
119 console.error(err);
120 process.exit(1);
121 });
122 }
123 }
124 });
125}