1/* eslint-disable n/no-deprecated-api */
2
3'use strict'
4
5const semver = require('semver')
6const url = require('url')
7const path = require('path')
8const log = require('./log')
9
10// versions where -headers.tar.gz started shipping
11const headersTarballRange = '>= 3.0.0 || ~0.12.10 || ~0.10.42'
12const bitsre = /\/win-(x86|x64|arm64)\//
13const bitsreV3 = /\/win-(x86|ia32|x64)\// // io.js v3.x.x shipped with "ia32" but should
14// have been "x86"
15
16// Captures all the logic required to determine download URLs, local directory and
17// file names. Inputs come from command-line switches (--target, --dist-url),
18// `process.version` and `process.release` where it exists.
19function processRelease (argv, gyp, defaultVersion, defaultRelease) {
20  let version = (semver.valid(argv[0]) && argv[0]) || gyp.opts.target || defaultVersion
21  const versionSemver = semver.parse(version)
22  let overrideDistUrl = gyp.opts['dist-url'] || gyp.opts.disturl
23  let isNamedForLegacyIojs
24  let name
25  let distBaseUrl
26  let baseUrl
27  let libUrl32
28  let libUrl64
29  let libUrlArm64
30  let tarballUrl
31  let canGetHeaders
32
33  if (!versionSemver) {
34    // not a valid semver string, nothing we can do
35    return { version }
36  }
37  // flatten version into String
38  version = versionSemver.version
39
40  // defaultVersion should come from process.version so ought to be valid semver
41  const isDefaultVersion = version === semver.parse(defaultVersion).version
42
43  // can't use process.release if we're using --target=x.y.z
44  if (!isDefaultVersion) {
45    defaultRelease = null
46  }
47
48  if (defaultRelease) {
49    // v3 onward, has process.release
50    name = defaultRelease.name.replace(/io\.js/, 'iojs') // remove the '.' for directory naming purposes
51  } else {
52    // old node or alternative --target=
53    // semver.satisfies() doesn't like prerelease tags so test major directly
54    isNamedForLegacyIojs = versionSemver.major >= 1 && versionSemver.major < 4
55    // isNamedForLegacyIojs is required to support Electron < 4 (in particular Electron 3)
56    // as previously this logic was used to ensure "iojs" was used to download iojs releases
57    // and "node" for node releases.  Unfortunately the logic was broad enough that electron@3
58    // published release assets as "iojs" so that the node-gyp logic worked.  Once Electron@3 has
59    // been EOL for a while (late 2019) we should remove this hack.
60    name = isNamedForLegacyIojs ? 'iojs' : 'node'
61  }
62
63  // check for the nvm.sh standard mirror env variables
64  if (!overrideDistUrl && process.env.NODEJS_ORG_MIRROR) {
65    overrideDistUrl = process.env.NODEJS_ORG_MIRROR
66  }
67
68  if (overrideDistUrl) {
69    log.verbose('download', 'using dist-url', overrideDistUrl)
70  }
71
72  if (overrideDistUrl) {
73    distBaseUrl = overrideDistUrl.replace(/\/+$/, '')
74  } else {
75    distBaseUrl = 'https://nodejs.org/dist'
76  }
77  distBaseUrl += '/v' + version + '/'
78
79  // new style, based on process.release so we have a lot of the data we need
80  if (defaultRelease && defaultRelease.headersUrl && !overrideDistUrl) {
81    baseUrl = url.resolve(defaultRelease.headersUrl, './')
82    libUrl32 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x86', versionSemver.major)
83    libUrl64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x64', versionSemver.major)
84    libUrlArm64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'arm64', versionSemver.major)
85    tarballUrl = defaultRelease.headersUrl
86  } else {
87    // older versions without process.release are captured here and we have to make
88    // a lot of assumptions, additionally if you --target=x.y.z then we can't use the
89    // current process.release
90    baseUrl = distBaseUrl
91    libUrl32 = resolveLibUrl(name, baseUrl, 'x86', versionSemver.major)
92    libUrl64 = resolveLibUrl(name, baseUrl, 'x64', versionSemver.major)
93    libUrlArm64 = resolveLibUrl(name, baseUrl, 'arm64', versionSemver.major)
94
95    // making the bold assumption that anything with a version number >3.0.0 will
96    // have a *-headers.tar.gz file in its dist location, even some frankenstein
97    // custom version
98    canGetHeaders = semver.satisfies(versionSemver, headersTarballRange)
99    tarballUrl = url.resolve(baseUrl, name + '-v' + version + (canGetHeaders ? '-headers' : '') + '.tar.gz')
100  }
101
102  return {
103    version,
104    semver: versionSemver,
105    name,
106    baseUrl,
107    tarballUrl,
108    shasumsUrl: url.resolve(baseUrl, 'SHASUMS256.txt'),
109    versionDir: (name !== 'node' ? name + '-' : '') + version,
110    ia32: {
111      libUrl: libUrl32,
112      libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl32).path))
113    },
114    x64: {
115      libUrl: libUrl64,
116      libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl64).path))
117    },
118    arm64: {
119      libUrl: libUrlArm64,
120      libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrlArm64).path))
121    }
122  }
123}
124
125function normalizePath (p) {
126  return path.normalize(p).replace(/\\/g, '/')
127}
128
129function resolveLibUrl (name, defaultUrl, arch, versionMajor) {
130  const base = url.resolve(defaultUrl, './')
131  const hasLibUrl = bitsre.test(defaultUrl) || (versionMajor === 3 && bitsreV3.test(defaultUrl))
132
133  if (!hasLibUrl) {
134    // let's assume it's a baseUrl then
135    if (versionMajor >= 1) {
136      return url.resolve(base, 'win-' + arch + '/' + name + '.lib')
137    }
138    // prior to io.js@1.0.0 32-bit node.lib lives in /, 64-bit lives in /x64/
139    return url.resolve(base, (arch === 'x86' ? '' : arch + '/') + name + '.lib')
140  }
141
142  // else we have a proper url to a .lib, just make sure it's the right arch
143  return defaultUrl.replace(versionMajor === 3 ? bitsreV3 : bitsre, '/win-' + arch + '/')
144}
145
146module.exports = processRelease
147