-
Notifications
You must be signed in to change notification settings - Fork 50
/
prepNodeBin.js
152 lines (120 loc) · 5.18 KB
/
prepNodeBin.js
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
const ResEdit = require('resedit')
const { join } = require("path")
const { access, createWriteStream, constants, existsSync, mkdirSync, readFileSync, unlink, writeFileSync } = require('fs')
const { get } = require('https')
function download(url, dest) {
return new Promise((resolve, reject) => {
access(dest, constants.F_OK, (accessErr) => {
if (accessErr === null) return reject('File already exists')
const request = get(url, response => {
if (response.statusCode === 200) {
const file = createWriteStream(dest, { flags: 'wx' })
file.on('finish', () => resolve())
file.on('error', err => {
file.close()
if (err.code === 'EEXIST') reject('File already exists')
else unlink(dest, () => reject(err.message)) // Delete temp file
})
response.pipe(file)
} else if (response.statusCode === 302 || response.statusCode === 301) {
download(response.headers.location, dest).then(() => resolve())
} else {
reject(`Server responded with ${response.statusCode}: ${response.statusMessage}`)
}
})
request.on('error', err => reject(err.message))
})
})
}
const packageConfig = require('./package.json')
const supportedNodeVersions = Object.keys(require('pkg-fetch/patches/patches.json')).map(v => v.slice(1))
const pkgFetchVersion = `v${require('pkg-fetch/package').version.split('.').slice(0, 2).join('.')}`
const cachePath = join(process.env['PKG_CACHE_PATH'], pkgFetchVersion)
function getTargetInfo(target) {
const targetVersion = target.match(/node(.*?)-/)[1]
const nodeVersion = supportedNodeVersions.find(v => v.split('.')[0] === targetVersion)
return {
nodeVersion,
fetchedPath: join(cachePath, `fetched-v${nodeVersion}-win-x64`),
builtPath: join(cachePath, `built-v${nodeVersion}-win-x64`),
url: `https://github.com/vercel/pkg-fetch/releases/download/${pkgFetchVersion}/node-v${nodeVersion}-win-x64`
}
}
function checkExistingBuild(builtPath, versionSegments) {
const buildVersion = `${versionSegments[0]}.${versionSegments[1]}.${versionSegments[2]}.${versionSegments[3]}`
if (!existsSync(builtPath)) return false
const builtExe = ResEdit.NtExecutable.from(readFileSync(builtPath))
const builtRes = ResEdit.NtExecutableResource.from(builtExe)
const builtViList = ResEdit.Resource.VersionInfo.fromEntries(builtRes.entries)
const builtVersion = builtViList[0].getStringValues({ lang: 1033, codepage: 1200 })?.['FileVersion']
if (buildVersion === builtVersion) {
console.log('Using existing build')
return true
}
console.log('Version changed, rebuilding...')
return false
}
module.exports = async () => {
const targets = packageConfig.pkg.targets.map(getTargetInfo)
for (let target of targets) {
const { nodeVersion, fetchedPath, builtPath, url } = target
const versionSegments = `${packageConfig.version.replace('-', '.')}`.split('.').map(v => parseInt(v))
while (versionSegments.length < 4) versionSegments.push(0)
console.log('Target:', nodeVersion)
if (checkExistingBuild(builtPath, versionSegments)) continue
if (!existsSync(fetchedPath)) {
console.log('Downloading file...')
// attemp to create directory
try { mkdirSync(cachePath, { recursive: true }) } catch (e) { console.error(e) }
// attemp to download file
try {
await download(url, fetchedPath)
} catch (e) {
console.error(e)
process.exit(1)
}
console.log('Downloaded file.')
} else {
console.log('Using existing file')
}
console.log('Reading EXE')
const exe = ResEdit.NtExecutable.from(readFileSync(fetchedPath))
const res = ResEdit.NtExecutableResource.from(exe)
const viList = ResEdit.Resource.VersionInfo.fromEntries(res.entries)
const vi = viList[0]
console.log(vi.data.strings)
console.log('Removing OriginalFilename')
vi.removeStringValue({ lang: 1033, codepage: 1200 }, 'OriginalFilename')
console.log('Removing InternalName')
vi.removeStringValue({ lang: 1033, codepage: 1200 }, 'InternalName')
console.log('Setting Product Version')
vi.setProductVersion(versionSegments[0], versionSegments[1], versionSegments[2], versionSegments[3], 1033)
console.log('Setting File Version')
vi.setFileVersion(versionSegments[0], versionSegments[1], versionSegments[2], versionSegments[3], 1033)
console.log('Setting File Info')
vi.setStringValues(
{ lang: 1033, codepage: 1200 },
{
FileDescription: packageConfig.description,
ProductName: packageConfig.name,
CompanyName: '',
LegalCopyright: packageConfig.author
}
)
console.log(vi.data.strings)
vi.outputToResourceEntries(res.entries)
console.log('Replacing Icon')
const iconFile = ResEdit.Data.IconFile.from(readFileSync(join(__dirname, 'appIcon.ico')))
ResEdit.Resource.IconGroupEntry.replaceIconsForResource(
res.entries,
1,
1033,
iconFile.icons.map((item) => item.data)
)
res.outputResource(exe)
console.log('Generating EXE')
const newBinary = exe.generate()
console.log('Saving EXE')
writeFileSync(builtPath, Buffer.from(newBinary))
}
}