Skip to content

Commit

Permalink
perf: got rid of all synchronous subprocess and filesystem calls
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed Jun 3, 2018
1 parent ce741f6 commit 9b62424
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 78 deletions.
14 changes: 5 additions & 9 deletions src/build-dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
import {
emptyDir,
ensureDir,
ensureDirSync,
} from "fs-extra"
import * as Rsync from "rsync"
import { GARDEN_DIR_NAME } from "./constants"
Expand All @@ -34,15 +33,12 @@ import { zip } from "lodash"
const buildDirRelPath = join(GARDEN_DIR_NAME, "build")

export class BuildDir {
buildDirPath: string
constructor(private projectRoot: string, public buildDirPath: string) { }

constructor(private projectRoot: string) {
this.buildDirPath = join(projectRoot, buildDirRelPath)
}

// Synchronous, so it can run in Garden's constructor.
init() {
ensureDirSync(this.buildDirPath)
static async factory(projectRoot: string) {
const buildDirPath = join(projectRoot, buildDirRelPath)
await ensureDir(buildDirPath)
return new BuildDir(projectRoot, buildDirPath)
}

async syncFromSrc(module: Module) {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import * as execa from "execa"
import { PluginContext } from "../plugin-context"
import { BuildTask } from "../tasks/build"
import { Task } from "../types/task"
Expand All @@ -15,7 +16,6 @@ import {
} from "./base"
import { join } from "path"
import { STATIC_DIR } from "../constants"
import { spawnSync } from "child_process"
import chalk from "chalk"
import moment = require("moment")

Expand All @@ -39,7 +39,7 @@ export class DevCommand extends Command {

async action(ctx: PluginContext): Promise<CommandResult> {
try {
spawnSync(imgcatPath, [bannerPath], {
await execa(imgcatPath, [bannerPath], {
stdio: "inherit",
})
} catch (_) {
Expand Down
18 changes: 10 additions & 8 deletions src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ export interface ContextOpts {
}

export class Garden {
public buildDir: BuildDir
public readonly log: RootLogNode
public readonly actionHandlers: PluginActionMap
public readonly moduleActionHandlers: ModuleActionMap
Expand All @@ -158,13 +157,13 @@ export class Garden {
private readonly namespace: string,
public readonly config: EnvironmentConfig,
public readonly localConfigStore: LocalConfigStore,
public readonly buildDir: BuildDir,
logger?: RootLogNode,
) {
this.modulesScanned = false
this.log = logger || getLogger()
// TODO: Support other VCS options.
this.vcs = new GitHandler(this.projectRoot)
this.buildDir = new BuildDir(this.projectRoot)

this.modules = {}
this.services = {}
Expand All @@ -173,8 +172,6 @@ export class Garden {
this.actionHandlers = <PluginActionMap>fromPairs(pluginActionNames.map(n => [n, {}]))
this.moduleActionHandlers = <ModuleActionMap>fromPairs(moduleActionNames.map(n => [n, {}]))

this.buildDir.init()

this.config = config

this.configKeyNamespaces = ["project"]
Expand Down Expand Up @@ -259,11 +256,16 @@ export class Garden {
variables: merge({}, globalConfig.variables, envConfig.variables),
}

const buildDir = await BuildDir.factory(projectRoot)

const garden = new Garden(
projectRoot, projectName,
environment, namespace,
projectRoot,
projectName,
environment,
namespace,
projectEnvConfig,
localConfigStore,
buildDir,
logger,
)

Expand Down Expand Up @@ -381,7 +383,7 @@ export class Garden {
let plugin

try {
plugin = factory({
plugin = await factory({
config,
logEntry: this.log,
})
Expand Down Expand Up @@ -585,7 +587,7 @@ export class Garden {
Scans the project root for modules and adds them to the context.
*/
async scanModules() {
const ignorer = getIgnorer(this.projectRoot)
const ignorer = await getIgnorer(this.projectRoot)
const scanOpts = {
filter: (path) => {
const relPath = relative(this.projectRoot, path)
Expand Down
15 changes: 7 additions & 8 deletions src/plugins/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
PrimitiveMap,
joiPrimitive,
} from "../types/common"
import { existsSync } from "fs"
import { pathExists } from "fs-extra"
import { join } from "path"
import { ConfigurationError } from "../exceptions"
import {
Expand Down Expand Up @@ -218,7 +218,7 @@ export async function getImage(module: ContainerModule) {

export const helpers = {
async getLocalImageId(module: ContainerModule) {
if (helpers.hasDockerfile(module)) {
if (await helpers.hasDockerfile(module)) {
const { versionString } = await module.getVersion()
return `${module.name}:${versionString}`
} else {
Expand Down Expand Up @@ -263,8 +263,8 @@ export const helpers = {
return childProcess.exec("docker " + args, { cwd: await module.getBuildPath(), maxBuffer: 1024 * 1024 })
},

hasDockerfile(module: ContainerModule) {
return existsSync(join(module.path, "Dockerfile"))
async hasDockerfile(module: ContainerModule) {
return pathExists(join(module.path, "Dockerfile"))
},
}

Expand Down Expand Up @@ -330,7 +330,7 @@ export async function parseContainerModule({ ctx, moduleConfig }: ParseModulePar
const module = new ContainerModule(ctx, moduleConfig, services, tests)

// make sure we can build the thing
if (!(await getImage(module)) && !helpers.hasDockerfile(module)) {
if (!(await getImage(module)) && !(await helpers.hasDockerfile(module))) {
throw new ConfigurationError(
`Module ${moduleConfig.name} neither specifies image nor provides Dockerfile`,
{},
Expand Down Expand Up @@ -366,10 +366,9 @@ export const gardenPlugin = (): GardenPlugin => ({

async buildModule({ ctx, module, logEntry }: BuildModuleParams<ContainerModule>) {
const buildPath = await module.getBuildPath()
const dockerfilePath = join(buildPath, "Dockerfile")
const image = await getImage(module)

if (!!image && !existsSync(dockerfilePath)) {
if (!!image && !(await helpers.hasDockerfile(module))) {
if (await helpers.imageExistsLocally(module)) {
return { fresh: false }
}
Expand All @@ -396,7 +395,7 @@ export const gardenPlugin = (): GardenPlugin => ({
},

async pushModule({ module, logEntry }: PushModuleParams<ContainerModule>) {
if (!helpers.hasDockerfile(module)) {
if (!(await helpers.hasDockerfile(module))) {
logEntry && logEntry.setState({ msg: `Nothing to push` })
return { pushed: false }
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/google/google-app-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const gardenPlugin = (): GardenPlugin => ({

// write app.yaml to build context
const appYamlPath = join(service.module.path, "app.yaml")
dumpYaml(appYamlPath, appYaml)
await dumpYaml(appYamlPath, appYaml)

// deploy to GAE
const project = getProject(service, provider)
Expand Down
22 changes: 11 additions & 11 deletions src/plugins/kubernetes/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { execSync } from "child_process"
import { readFileSync } from "fs"
import * as execa from "execa"
import { safeLoad } from "js-yaml"
import {
every,
Expand Down Expand Up @@ -39,6 +38,7 @@ import {
getSystemGarden,
isSystemGarden,
} from "./system"
import { readFile } from "fs-extra"

// TODO: split this into separate plugins to handle Docker for Mac and Minikube

Expand Down Expand Up @@ -116,16 +116,16 @@ async function configureLocalEnvironment(
return {}
}

function getKubeConfig(): any {
async function getKubeConfig(): Promise<any> {
try {
return safeLoad(readFileSync(kubeConfigPath).toString())
return safeLoad((await readFile(kubeConfigPath)).toString())
} catch {
return {}
}
}

function setMinikubeDockerEnv() {
const minikubeEnv = execSync("minikube docker-env --shell=bash").toString()
async function setMinikubeDockerEnv() {
const minikubeEnv = await execa.stdout("minikube docker-env --shell=bash")
for (const line of minikubeEnv.split("\n")) {
const matched = line.match(/^export (\w+)="(.+)"$/)
if (matched) {
Expand Down Expand Up @@ -154,7 +154,7 @@ const configSchema = providerConfigBase

export const name = "local-kubernetes"

export function gardenPlugin({ config, logEntry }): GardenPlugin {
export async function gardenPlugin({ config, logEntry }): Promise<GardenPlugin> {
config = validate(config, configSchema, { context: "kubernetes provider config" })

let context = config.context
Expand All @@ -164,7 +164,7 @@ export function gardenPlugin({ config, logEntry }): GardenPlugin {

if (!context) {
// automatically detect supported kubectl context if not explicitly configured
const kubeConfig = getKubeConfig()
const kubeConfig = await getKubeConfig()
const currentContext = kubeConfig["current-context"]

if (currentContext && supportedContexts.includes(currentContext)) {
Expand All @@ -190,13 +190,13 @@ export function gardenPlugin({ config, logEntry }): GardenPlugin {
}

if (context === "minikube") {
execSync("minikube addons enable ingress")
await execa("minikube addons enable ingress")

ingressHostname = config.ingressHostname

if (!ingressHostname) {
// use the nip.io service to give a hostname to the instance, if none is explicitly configured
const minikubeIp = execSync("minikube ip").toString().trim()
const minikubeIp = await execa.stdout("minikube ip")
ingressHostname = minikubeIp + ".nip.io"
}

Expand All @@ -205,7 +205,7 @@ export function gardenPlugin({ config, logEntry }): GardenPlugin {

// automatically set docker environment variables for minikube
// TODO: it would be better to explicitly provide those to docker instead of using process.env
setMinikubeDockerEnv()
await setMinikubeDockerEnv()
} else {
ingressHostname = config.ingressHostname || "local.app.garden"
ingressPort = 32000
Expand Down
8 changes: 4 additions & 4 deletions src/template-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { readFileSync } from "fs"
import { readFile } from "fs-extra"
import { resolve } from "path"
import Bluebird = require("bluebird")
import { isPrimitive, Primitive } from "./types/common"
Expand All @@ -27,15 +27,15 @@ class TemplateStringError extends GardenBaseError {

let _parser: any

function getParser() {
async function getParser() {
if (!_parser) {
try {
_parser = require("./template-string-parser")
} catch (_err) {
// fallback for when running with ts-node or mocha
const peg = require("pegjs")
const pegFilePath = resolve(__dirname, "template-string-parser.pegjs")
const grammar = readFileSync(pegFilePath)
const grammar = await readFile(pegFilePath)
_parser = peg.generate(grammar.toString(), { trace: false })
}
}
Expand All @@ -60,7 +60,7 @@ export interface TemplateOpts {
export async function resolveTemplateString(
string: string, context: TemplateStringContext, { ignoreMissingKeys = false }: TemplateOpts = {},
) {
const parser = getParser()
const parser = await getParser()
const parsed = parser.parse(string, {
getKey: genericResolver(context, ignoreMissingKeys),
// need this to allow nested template strings
Expand Down
4 changes: 2 additions & 2 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { joiIdentifier, validate } from "./common"
import { ConfigurationError } from "../exceptions"
import * as Joi from "joi"
import * as yaml from "js-yaml"
import { readFileSync } from "fs"
import { readFile } from "fs-extra"
import { defaultEnvironments, ProjectConfig, projectSchema } from "./project"
import { omit } from "lodash"

Expand Down Expand Up @@ -55,7 +55,7 @@ export async function loadConfig(projectRoot: string, path: string): Promise<Gar
let spec: any

try {
fileData = readFileSync(absPath)
fileData = await readFile(absPath)
} catch (err) {
throw new ConfigurationError(`Could not find ${CONFIG_FILENAME} in directory ${path}`, err)
}
Expand Down
10 changes: 5 additions & 5 deletions src/types/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

import * as Bluebird from "bluebird"
import {
existsSync,
readFileSync,
} from "fs"
pathExists,
readFile,
} from "fs-extra"
import * as Joi from "joi"
import {
flatten,
Expand Down Expand Up @@ -212,9 +212,9 @@ export class Module<
async getVersion(): Promise<TreeVersion> {
const versionFilePath = join(this.path, GARDEN_VERSIONFILE_NAME)

if (existsSync(versionFilePath)) {
if (await pathExists(versionFilePath)) {
// this is used internally to specify version outside of source control
const versionFileContents = readFileSync(versionFilePath).toString().trim()
const versionFileContents = await readFile(versionFilePath).toString().trim()

if (!!versionFileContents) {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/types/plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export interface GardenPlugin {
}

export interface PluginFactory {
({ config: object, logEntry: LogEntry }): GardenPlugin
({ config: object, logEntry: LogEntry }): GardenPlugin | Promise<GardenPlugin>
pluginName?: string
}
export type RegisterPluginParam = string | PluginFactory
Expand Down
Loading

0 comments on commit 9b62424

Please sign in to comment.