-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
236 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { spawn } from 'child_process'; | ||
import path from 'path'; | ||
import * as readline from 'readline'; | ||
import { Writable } from 'stream'; | ||
|
||
import { Flags } from '@oclif/core'; | ||
import chalk from 'chalk'; | ||
import dotenv from 'dotenv'; | ||
|
||
import { CliCommand } from '../command'; | ||
import { loadManifestFile } from '../manifest/loadManifestFile'; | ||
|
||
function runProcess( | ||
{ cwd, output }: { cwd: string; output: Writable }, | ||
{ name, cmd, env }: { name: string; cmd: string[]; env: Record<string, string> }, | ||
) { | ||
const [command, ...args] = cmd; | ||
const { PROCESSOR_PROMETHEUS_PORT, ...childEnv } = process.env; | ||
|
||
const child = spawn(command, args, { | ||
env: { | ||
...childEnv, | ||
...env, | ||
FORCE_PRETTY_LOGGER: 'true', | ||
}, | ||
cwd, | ||
}); | ||
|
||
const prefix = chalk.magenta(`[${name}] `); | ||
|
||
readline | ||
.createInterface({ | ||
input: child.stderr, | ||
}) | ||
.on('line', (line) => { | ||
output.write(`${prefix}${line}\n`); | ||
}); | ||
readline | ||
.createInterface({ | ||
input: child.stdout, | ||
}) | ||
.on('line', (line) => { | ||
output.write(`${prefix}${line}\n`); | ||
}); | ||
|
||
return child; | ||
} | ||
|
||
function isSkipped({ include, exclude }: { include?: string[]; exclude?: string[] }, haystack: string) { | ||
if (exclude?.length && exclude.includes(haystack)) return true; | ||
else if (include?.length && !include.includes(haystack)) return true; | ||
|
||
return false; | ||
} | ||
|
||
export default class Run extends CliCommand { | ||
static description = 'Run a squid'; | ||
|
||
static flags = { | ||
manifest: Flags.string({ | ||
char: 'm', | ||
description: 'Relative path to a squid manifest file in squid source', | ||
required: false, | ||
default: 'squid.yaml', | ||
}), | ||
envFile: Flags.string({ | ||
char: 'f', | ||
description: 'Relative path to an additional environment file in squid source', | ||
required: false, | ||
default: '.env', | ||
}), | ||
exclude: Flags.string({ | ||
char: 'e', | ||
description: 'Do not run specified services', | ||
required: false, | ||
multiple: true, | ||
}), | ||
include: Flags.string({ | ||
char: 'i', | ||
description: 'Run only specified services', | ||
required: false, | ||
multiple: true, | ||
exclusive: ['exclude'], | ||
}), | ||
}; | ||
|
||
static args = [ | ||
{ | ||
name: 'path', | ||
required: true, | ||
hidden: true, | ||
default: '.', | ||
}, | ||
]; | ||
|
||
async run(): Promise<void> { | ||
const { | ||
flags: { manifest: manifestPath, envFile, exclude, include }, | ||
args: { path: squidPath }, | ||
} = await this.parse(Run); | ||
|
||
try { | ||
const { squidDir, manifest } = loadManifestFile(squidPath, manifestPath); | ||
const runner = { cwd: squidDir, output: process.stdout }; | ||
|
||
if (envFile) { | ||
const { error } = dotenv.config({ | ||
path: path.join(squidDir, '/', envFile), | ||
}); | ||
if (error) { | ||
this.error(error); | ||
} | ||
} | ||
|
||
if (manifest.deploy?.api && !isSkipped({ include, exclude }, 'api')) { | ||
runProcess(runner, { | ||
name: 'api', | ||
...manifest.deploy.api, | ||
}); | ||
} | ||
|
||
if (manifest.deploy?.processor) { | ||
for (const processor of manifest.deploy?.processor) { | ||
if (isSkipped({ include, exclude }, processor.name)) { | ||
continue; | ||
} | ||
|
||
runProcess(runner, processor); | ||
} | ||
} | ||
} catch (e: any) { | ||
this.error(e.message); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
|
||
import chalk from 'chalk'; | ||
import yaml from 'js-yaml'; | ||
|
||
import { Manifest } from './manifest'; | ||
|
||
export function loadManifestFile(localPath: string, manifestPath: string): { squidDir: string; manifest: Manifest } { | ||
const squidDir = path.resolve(localPath); | ||
|
||
if (!fs.statSync(squidDir).isDirectory()) { | ||
throw new Error(`The path ${squidDir} is a not a squid directory. Please provide a path to a squid root directory`); | ||
} | ||
|
||
const manifestFullPath = path.resolve(path.join(localPath, manifestPath)); | ||
if (fs.statSync(manifestFullPath).isDirectory()) { | ||
throw new Error( | ||
`The path ${manifestFullPath} is a directory, not a manifest file. Please provide a path to a valid manifest file inside squid directory`, | ||
); | ||
} | ||
|
||
let manifestValue; | ||
try { | ||
manifestValue = yaml.load(fs.readFileSync(manifestFullPath).toString()) as Manifest; | ||
} catch (e: any) { | ||
throw new Error(`The manifest file on ${manifestFullPath} can not be parsed: ${e.message}`); | ||
} | ||
|
||
if (!manifestValue.name) { | ||
throw new Error(`A Squid ${chalk.bold('name')} must be specified in the manifest`); | ||
} else if (manifestValue.version < 1) { | ||
throw new Error(`A Squid ${chalk.bold('version')} must be greater than 0`); | ||
} else if (!manifestValue.version) { | ||
throw new Error(`A Squid ${chalk.bold('version')} must be specified in the manifest`); | ||
} | ||
|
||
return { | ||
squidDir, | ||
manifest: manifestValue, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,56 @@ | ||
import fs from 'fs'; | ||
|
||
import yaml from 'js-yaml'; | ||
import { isPlainObject } from 'lodash'; | ||
|
||
export type Manifest = { | ||
type ManifestApi = { | ||
cmd: string[]; | ||
env: Record<string, string>; | ||
}; | ||
|
||
type ManifestProcessor = { | ||
name: string; | ||
cmd: string[]; | ||
env: Record<string, string>; | ||
}; | ||
|
||
export interface RawManifest { | ||
name: string; | ||
version: number; | ||
build: null; | ||
}; | ||
deploy?: { | ||
processor?: ManifestProcessor | ManifestProcessor[]; | ||
api?: ManifestApi; | ||
}; | ||
} | ||
|
||
export interface Manifest extends RawManifest { | ||
deploy?: { | ||
api?: ManifestApi; | ||
processor?: ManifestProcessor[]; | ||
}; | ||
} | ||
|
||
export function readManifest(path: string, transform = true) { | ||
const manifest = yaml.load(fs.readFileSync(path).toString()) as RawManifest; | ||
|
||
if (transform) { | ||
if (manifest.deploy?.processor && isPlainObject(manifest.deploy.processor)) { | ||
manifest.deploy.processor = [manifest.deploy.processor as ManifestProcessor]; | ||
} | ||
} | ||
|
||
export function readManifest(path: string) { | ||
return yaml.load(fs.readFileSync(path).toString()) as Manifest; | ||
return manifest; | ||
} | ||
|
||
export function formatManifest(manifest: Manifest): string { | ||
export function formatManifest(manifest: RawManifest): string { | ||
return yaml.dump(manifest, { | ||
styles: { | ||
'tag:yaml.org,2002:null': 'empty', | ||
}, | ||
}); | ||
} | ||
|
||
export function saveManifest(path: string, manifest: Manifest) { | ||
export function saveManifest(path: string, manifest: RawManifest) { | ||
fs.writeFileSync(path, formatManifest(manifest)); | ||
} |