UNPKG

4.66 kBJavaScriptView Raw
1const childProcess = require('child_process')
2const { promisify } = require('util')
3const fs = require('fs')
4const path = require('path')
5const c = require('./colors')
6
7const exec = promisify(childProcess.exec)
8const copyFile = promisify(fs.copyFile)
9const mkdir = promisify(fs.mkdir)
10const stat = promisify(fs.stat)
11
12async function main() {
13 if (process.env.INIT_CWD) {
14 process.chdir(process.env.INIT_CWD) // necessary, because npm chooses __dirname as process.cwd()
15 // in the postinstall hook
16 }
17 await ensureEmptyDotPrisma()
18
19 const localPath = getLocalPackagePath()
20 // Only execute if !localpath
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 // if exit code = 1 do not print
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
50function 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
65async 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.
74Please 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
83if (!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
107function 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
129async 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
154async 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}