Skip to content

Commit

Permalink
fix: postinstall trigger in yarn workspace (prisma#5550)
Browse files Browse the repository at this point in the history
Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
  • Loading branch information
William Luke and Jolg42 authored Mar 2, 2021
1 parent d24e613 commit 465cd5d
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 26 deletions.
7 changes: 5 additions & 2 deletions src/packages/cli/src/Generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ export class Generate implements Command {
})

const isPostinstall = process.env.PRISMA_GENERATE_IN_POSTINSTALL

let cwd = process.cwd()
if(isPostinstall && isPostinstall !== 'true'){
cwd = isPostinstall
}
if (isError(args)) {
return this.help(args.message)
}
Expand All @@ -113,7 +116,7 @@ export class Generate implements Command {

const watchMode = args['--watch'] || false

const schemaPath = await getSchemaPath(args['--schema'])
const schemaPath = await getSchemaPath(args['--schema'], {cwd})
if (!schemaPath) {
if (isPostinstall) {
logger.warn(`The postinstall script automatically ran \`prisma generate\` and did not find your \`prisma/schema.prisma\`.
Expand Down
91 changes: 74 additions & 17 deletions src/packages/client/scripts/postinstall.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
const childProcess = require('child_process')
const { promisify } = require('util')
const fs = require('fs')
Expand All @@ -9,6 +10,45 @@ const copyFile = promisify(fs.copyFile)
const mkdir = promisify(fs.mkdir)
const stat = promisify(fs.stat)

function debug(message, ...optionalParams) {
if (process.env.DEBUG && process.env.DEBUG === 'prisma:postinstall') {
console.log(message, ...optionalParams)
}
}
/**
* Adds `package.json` to the end of a path if it doesn't already exist'
* @param {string} pth
*/
function addPackageJSON(pth){
if(pth.endsWith('package.json')) return pth
return path.join(pth, 'package.json')
}

/**
* Looks up for a `package.json` which is not `@prisma/cli` or `prisma` and returns the directory of the package
* @param {string} startPath - Path to Start At
* @param {number} limit - Find Up limit
* @returns {string | null}
*/
function findPackageRoot(startPath, limit = 10){
if(!startPath || !fs.existsSync(startPath)) return null
let currentPath = startPath
// Limit traversal
for(let i = 0; i < limit; i++){
const pkgPath = addPackageJSON(currentPath)
if(fs.existsSync(pkgPath)){
try {
const pkg = require(pkgPath)
if(pkg.name && !['@prisma/cli', 'prisma'].includes(pkg.name)){
return pkgPath.replace('package.json', '')
}
} catch {}
}
currentPath = path.join(currentPath, '../')
}
return null
}

async function main() {
if (process.env.INIT_CWD) {
process.chdir(process.env.INIT_CWD) // necessary, because npm chooses __dirname as process.cwd()
Expand All @@ -21,8 +61,20 @@ async function main() {
const installedGlobally = localPath ? undefined : await isInstalledGlobally()

// this is needed, so that the Generate command does not fail in postinstall

process.env.PRISMA_GENERATE_IN_POSTINSTALL = 'true'

// this is needed, so we can find the correct schemas in yarn workspace projects
const root = findPackageRoot(localPath)

process.env.PRISMA_GENERATE_IN_POSTINSTALL = root ? root : 'true'

debug({
localPath,
installedGlobally,
init_cwd: process.env.INIT_CWD,
PRISMA_GENERATE_IN_POSTINSTALL: process.env.PRISMA_GENERATE_IN_POSTINSTALL,
})
try {
if (localPath) {
await run('node', [
Expand All @@ -33,7 +85,6 @@ async function main() {
])
return
}

if (installedGlobally) {
await run('prisma', [
'generate',
Expand All @@ -47,6 +98,7 @@ async function main() {
if (e && e !== 1) {
console.error(e)
}
debug(e)
}

if (!localPath && !installedGlobally) {
Expand Down Expand Up @@ -97,32 +149,37 @@ Please uninstall it with either ${c.green('npm remove -g prisma')} or ${c.green(
}

if (!process.env.SKIP_GENERATE) {
main().catch((e) => {
if (e.stderr) {
if (e.stderr.includes(`Can't find schema.prisma`)) {
console.error(
`${c.yellow('warning')} @prisma/client needs a ${c.bold(
'schema.prisma',
)} to function, but couldn't find it.
main()
.catch((e) => {
if (e.stderr) {
if (e.stderr.includes(`Can't find schema.prisma`)) {
console.error(
`${c.yellow('warning')} @prisma/client needs a ${c.bold(
'schema.prisma',
)} to function, but couldn't find it.
Please either create one manually or use ${c.bold('prisma init')}.
Once you created it, run ${c.bold('prisma generate')}.
To keep Prisma related things separate, we recommend creating it in a subfolder called ${c.underline(
'./prisma',
)} like so: ${c.underline('./prisma/schema.prisma')}\n`,
)
)
} else {
console.error(e.stderr)
}
} else {
console.error(e.stderr)
console.error(e)
}
} else {
console.error(e)
}
process.exit(0)
})
process.exit(0)
})
.finally(() => {
debug(`postinstall trigger: ${getPostInstallTrigger()}`)
})
}

