Make packages/scripts work
This commit is contained in:
parent
166981fe3b
commit
33c401dbcb
41
packages/scripts/src/Subprocess.test.ts
Normal file
41
packages/scripts/src/Subprocess.test.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import {StdioOptions} from './Subprocess'
|
||||||
|
import {Subprocess} from './Subprocess'
|
||||||
|
|
||||||
|
describe('Subprocess', () => {
|
||||||
|
|
||||||
|
describe('constructor', () => {
|
||||||
|
it('sets stdio to inherit when log true', () => {
|
||||||
|
const p = new Subprocess('test', [], {})
|
||||||
|
expect(p.stdio).toEqual('pipe')
|
||||||
|
})
|
||||||
|
it('sets stdio to ignore when log false', () => {
|
||||||
|
const p = new Subprocess('test', [], {}, StdioOptions.IGNORE)
|
||||||
|
expect(p.stdio).toEqual('ignore')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('run', () => {
|
||||||
|
|
||||||
|
// it('rejects on error', async () => {
|
||||||
|
// const error = await getError(
|
||||||
|
// new Subprocess('exit 1', environment, StdioOptions.IGNORE).run())
|
||||||
|
// expect(error.message).toMatch(/exited with code 1/)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// it('logs errors', async () => {
|
||||||
|
// await getError(
|
||||||
|
// new Subprocess(
|
||||||
|
// 'invalid-non-existing-command',
|
||||||
|
// environment, StdioOptions.PIPE,
|
||||||
|
// )
|
||||||
|
// .run(),
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
|
||||||
|
it('resolves on successful invocation', async () => {
|
||||||
|
await new Subprocess('ls', [], {}, StdioOptions.IGNORE).run()
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
42
packages/scripts/src/Subprocess.ts
Normal file
42
packages/scripts/src/Subprocess.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import {spawn} from 'child_process'
|
||||||
|
|
||||||
|
export enum StdioOptions {
|
||||||
|
PIPE = 'pipe',
|
||||||
|
INHERIT = 'inherit',
|
||||||
|
IGNORE = 'ignore',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Subprocess {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly command: string,
|
||||||
|
public readonly args: readonly string[],
|
||||||
|
public readonly environment: Record<string, string | undefined>,
|
||||||
|
public readonly stdio: StdioOptions = StdioOptions.PIPE,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async run() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
process.stderr.write(`> ${this.command} ${this.args.join(' ')}\n`)
|
||||||
|
const subprocess = spawn(this.command, this.args, {
|
||||||
|
shell: false,
|
||||||
|
stdio: this.stdio,
|
||||||
|
env: this.environment,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.stdio === StdioOptions.PIPE) {
|
||||||
|
subprocess.stdout.on('data', data => process.stdout.write(data))
|
||||||
|
subprocess.stderr.on('data', data => process.stderr.write(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
subprocess.on('close', code => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
reject(new Error(`"${this.command}" exited with code ${code}`))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
subprocess.on('error', reject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,5 @@
|
|||||||
import * as childProcess from 'child_process'
|
import {run} from '../run'
|
||||||
|
|
||||||
export async function build(path: string) {
|
export async function build(path: string) {
|
||||||
// TODO fix this
|
await run('ttsc', ['--build', path])
|
||||||
await childProcess.spawn('npx', ['ttsc', '--build', path], {
|
|
||||||
stdio: 'inherit',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './help'
|
export * from './help'
|
||||||
export * from './build'
|
export * from './build'
|
||||||
|
export * from './watch'
|
||||||
|
|||||||
5
packages/scripts/src/commands/watch.ts
Normal file
5
packages/scripts/src/commands/watch.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import {run} from '../run'
|
||||||
|
|
||||||
|
export async function watch(path: string) {
|
||||||
|
await run('ttsc', ['--build', '--watch', '--preserveWatchOutput', path])
|
||||||
|
}
|
||||||
@ -5,7 +5,10 @@ import {TCommand} from './TCommand'
|
|||||||
async function run(...argv: string[]) {
|
async function run(...argv: string[]) {
|
||||||
const commandName = argv[0] || 'help'
|
const commandName = argv[0] || 'help'
|
||||||
if (!(commandName in commands)) {
|
if (!(commandName in commands)) {
|
||||||
throw new Error('Command not found:' + commandName)
|
const c = Object.keys(commands).filter(cmd => !cmd.startsWith('_'))
|
||||||
|
console.log(
|
||||||
|
`Available commands:\n\n${c.join('\n')}`)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
const command = (commands as any)[commandName] as TCommand
|
const command = (commands as any)[commandName] as TCommand
|
||||||
await command(...argv.slice(1))
|
await command(...argv.slice(1))
|
||||||
@ -13,4 +16,8 @@ async function run(...argv: string[]) {
|
|||||||
|
|
||||||
if (typeof require !== 'undefined' && require.main === module) {
|
if (typeof require !== 'undefined' && require.main === module) {
|
||||||
run(...process.argv.slice(2))
|
run(...process.argv.slice(2))
|
||||||
|
.catch(err => {
|
||||||
|
console.log('> ' + err.message)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
48
packages/scripts/src/modules.test.ts
Normal file
48
packages/scripts/src/modules.test.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {getPathVariable, getPathSeparator, findNodeModules} from './modules'
|
||||||
|
import {resolve} from 'path'
|
||||||
|
import {platform} from 'os'
|
||||||
|
|
||||||
|
describe('modules', () => {
|
||||||
|
|
||||||
|
describe('getPathSeparator', () => {
|
||||||
|
it('returns ";" when win32', () => {
|
||||||
|
expect(getPathSeparator('win32')).toEqual(';')
|
||||||
|
})
|
||||||
|
it('returns ":" otherwise', () => {
|
||||||
|
expect(getPathSeparator('linux')).toEqual(':')
|
||||||
|
expect(getPathSeparator('darwin')).toEqual(':')
|
||||||
|
expect(getPathSeparator('mac')).toEqual(':')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('findNodeModules', () => {
|
||||||
|
it('should find node_modules/.bin dirs in parent path(s)', () => {
|
||||||
|
const dirs = findNodeModules()
|
||||||
|
expect(dirs.length).toBeGreaterThanOrEqual(1)
|
||||||
|
})
|
||||||
|
it('should not fail when path does not exist', () => {
|
||||||
|
const dirs = findNodeModules('/non/existing/path/bla/123')
|
||||||
|
expect(dirs).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('addToPath', () => {
|
||||||
|
it('does nothing when pathsToAdd is empty', () => {
|
||||||
|
const paths = getPathVariable([])
|
||||||
|
expect(paths).toEqual(process.env.PATH)
|
||||||
|
})
|
||||||
|
it('adds paths to path variable', () => {
|
||||||
|
const separator = getPathSeparator(platform())
|
||||||
|
const paths = getPathVariable(['/a', '/b'], '/c')
|
||||||
|
expect(paths).toEqual(`/a${separator}/b${separator}/c`)
|
||||||
|
})
|
||||||
|
it('adds node modules paths to path variable by default', () => {
|
||||||
|
const paths = findNodeModules()
|
||||||
|
const separator = getPathSeparator(platform())
|
||||||
|
expect(paths.length).toBeGreaterThanOrEqual(1)
|
||||||
|
expect(getPathVariable())
|
||||||
|
.toEqual(`${paths.join(separator)}${separator}${process.env.PATH}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
36
packages/scripts/src/modules.ts
Normal file
36
packages/scripts/src/modules.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import * as fs from 'fs'
|
||||||
|
import * as path from 'path'
|
||||||
|
import {platform} from 'os'
|
||||||
|
|
||||||
|
export function getPathSeparator(platformValue: string) {
|
||||||
|
return platformValue === 'win32' ? ';' : ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findNodeModules(dir: string = process.cwd()): string[] {
|
||||||
|
let lastPath = ''
|
||||||
|
const paths = []
|
||||||
|
dir = path.resolve(dir)
|
||||||
|
while (dir !== lastPath) {
|
||||||
|
const nodeModulesDir = path.join(dir, 'node_modules', '.bin')
|
||||||
|
if (
|
||||||
|
fs.existsSync(nodeModulesDir)
|
||||||
|
&& fs.statSync(nodeModulesDir).isDirectory()
|
||||||
|
) {
|
||||||
|
paths.push(nodeModulesDir)
|
||||||
|
}
|
||||||
|
lastPath = dir
|
||||||
|
dir = path.resolve(dir, '..')
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPathVariable(
|
||||||
|
pathsToAdd: string[] = findNodeModules(),
|
||||||
|
currentPath = process.env.PATH,
|
||||||
|
) {
|
||||||
|
if (!pathsToAdd.length) {
|
||||||
|
return currentPath
|
||||||
|
}
|
||||||
|
const separator = getPathSeparator(platform())
|
||||||
|
return `${pathsToAdd.join(separator)}${separator}${currentPath}`
|
||||||
|
}
|
||||||
10
packages/scripts/src/run.ts
Normal file
10
packages/scripts/src/run.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import {Subprocess} from './Subprocess'
|
||||||
|
import {getPathVariable} from './modules'
|
||||||
|
|
||||||
|
export async function run(command: string, args: string[]) {
|
||||||
|
return new Subprocess(command, args, {
|
||||||
|
...process.env,
|
||||||
|
PATH: getPathVariable(),
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user