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', [localPath, 'generate', '--postinstall'])
|
27 | return
|
28 | }
|
29 |
|
30 | if (installedGlobally) {
|
31 | await run('prisma', ['generate', '--postinstall'])
|
32 | return
|
33 | }
|
34 | } catch (e) {
|
35 |
|
36 | if (e && e !== 1) {
|
37 | console.error(e)
|
38 | }
|
39 | }
|
40 |
|
41 | if (!localPath && !installedGlobally) {
|
42 | console.error(
|
43 | `${c.yellow(
|
44 | 'warning',
|
45 | )} In order to use "@prisma/client", please install @prisma/cli. You can install it with "npm add -D @prisma/cli".`,
|
46 | )
|
47 | }
|
48 | }
|
49 |
|
50 | function getLocalPackagePath() {
|
51 | let packagePath
|
52 | try {
|
53 | packagePath = require.resolve('@prisma/cli/package.json')
|
54 | } catch (e) {
|
55 | return null
|
56 | }
|
57 |
|
58 | if (packagePath) {
|
59 | return require.resolve('@prisma/cli')
|
60 | }
|
61 |
|
62 | return null
|
63 | }
|
64 |
|
65 | async function isInstalledGlobally() {
|
66 | try {
|
67 | const result = await exec('prisma -v')
|
68 | if (result.stdout.includes('@prisma/cli')) {
|
69 | return true
|
70 | } else {
|
71 | console.error(`${c.yellow('warning')} You still have the ${c.bold(
|
72 | 'prisma',
|
73 | )} cli (Prisma 1) installed globally.
|
74 | Please uninstall it with either ${c.green('npm remove -g prisma')} or ${c.green(
|
75 | 'yarn global remove prisma',
|
76 | )}.`)
|
77 | }
|
78 | } catch (e) {
|
79 | return false
|
80 | }
|
81 | }
|
82 |
|
83 | if (!process.env.SKIP_GENERATE) {
|
84 | main().catch((e) => {
|
85 | if (e.stderr) {
|
86 | if (e.stderr.includes(`Can't find schema.prisma`)) {
|
87 | console.error(
|
88 | `${c.yellow('warning')} @prisma/client needs a ${c.bold(
|
89 | 'schema.prisma',
|
90 | )} to function, but couldn't find it.
|
91 | Please either create one manually or use ${c.bold('prisma init')}.
|
92 | Once you created it, run ${c.bold('prisma generate')}.
|
93 | To keep Prisma related things separate, we recommend creating it in a subfolder called ${c.underline(
|
94 | './prisma',
|
95 | )} like so: ${c.underline('./prisma/schema.prisma')}\n`,
|
96 | )
|
97 | } else {
|
98 | console.error(e.stderr)
|
99 | }
|
100 | } else {
|
101 | console.error(e)
|
102 | }
|
103 | process.exit(0)
|
104 | })
|
105 | }
|
106 |
|
107 | function run(cmd, params) {
|
108 | const child = childProcess.spawn(cmd, params, {
|
109 | stdio: ['pipe', 'inherit', 'inherit'],
|
110 | })
|
111 |
|
112 | return new Promise((resolve, reject) => {
|
113 | child.on('close', () => {
|
114 | resolve()
|
115 | })
|
116 | child.on('exit', (code) => {
|
117 | if (code === 0) {
|
118 | resolve()
|
119 | } else {
|
120 | reject(code)
|
121 | }
|
122 | })
|
123 | child.on('error', () => {
|
124 | reject()
|
125 | })
|
126 | })
|
127 | }
|
128 |
|
129 | async function ensureEmptyDotPrisma() {
|
130 | try {
|
131 | const dotPrismaClientDir = path.join(__dirname, '../../../.prisma/client')
|
132 | await makeDir(dotPrismaClientDir)
|
133 | const defaultIndexJsPath = path.join(dotPrismaClientDir, 'index.js')
|
134 | const defaultIndexDTSPath = path.join(dotPrismaClientDir, 'index.d.ts')
|
135 |
|
136 | if (!fs.existsSync(defaultIndexJsPath)) {
|
137 | await copyFile(
|
138 | path.join(__dirname, 'default-index.js'),
|
139 | defaultIndexJsPath,
|
140 | )
|
141 | }
|
142 |
|
143 | if (!fs.existsSync(defaultIndexDTSPath)) {
|
144 | await copyFile(
|
145 | path.join(__dirname, 'default-index.d.ts'),
|
146 | defaultIndexDTSPath,
|
147 | )
|
148 | }
|
149 | } catch (e) {
|
150 | console.error(e)
|
151 | }
|
152 | }
|
153 |
|
154 | async function makeDir(input) {
|
155 | const make = async (pth) => {
|
156 | try {
|
157 | await mkdir(pth)
|
158 |
|
159 | return pth
|
160 | } catch (error) {
|
161 | if (error.code === 'EPERM') {
|
162 | throw error
|
163 | }
|
164 |
|
165 | if (error.code === 'ENOENT') {
|
166 | if (path.dirname(pth) === pth) {
|
167 | throw permissionError(pth)
|
168 | }
|
169 |
|
170 | if (error.message.includes('null bytes')) {
|
171 | throw error
|
172 | }
|
173 |
|
174 | await make(path.dirname(pth))
|
175 |
|
176 | return make(pth)
|
177 | }
|
178 |
|
179 | try {
|
180 | const stats = await stat(pth)
|
181 | if (!stats.isDirectory()) {
|
182 | throw new Error('The path is not a directory')
|
183 | }
|
184 | } catch (_) {
|
185 | throw error
|
186 | }
|
187 |
|
188 | return pth
|
189 | }
|
190 | }
|
191 |
|
192 | return make(path.resolve(input))
|
193 | }
|