-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild-contract-predockerbuild
More file actions
executable file
·135 lines (120 loc) · 5.24 KB
/
build-contract-predockerbuild
File metadata and controls
executable file
·135 lines (120 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const mnpm = require('./mnpm');
const npmLib = new Promise((resolve,reject) => {
// ls -la $(which npm), or we could do something like https://stackoverflow.com/a/25106648/113009
const guesses = ['./node_modules/npm', '/usr/local/lib/node_modules/npm', '/usr/lib/node_modules/npm'];
const check = (path) => path ? fs.stat(path, (err, stats) => {
if (err) return check(guesses.shift());
let installed = /^(?:\.\/)?node_modules\/(.*)/.exec(path);
if (installed) path = installed[1];
require(installed ? installed[1] : path).load((err, loaded) => {
if (err) throw err;
resolve(loaded);
});
}) : reject(new Error("Failed to guess the npm lib\'s install path. Try `npm (link|install) npm`."));
check(guesses.shift());
});
let dir = path.resolve('.');
let mdir = path.join(dir, 'npm-monorepo');
let cidir = path.join(mdir, 'ci');
let cimdir = path.join(cidir, 'npm-monorepo');
/**
* Gets a minimal package.json with only the stuff that should
* trigger an invalidation of docker build cache for the npm ci layer.
*/
function getCiPackage(packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
dependencies: packageJson.dependencies
}
}
/**
* Produces a package tarball.
* @param modulePath In case we find a way to avoid depending on process.cwd
*/
function npmPackage(modulePath, cb) {
if (process.cwd() !== modulePath) throw new Error('npm expected to run in ' + modulePath + ', not ' + process.cwd());
npmLib.then(npm => {
npm.commands.pack([], (err, result) => {
if (err) return cb(err);
const name = result[0].filename;
fs.stat(name, (err, stats) => {
if (err) console.error('# npm pack failed to produce the result file', npm, process.cwd());
cb(err, err ? undefined : name);
});
});
});
}
let package = require(path.join(dir,'package.json'));
let monorepoDeps = Object.keys(package.dependencies).filter(
dep => /^file:\.\.\//.test(package.dependencies[dep]));
fs.mkdir(dir, err1 => fs.mkdir(mdir, err2 => fs.mkdir(cidir, err3 => fs.mkdir(cimdir, err => {
if (err) {
if (err.code !== 'EEXIST') throw err;
console.log('# Monorepo dir structure already present', cimdir);
}
const completed = () => {
process.chdir(dir); // restore after npm
if (monorepoDeps.length) {
console.log('# Zero monorepo dependencies found');
fs.unlink(path.join(cimdir, 'package.json'), err => err && console.error('Failed to clean up after sourceless tgz pack', err));
}
fs.writeFile(path.join(mdir, 'package.json'), mnpm.stringifyPackageJson(package),
err => { if (err) throw err; });
const ciPackage = getCiPackage(package);
fs.writeFile(path.join(cidir, 'package.json'), mnpm.stringifyPackageJson(ciPackage),
err => { if (err) throw err; });
fs.unlink(path.join(cimdir, '.npmignore'), err => err && console.error(err));
};
// Needed for the depCiPackage part in the callback stack below
fs.writeFile(path.join(cimdir, '.npmignore'), "*.tgz\n", err => err && console.error(err));
const next = dep => {
if (!dep) return completed();
let uri = package.dependencies[dep];
let urimatch = /^file:(\.\.\/.*)/.exec(uri);
if (!urimatch) return console.error('# Unrecognized monorepo dependency URI', uri);
let depdir = path.normalize(path.join(dir, urimatch[1]));
process.chdir(dir); process.chdir(depdir); // for npm
let depPackage = require(path.resolve('./package.json'));
npmPackage(depdir, (err, tgzname) => {
if (err) throw err;
console.log('# Packed', tgzname, 'in', process.cwd());
fs.rename(tgzname, path.join(mdir, tgzname), err => {
if (err) throw err;
console.log('# Created monorepo tarball', mdir, tgzname);
package.dependencies[dep] = `file:npm-monorepo/${tgzname}`;
let depCiPackage = getCiPackage(depPackage);
// We could probably speed things up here by using tar-stream, and maybe set permissions
let depPpJson = path.join(cimdir, 'package.json');
fs.writeFile(depPpJson, mnpm.stringifyPackageJson(depCiPackage), err => {
mnpm.writeProdPackageTgzWithDeterministicHash({
packageJsonObject: getCiPackage(depPackage),
filePath: path.join(cimdir, tgzname)
}).then(() => {
console.log('# Created monorepo sourceless tarball for npm ci', cimdir, tgzname);
console.log('------- debug info -------');
process.chdir(cimdir); // for npm
require('child_process').execSync('tar xvzf ' + tgzname, {stdio:[0,1,2]});
require('child_process').execSync('ls -la package/', {stdio:[0,1,2]});
require('child_process').execSync('shasum package/package.json', {stdio:[0,1,2]});
require('child_process').execSync('rm -rf package/', {stdio:[0,1,2]});
console.log('------- ---------- -------');
next(monorepoDeps.shift());
});
});
});
});
};
next(monorepoDeps.shift());
}))));
process.on('uncaughtException', err => {
console.error('Uncaught exception', err);
process.exit(1);
});
process.on('unhandledRejection', (err, p) => {
console.error('Unhandled rejection', err);
process.exit(1);
});