@@ -4,6 +4,9 @@ const common = require('../common'); |
4 | 4 | const fixtures = require('../common/fixtures'); |
5 | 5 | const tmpdir = require('../common/tmpdir'); |
6 | 6 | const { inspect } = require('util'); |
| 7 | +const fs = require('fs'); |
| 8 | +const path = require('path'); |
| 9 | +const assert = require('assert'); |
7 | 10 |
|
8 | 11 | const { readFileSync, copyFileSync, statSync } = require('fs'); |
9 | 12 | const { |
@@ -70,37 +73,76 @@ function skipIfSingleExecutableIsNotSupported() { |
70 | 73 | } |
71 | 74 | } |
72 | 75 |
|
73 | | -function generateSEA(targetExecutable, sourceExecutable, seaBlob, verifyWorkflow = false) { |
| 76 | +function generateSEA(fixtureDir, options = {}) { |
| 77 | + const { |
| 78 | + workingDir = tmpdir.path, |
| 79 | + configPath = 'sea-config.json', |
| 80 | + verifyWorkflow = false, |
| 81 | + } = options; |
| 82 | + // Copy fixture files to working directory if they are different. |
| 83 | + if (fixtureDir !== workingDir) { |
| 84 | + fs.cpSync(fixtureDir, workingDir, { recursive: true }); |
| 85 | + } |
| 86 | + |
| 87 | + // Determine the output executable path. |
| 88 | + const outputFile = path.resolve(workingDir, process.platform === 'win32' ? 'sea.exe' : 'sea'); |
| 89 | + |
74 | 90 | try { |
75 | | - copyFileSync(sourceExecutable, targetExecutable); |
| 91 | + // Copy the executable. |
| 92 | + copyFileSync(process.execPath, outputFile); |
| 93 | + console.log(`Copied ${process.execPath} to ${outputFile}`); |
76 | 94 | } catch (e) { |
77 | | - const message = `Cannot copy ${sourceExecutable} to ${targetExecutable}: ${inspect(e)}`; |
| 95 | + const message = `Cannot copy ${process.execPath} to ${outputFile}: ${inspect(e)}`; |
78 | 96 | if (verifyWorkflow) { |
79 | 97 | throw new Error(message); |
80 | 98 | } |
81 | 99 | common.skip(message); |
82 | 100 | } |
83 | | - console.log(`Copied ${sourceExecutable} to ${targetExecutable}`); |
84 | 101 |
|
| 102 | + // Generate the blob using --experimental-sea-config. |
| 103 | + spawnSyncAndExitWithoutError( |
| 104 | + process.execPath, |
| 105 | + ['--experimental-sea-config', configPath], |
| 106 | + { |
| 107 | + cwd: workingDir, |
| 108 | + env: { |
| 109 | + NODE_DEBUG_NATIVE: 'SEA', |
| 110 | + ...process.env, |
| 111 | + }, |
| 112 | + }, |
| 113 | + ); |
| 114 | + |
| 115 | + // Parse the config to get the output file path. |
| 116 | + const config = JSON.parse(fs.readFileSync(path.resolve(workingDir, configPath))); |
| 117 | + assert.strictEqual(typeof config.output, 'string'); |
| 118 | + const seaPrepBlob = path.resolve(workingDir, config.output); |
| 119 | + assert(fs.existsSync(seaPrepBlob), `Expected SEA blob ${seaPrepBlob} to exist`); |
| 120 | + |
| 121 | + // Use postject to inject the blob. |
85 | 122 | const postjectFile = fixtures.path('postject-copy', 'node_modules', 'postject', 'dist', 'cli.js'); |
86 | 123 | try { |
87 | 124 | spawnSyncAndExitWithoutError(process.execPath, [ |
88 | 125 | postjectFile, |
89 | | - targetExecutable, |
| 126 | + outputFile, |
90 | 127 | 'NODE_SEA_BLOB', |
91 | | - seaBlob, |
| 128 | + seaPrepBlob, |
92 | 129 | '--sentinel-fuse', 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2', |
93 | 130 | ...process.platform === 'darwin' ? [ '--macho-segment-name', 'NODE_SEA' ] : [], |
94 | 131 | ]); |
95 | 132 | } catch (e) { |
96 | | - const message = `Cannot inject ${seaBlob} into ${targetExecutable}: ${inspect(e)}`; |
| 133 | + const message = `Cannot inject ${seaPrepBlob} into ${outputFile}: ${inspect(e)}`; |
97 | 134 | if (verifyWorkflow) { |
98 | 135 | throw new Error(message); |
99 | 136 | } |
100 | 137 | common.skip(message); |
101 | 138 | } |
102 | | - console.log(`Injected ${seaBlob} into ${targetExecutable}`); |
| 139 | + console.log(`Injected ${seaPrepBlob} into ${outputFile}`); |
| 140 | + |
| 141 | + signSEA(outputFile, verifyWorkflow); |
| 142 | + return outputFile; |
| 143 | +} |
103 | 144 |
|
| 145 | +function signSEA(targetExecutable, verifyWorkflow = false) { |
104 | 146 | if (process.platform === 'darwin') { |
105 | 147 | try { |
106 | 148 | spawnSyncAndExitWithoutError('codesign', [ '--sign', '-', targetExecutable ]); |
|