function run(cmd, params) {
function run(cmd, params, cwd = process.cwd()) {
const child = childProcess.spawn(cmd, params, {
stdio: ['pipe', 'inherit', 'inherit'],
cwd,
})

return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -190,7 +247,7 @@ async function makeDir(input) {

if (error.code === 'ENOENT') {
if (path.dirname(pth) === pth) {
throw permissionError(pth)
throw new Error(`operation not permitted, mkdir '${pth}'`)
}

if (error.message.includes('null bytes')) {
Expand Down
15 changes: 9 additions & 6 deletions src/packages/client/src/generation/generateClient.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import copy from '@timsuchanek/copy'
import {
BinaryPaths,
DataSource,
DMMF,
GeneratorConfig,
} from '@prisma/generator-helper'
import { getVersion } from '@prisma/sdk/dist/engineCommands'
import copy from '@timsuchanek/copy'
import chalk from 'chalk'
import fs from 'fs'
import makeDir from 'make-dir'
import path from 'path'
import chalk from 'chalk'
import pkgUp from 'pkg-up'
import { promisify } from 'util'
import { DMMF as PrismaClientDMMF } from '../runtime/dmmf-types'
import { Dictionary } from '../runtime/utils/common'
import { getPrismaClientDMMF } from './getDMMF'
import { resolveDatasources } from '../utils/resolveDatasources'
import { extractSqliteSources } from './extractSqliteSources'
import { TSClient, TS, JS } from './TSClient'
import { getVersion } from '@prisma/sdk/dist/engineCommands'
import pkgUp from 'pkg-up'
import { getPrismaClientDMMF } from './getDMMF'
import { JS, TS, TSClient } from './TSClient'
import { BrowserJS } from './TSClient/Generatable'

const remove = promisify(fs.unlink)
Expand Down Expand Up @@ -110,6 +110,9 @@ export async function buildClient({
}

async function getDotPrismaDir(outputDir: string): Promise<string> {
if (outputDir.endsWith('node_modules/@prisma/client')) {
return path.join(outputDir, '../../.prisma/client')
}
if (
process.env.INIT_CWD &&
process.env.npm_lifecycle_event === 'postinstall' &&
Expand Down
5 changes: 4 additions & 1 deletion src/packages/sdk/src/cli/getSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ const readFile = promisify(fs.readFile)

export async function getSchemaPath(
schemaPathFromArgs?: string,
opts: { cwd: string } = {
cwd: process.cwd(),
},
): Promise<string | null> {
return getSchemaPathInternal(schemaPathFromArgs, {
cwd: process.cwd(),
cwd: opts.cwd,
})
}

Expand Down

0 comments on commit 465cd5d

Please sign in to comment.