1 | const childProcess = require('child_process')
|
2 | const { promisify } = require('util')
|
3 | const fs = require('fs')
|
4 | const path = require('path')
|
5 | const c = require('./colors')
|
6 |
|
7 | const exec = promisify(childProcess.exec)
|
8 | const copyFile = promisify(fs.copyFile)
|
9 | const mkdir = promisify(fs.mkdir)
|
10 | const stat = promisify(fs.stat)
|
11 |
|
12 | async function main() {
|
13 | if (process.env.INIT_CWD) {
|
14 | process.chdir(process.env.INIT_CWD)
|
15 |
|
16 | }
|
17 | await ensureEmptyDotPrisma()
|
18 |
|
19 | const localPath = getLocalPackagePath()
|
20 |
|
21 | const installedGlobally = localPath ? undefined : await isInstalledGlobally()
|
22 |
|
23 | process.env.PRISMA_GENERATE_IN_POSTINSTALL = 'true'
|
24 | try {
|
25 | if (localPath) {
|
26 | await run('node', [
|
27 | localPath,
|
28 | 'generate',
|
29 | '--postinstall',
|
30 | doubleQuote(getPostInstallTrigger()),
|
31 | ])
|
32 | return
|
33 | }
|
34 |
|
35 | if (installedGlobally) {
|
36 | await run('prisma', [
|
37 | 'generate',
|
38 | '--postinstall',
|
39 | doubleQuote(getPostInstallTrigger()),
|
40 | ])
|
41 | return
|
42 | }
|
43 | } catch (e) {
|
44 |
|
45 | if (e && e !== 1) {
|
46 | console.error(e)
|
47 | }
|
48 | }
|
49 |
|
50 | if (!localPath && !installedGlobally) {
|
51 | console.error(
|
52 | `${c.yellow(
|
53 | 'warning',
|
54 | )} In order to use "@prisma/client", please install @prisma/cli. You can install it with "npm add -D @prisma/cli".`,
|
55 | )
|
56 | }
|
57 | }
|
58 |
|
59 | function getLocalPackagePath() {
|
60 | let packagePath
|
61 | try {
|
62 | packagePath = require.resolve('@prisma/cli/package.json')
|
63 | } catch (e) {
|
64 | return null
|
65 | }
|
66 |
|
67 | if (packagePath) {
|
68 | return require.resolve('@prisma/cli')
|
69 | }
|
70 |
|
71 | return null
|
72 | }
|
73 |
|
74 | async function isInstalledGlobally() {
|
75 | try {
|
76 | const result = await exec('prisma -v')
|
77 | if (result.stdout.includes('@prisma/cli')) {
|
78 | return true
|
79 | } else {
|
80 | console.error(`${c.yellow('warning')} You still have the ${c.bold(
|
81 | 'prisma',
|
82 | )} cli (Prisma 1) installed globally.
|
83 | Please uninstall it with either ${c.green('npm remove -g prisma')} or ${c.green(
|
84 | 'yarn global remove prisma',
|
85 | )}.`)
|
86 | }
|
87 | } catch (e) {
|
88 | return false
|
89 | }
|
90 | }
|
91 |
|
92 | if (!process.env.SKIP_GENERATE) {
|
93 | main().catch((e) => {
|
94 | if (e.stderr) {
|
95 | if (e.stderr.includes(`Can't find schema.prisma`)) {
|
96 | console.error(
|
97 | `${c.yellow('warning')} @prisma/client needs a ${c.bold(
|
98 | 'schema.prisma',
|
99 | )} to function, but couldn't find it.
|
100 | Please either create one manually or use ${c.bold('prisma init')}.
|
101 | Once you created it, run ${c.bold('prisma generate')}.
|
102 | To keep Prisma related things separate, we recommend creating it in a subfolder called ${c.underline(
|
103 | './prisma',
|
104 | )} like so: ${c.underline('./prisma/schema.prisma')}\n`,
|
105 | )
|
106 | } else {
|
107 | console.error(e.stderr)
|
108 | }
|
109 | } else {
|
110 | console.error(e)
|
111 | }
|
112 | process.exit(0)
|
113 | })
|
114 | }
|
115 |
|
116 | function run(cmd, params) {
|
117 | const child = childProcess.spawn(cmd, params, {
|
118 | stdio: ['pipe', 'inherit', 'inherit'],
|
119 | })
|
120 |
|
121 | return new Promise((resolve, reject) => {
|
122 | child.on('close', () => {
|
123 | resolve()
|
124 | })
|
125 | child.on('exit', (code) => {
|
126 | if (code === 0) {
|
127 | resolve()
|
128 | } else {
|
129 | reject(code)
|
130 | }
|
131 | })
|
132 | child.on('error', () => {
|
133 | reject()
|
134 | })
|
135 | })
|
136 | }
|
137 |
|
138 | async function ensureEmptyDotPrisma() {
|
139 | try {
|
140 | const dotPrismaClientDir = path.join(__dirname, '../../../.prisma/client')
|
141 | await makeDir(dotPrismaClientDir)
|
142 | const defaultIndexJsPath = path.join(dotPrismaClientDir, 'index.js')
|
143 | const defaultIndexDTSPath = path.join(dotPrismaClientDir, 'index.d.ts')
|
144 |
|
145 | if (!fs.existsSync(defaultIndexJsPath)) {
|
146 | await copyFile(
|
147 | path.join(__dirname, 'default-index.js'),
|
148 | defaultIndexJsPath,
|
149 | )
|
150 | }
|
151 |
|
152 | if (!fs.existsSync(defaultIndexDTSPath)) {
|
153 | await copyFile(
|
154 | path.join(__dirname, 'default-index.d.ts'),
|
155 | defaultIndexDTSPath,
|
156 | )
|
157 | }
|
158 | } catch (e) {
|
159 | console.error(e)
|
160 | }
|
161 | }
|
162 |
|
163 | async function makeDir(input) {
|
164 | const make = async (pth) => {
|
165 | try {
|
166 | await mkdir(pth)
|
167 |
|
168 | return pth
|
169 | } catch (error) {
|
170 | if (error.code === 'EPERM') {
|
171 | throw error
|
172 | }
|
173 |
|
174 | if (error.code === 'ENOENT') {
|
175 | if (path.dirname(pth) === pth) {
|
176 | throw permissionError(pth)
|
177 | }
|
178 |
|
179 | if (error.message.includes('null bytes')) {
|
180 | throw error
|
181 | }
|
182 |
|
183 | await make(path.dirname(pth))
|
184 |
|
185 | return make(pth)
|
186 | }
|
187 |
|
188 | try {
|
189 | const stats = await stat(pth)
|
190 | if (!stats.isDirectory()) {
|
191 | throw new Error('The path is not a directory')
|
192 | }
|
193 | } catch (_) {
|
194 | throw error
|
195 | }
|
196 |
|
197 | return pth
|
198 | }
|
199 | }
|
200 |
|
201 | return make(path.resolve(input))
|
202 | }
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | function getPostInstallTrigger() {
|
210 | |
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 | const maybe_npm_config_argv_string = process.env.npm_config_argv
|
235 |
|
236 | if (maybe_npm_config_argv_string === undefined) {
|
237 | return UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING
|
238 | }
|
239 |
|
240 | let npm_config_argv
|
241 | try {
|
242 | npm_config_argv = JSON.parse(maybe_npm_config_argv_string)
|
243 | } catch (e) {
|
244 | return `${UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR}: ${maybe_npm_config_argv_string}`
|
245 | }
|
246 |
|
247 | if (typeof npm_config_argv !== 'object' || npm_config_argv === null) {
|
248 | return `${UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR}: ${maybe_npm_config_argv_string}`
|
249 | }
|
250 |
|
251 | const npm_config_arv_original_arr = npm_config_argv.original
|
252 |
|
253 | if (!Array.isArray(npm_config_arv_original_arr)) {
|
254 | return `${UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR}: ${maybe_npm_config_argv_string}`
|
255 | }
|
256 |
|
257 | const npm_config_arv_original = npm_config_arv_original_arr
|
258 | .filter((arg) => arg !== '')
|
259 | .join(' ')
|
260 |
|
261 | const command =
|
262 | npm_config_arv_original === ''
|
263 | ? getPackageManagerName()
|
264 | : [getPackageManagerName(), npm_config_arv_original].join(' ')
|
265 |
|
266 | return command
|
267 | }
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | function doubleQuote(x) {
|
273 | return `"${x}"`
|
274 | }
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 | function getPackageManagerName() {
|
281 | const userAgent = process.env.npm_config_user_agent
|
282 | if (!userAgent) return 'MISSING_NPM_CONFIG_USER_AGENT'
|
283 |
|
284 | const name = parsePackageManagerName(userAgent)
|
285 | if (!name) return `UNKNOWN_NPM_CONFIG_USER_AGENT(${userAgent})`
|
286 |
|
287 | return name
|
288 | }
|
289 |
|
290 |
|
291 |
|
292 |
|
293 | function parsePackageManagerName(userAgent) {
|
294 | let packageManager = null
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 | if (userAgent) {
|
301 | const matchResult = userAgent.match(/^([^\/]+)\/.+/)
|
302 | if (matchResult) {
|
303 | packageManager = matchResult[1].trim()
|
304 | }
|
305 | }
|
306 |
|
307 | return packageManager
|
308 | }
|
309 |
|
310 |
|
311 | const UNABLE_TO_FIND_POSTINSTALL_TRIGGER__EMPTY_STRING = 'UNABLE_TO_FIND_POSTINSTALL_TRIGGER__EMPTY_STRING'
|
312 |
|
313 | const UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING = 'UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING'
|
314 |
|
315 | const UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR = 'UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR'
|
316 |
|
317 | const UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR = 'UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR'
|
318 |
|
319 |
|
320 |
|
321 | exports.UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING = UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING
|
322 | exports.UNABLE_TO_FIND_POSTINSTALL_TRIGGER__EMPTY_STRING = UNABLE_TO_FIND_POSTINSTALL_TRIGGER__EMPTY_STRING
|
323 | exports.UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR = UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR
|
324 | exports.UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR = UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR
|
325 | exports.getPostInstallTrigger = getPostInstallTrigger
|