diff --git a/buildgraph/CoreBuildGraph.xml b/buildgraph/CoreBuildGraph.xml new file mode 100644 index 0000000..a7cbc1e --- /dev/null +++ b/buildgraph/CoreBuildGraph.xml @@ -0,0 +1,345 @@ + + + + + + \ No newline at end of file diff --git a/src/commands/buildgraph/run.ts b/src/commands/buildgraph/run.ts index 175d91c..d9ed87e 100644 --- a/src/commands/buildgraph/run.ts +++ b/src/commands/buildgraph/run.ts @@ -24,7 +24,7 @@ export const run = new Command() }) const project = await createProject(enginePath, projectPath) - const { success, code } = await project.runBuildGraph(buildGraphScript, buildGraphArgs) + const { success, code } = await project.runCustomBuildGraph(buildGraphScript, buildGraphArgs) if (!success) { const logs = await project.engine.getAutomationToolLogs(enginePath) @@ -36,6 +36,7 @@ export const run = new Command() await writeMarkdownReport(logs, options.buildgraphReportErrors) } - Deno.exit(code) + //Deno.exit(code) + Deno.exit(1) } }) diff --git a/src/commands/project/compile.ts b/src/commands/project/compile.ts index 2643c57..f31acac 100644 --- a/src/commands/project/compile.ts +++ b/src/commands/project/compile.ts @@ -17,6 +17,7 @@ export const compile = new Command() .option('-c, --configuration ', 'Configuration', { default: EngineConfiguration.Development, }) + .option('--buildgraph', 'Build Graph', { default: false }) .option('--dry-run', 'Dry run', { default: false }) .arguments('') .action(async (options, target = EngineTarget.Editor) => { @@ -25,7 +26,7 @@ export const compile = new Command() const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ cliOptions: options, }) - const project = await createProject(enginePath, projectPath) + const project = await createProject(enginePath, projectPath, options.buildgraph) await project.compile({ target: target as EngineTarget, configuration: configuration as EngineConfiguration, diff --git a/src/commands/project/editor.ts b/src/commands/project/editor.ts index dc57116..8ac674b 100644 --- a/src/commands/project/editor.ts +++ b/src/commands/project/editor.ts @@ -3,6 +3,7 @@ import { Command } from '@cliffy/command' import { createProject } from '../../lib/project.ts' import type { GlobalOptions } from '../../lib/types.ts' import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' export const editor = new Command() .description('Run the editor') @@ -25,8 +26,12 @@ export const editor = new Command() console.log(`Running editor with ${editorArguments}`) if (options.compile) { - await project.compileAndRunEditor({ extraRunArgs: editorArguments }) - } else { - await project.runEditor({ extraArgs: editorArguments }) + await project.compile({ + target: EngineTarget.Editor, + configuration: EngineConfiguration.Development, + dryRun: options.dryRun, + platform: EnginePlatform.Windows, + }) } + await project.runEditor({ extraArgs: editorArguments }) }) diff --git a/src/commands/project/pkg.ts b/src/commands/project/pkg.ts index 46c0e6e..c1ad653 100644 --- a/src/commands/project/pkg.ts +++ b/src/commands/project/pkg.ts @@ -3,6 +3,7 @@ import { Engine, EngineConfiguration, EnginePlatform } from '../../lib/engine.ts import { Config } from '../../lib/config.ts' import type { GlobalOptions } from '../../lib/types.ts' import { createProject } from '../../lib/project.ts' +import { formatIsoTimestamp } from '../../lib/utils.ts' export type PkgOptions = typeof pkg extends Command ? Options : never @@ -18,8 +19,9 @@ export const pkg = new Command() }) .option('-a, --archive-directory ', 'Path to archive directory') .option('-z, --zip', 'Should we zip the archive') - .option('-d, --dry-run', 'Dry run') - .option('--compile', 'Use the precompiled binaries', { default: false }) + .option('--buildgraph', 'Build Graph', { default: false }) + .option('-d, --dry-run', 'Dry run', { default: false }) + .option('--compile', 'Compile the editor', { default: false }) .option('--profile ', 'Build profile', { default: 'client', required: true }) .stopEarly() .action(async (options, ...pkgArguments: Array) => { @@ -29,8 +31,16 @@ export const pkg = new Command() cliOptions: options, }) - const args = pkg.getLiteralArgs().concat(pkgArguments) + const buildId = `${ + formatIsoTimestamp(cfg.getConfig().metadata?.ts) + }-${cfg.getBuildId()}-${cfg.getConfig().buildkite?.buildNumber}` - const project = await createProject(enginePath, projectPath) - project.package({ archiveDirectory: archiveDirectory, profile: profile, extraArgs: args }) + const project = await createProject(enginePath, projectPath, options.buildgraph) + project.package({ + archiveDirectory: archiveDirectory, + profile: profile, + buildId: buildId, + extraArgs: pkgArguments, + dryRun: options.dryRun, + }) }) diff --git a/src/commands/project/run.ts b/src/commands/project/run.ts index 9ebdf95..38fbcb7 100644 --- a/src/commands/project/run.ts +++ b/src/commands/project/run.ts @@ -3,6 +3,7 @@ import { Command } from '@cliffy/command' import { createProject } from '../../lib/project.ts' import type { GlobalOptions } from '../../lib/types.ts' import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' export const run = new Command() .description('Run the game') @@ -19,8 +20,12 @@ export const run = new Command() const project = await createProject(enginePath, projectPath) if (options.compile) { - await project.runEditor({ extraArgs: ['-game', ...runArguments] }) - } else { - await project.compileAndRunEditor({ extraRunArgs: ['-game', ...runArguments] }) + await project.compile({ + target: EngineTarget.Editor, + configuration: EngineConfiguration.Development, + dryRun: options.dryRun, + platform: EnginePlatform.Windows, + }) } + await project.runEditor({ extraArgs: ['-game', ...runArguments] }) }) diff --git a/src/lib/buildgraph.ts b/src/lib/buildgraph.ts new file mode 100644 index 0000000..3d347c0 --- /dev/null +++ b/src/lib/buildgraph.ts @@ -0,0 +1,122 @@ +export interface BuildGraphArgs { + buildId?: string + editorTarget?: string + gameTargets?: string[] | string + licensee?: string + versioned?: string + promoted?: string + archiveStream?: string + forceSubmit?: string + preferredAgent?: string + archiveName?: string + symbolStorePath?: string + clientPlatforms?: string[] | string + serverPlatforms?: string[] | string + clientConfigurations?: string[] | string + serverConfigurations?: string[] | string + clientTargetType?: string + outputDir?: string + extraCompileArguments?: string[] | string + extraCookArguments?: string[] | string + extraPackageArguments?: string[] | string + additionalTools?: string[] | string + dryRun?: boolean +} + +function buildGraphArgToString(arg: string[] | string, separator: string = ';') { + if (Array.isArray(arg)) { + return `${(arg as string[]).join(separator).replaceAll(' ', '')}` + } else { + return `${(arg as string)}` + } +} + +export function buildCommandLine(buildGraphArgs: BuildGraphArgs): string[] { + const outArgs: string[] = [] + + if (buildGraphArgs.buildId) { + outArgs.push(`-Set:buildId=${buildGraphArgToString(buildGraphArgs.buildId)}`) + } + + if (buildGraphArgs.editorTarget) { + outArgs.push(`-Set:editorTarget=${buildGraphArgToString(buildGraphArgs.editorTarget)}`) + } + + if (buildGraphArgs.gameTargets) { + outArgs.push(`-Set:gameTargets=${buildGraphArgToString(buildGraphArgs.gameTargets, ';')}`) + } + + if (buildGraphArgs.versioned) { + outArgs.push(`-Set:versioned=${buildGraphArgToString(buildGraphArgs.versioned)}`) + } + + if (buildGraphArgs.promoted) { + outArgs.push(`-Set:promoted=${buildGraphArgToString(buildGraphArgs.promoted)}`) + } + + if (buildGraphArgs.archiveStream) { + outArgs.push(`-Set:archiveStream=${buildGraphArgToString(buildGraphArgs.archiveStream)}`) + } + + if (buildGraphArgs.forceSubmit) { + outArgs.push(`-Set:forceSubmit=${buildGraphArgToString(buildGraphArgs.forceSubmit)}`) + } + + if (buildGraphArgs.preferredAgent) { + outArgs.push(`-Set:preferredAgent=${buildGraphArgToString(buildGraphArgs.preferredAgent)}`) + } + + if (buildGraphArgs.archiveName) { + outArgs.push(`-Set:archiveName=${buildGraphArgToString(buildGraphArgs.archiveName)}`) + } + + if (buildGraphArgs.symbolStorePath) { + outArgs.push(`-Set:symbolStorePath=${buildGraphArgToString(buildGraphArgs.symbolStorePath)}`) + } + + if (buildGraphArgs.clientPlatforms) { + outArgs.push(`-Set:clientPlatforms=${buildGraphArgToString(buildGraphArgs.clientPlatforms)}`) + } + + if (buildGraphArgs.serverPlatforms) { + outArgs.push(`-Set:serverPlatforms=${buildGraphArgToString(buildGraphArgs.serverPlatforms)}`) + } + + if (buildGraphArgs.clientConfigurations) { + outArgs.push(`-Set:clientConfigurations=${buildGraphArgToString(buildGraphArgs.clientConfigurations)}`) + } + + if (buildGraphArgs.serverConfigurations) { + outArgs.push(`-Set:serverConfigurations=${buildGraphArgToString(buildGraphArgs.serverConfigurations)}`) + } + + if (buildGraphArgs.clientTargetType) { + outArgs.push(`-Set:clientTargetType=${buildGraphArgToString(buildGraphArgs.clientTargetType)}`) + } + + if (buildGraphArgs.outputDir) { + outArgs.push(`-Set:outputDir=${buildGraphArgToString(buildGraphArgs.outputDir)}`) + } + + if (buildGraphArgs.extraCompileArguments) { + outArgs.push(`-Set:extraCompileArguments=${buildGraphArgToString(buildGraphArgs.extraCompileArguments)}`) + } + + if (buildGraphArgs.extraCookArguments) { + outArgs.push(`-Set:extraCookArguments=${buildGraphArgToString(buildGraphArgs.extraCookArguments)}`) + } + + if (buildGraphArgs.extraPackageArguments) { + outArgs.push(`-Set:extraPackageArguments=${buildGraphArgToString(buildGraphArgs.extraPackageArguments)}`) + } + + if (buildGraphArgs.additionalTools) { + outArgs.push(`-Set:additionalTools=${buildGraphArgToString(buildGraphArgs.additionalTools)}`) + } + + if (buildGraphArgs.dryRun) { + outArgs.push('-ListOnly') + } + + return outArgs +} diff --git a/src/lib/engine.ts b/src/lib/engine.ts index 1741b1a..f0604d8 100644 --- a/src/lib/engine.ts +++ b/src/lib/engine.ts @@ -163,7 +163,7 @@ export abstract class Engine { const buildScript = this.getBuildScript() const args = [target, configuration, platform, ...extraArgs] console.log('[runUBT]', args) - if (dryRun) return + if (dryRun) return { success: true, code: 0, signal: null, output: '' } return await exec(buildScript, args) } diff --git a/src/lib/project.ts b/src/lib/project.ts index 5c28ff1..95ccc10 100644 --- a/src/lib/project.ts +++ b/src/lib/project.ts @@ -4,6 +4,8 @@ import { globber } from 'globber' import { ValidationError } from '@cliffy/command' import { logger } from '../lib/logger.ts' +import { buildCommandLine, BuildGraphArgs } from '../lib/buildgraph.ts' + import { createEngine, Engine, @@ -77,15 +79,121 @@ interface ProjectFileVars { projectDir: string } -export class Project { +export abstract class Project { public readonly engine: Engine public readonly projectFileVars: ProjectFileVars + abstract compile({ + target, + configuration, + extraArgs, + dryRun, + platform, + }: { + target?: EngineTarget + configuration?: EngineConfiguration + platform?: EnginePlatform + extraArgs?: string[] + dryRun?: boolean + }): Promise<{ success: boolean; code: number; signal: Deno.Signal | null; output: string }> + + abstract package({ + buildId, + configuration, + extraArgs, + dryRun, + platform, + zip, + profile, + archiveDirectory, + }: { + buildId: string + archiveDirectory: string + profile: string + zip?: boolean + configuration?: EngineConfiguration + platform?: EnginePlatform + extraArgs?: string[] + dryRun?: boolean + }): Promise<{ success: boolean; code: number; signal: Deno.Signal | null; output: string }> + + abstract runEditor({ + extraArgs, + }: { + extraArgs?: string[] + }): Promise<{ success: boolean; code: number; signal: Deno.Signal | null; output: string }> + + abstract cookContent({ + extraArgs, + }: { + extraArgs?: string[] + }): Promise<{ success: boolean; code: number; signal: Deno.Signal | null; output: string }> + + abstract runClean(dryRun?: boolean): Promise + constructor(enginePath: Engine, projectFileVars: ProjectFileVars) { this.engine = enginePath this.projectFileVars = projectFileVars } + async parseProjectTargets(): Promise { + const args = ['-Mode=QueryTargets', this.projectFileVars.projectArgument] + await this.engine.ubt(args, { quiet: true }) + try { + const targetInfoJson = path.resolve(path.join(this.projectFileVars.projectDir, 'Intermediate', 'TargetInfo.json')) + const { Targets } = JSON.parse(Deno.readTextFileSync(targetInfoJson)) + const targets = Targets.map((target: TargetInfo) => target.Name) + return targets + } catch (e) { + return [] + } + } + + async checkTarget(target: string) { + const validTargets = await this.parseProjectTargets() + if (!validTargets.includes(target)) { + throw TargetError(target, validTargets) + } + } + + async genProjectFiles(args: string[]) { + // Generate project + // GenerateProjectFiles.bat -project=E:\Project\TestProject.uproject -game -engine + return await exec(this.engine.getGenerateScript(), [ + this.projectFileVars.projectArgument, + ...args, + ]) + } + + async runPython(scriptPath: string, extraArgs: Array) { + const args = [ + '-run=pythonscript', + `-script=${scriptPath}`, + ...extraArgs, + ] + logger.info(`Running Python script: ${scriptPath}`) + return await this.runEditor({ extraArgs: args }) + } + + async runCustomBuildGraph(buildGraphScript: string, args: string[] = []) { + let bgScriptPath = path.resolve(buildGraphScript) + if (!bgScriptPath.endsWith('.xml')) { + throw new Error('Invalid buildgraph script') + } + if (path.relative(this.engine.enginePath, bgScriptPath).startsWith('..')) { + console.log('Buildgraph script is outside of engine folder, copying...') + bgScriptPath = await copyBuildGraphScripts(this.engine.enginePath, bgScriptPath) + } + const uatArgs = [ + 'BuildGraph', + `-Script=${bgScriptPath}`, + ...args, + ] + return this.engine.runUAT(uatArgs) + } +} + +export class ManualProject extends Project { async compile({ target = EngineTarget.Editor, configuration = EngineConfiguration.Development, @@ -112,7 +220,7 @@ export class Project { const projectTarget = `${this.projectFileVars.projectName}${target}` await this.checkTarget(projectTarget) - await this.engine.runUBT({ + return await this.engine.runUBT({ target: projectTarget, configuration: configuration, platform: platform, @@ -127,9 +235,11 @@ export class Project { dryRun = false, platform = this.engine.getPlatformName(), zip = false, + buildId, profile, archiveDirectory, }: { + buildId: string archiveDirectory: string profile: string zip?: boolean @@ -161,10 +271,14 @@ export class Project { console.log(`[package] package ${profile} ${configuration} ${platform}`) console.log('[package] BCR args:') console.log(bcrArgs) - return + return { success: true, code: 0, signal: null, output: '' } } - await this.engine.runUAT(['BuildCookRun', ...bcrArgs]) + const result = await this.engine.runUAT(['BuildCookRun', ...bcrArgs]) + + if (!result.success) { + return result + } if (zip) { // Reverse the EnginePlatform enum to get the build output platform name, ie Win64 => Windows @@ -180,21 +294,12 @@ export class Project { `-archive=${archivePath}.zip`, '-compression=5', ] - await this.engine.runUAT(['ZipUtils', ...zipArgs]) + return await this.engine.runUAT(['ZipUtils', ...zipArgs]) + } else { + return result } } - async compileAndRunEditor({ - extraCompileArgs = [], - extraRunArgs = [], - }: { - extraCompileArgs?: string[] - extraRunArgs?: string[] - }) { - await this.compile({ extraArgs: extraCompileArgs }) - await this.runEditor({ extraArgs: extraRunArgs }) - } - async runEditor({ extraArgs = [], }: { @@ -207,8 +312,7 @@ export class Project { console.log(`Running editor with: ${this.engine.getEditorBin} ${args.join(' ')}`) try { - const result = await exec(this.engine.getEditorBin(), args) - return result + return await exec(this.engine.getEditorBin(), args) } catch (error: unknown) { console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) Deno.exit(1) @@ -231,43 +335,13 @@ export class Project { console.log(`Running editor with: ${this.engine.getEditorCmdBin} ${args.join(' ')}`) try { - const result = await exec(this.engine.getEditorCmdBin(), args) - return result + return await exec(this.engine.getEditorCmdBin(), args) } catch (error: unknown) { console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) Deno.exit(1) } } - async parseProjectTargets(): Promise { - const args = ['-Mode=QueryTargets', this.projectFileVars.projectArgument] - await this.engine.ubt(args, { quiet: true }) - try { - const targetInfoJson = path.resolve(path.join(this.projectFileVars.projectDir, 'Intermediate', 'TargetInfo.json')) - const { Targets } = JSON.parse(Deno.readTextFileSync(targetInfoJson)) - const targets = Targets.map((target: TargetInfo) => target.Name) - return targets - } catch (e) { - return [] - } - } - - async checkTarget(target: string) { - const validTargets = await this.parseProjectTargets() - if (!validTargets.includes(target)) { - throw TargetError(target, validTargets) - } - } - - async genProjectFiles(args: string[]) { - // Generate project - // GenerateProjectFiles.bat -project=E:\Project\TestProject.uproject -game -engine - await exec(this.engine.getGenerateScript(), [ - this.projectFileVars.projectArgument, - ...args, - ]) - } - async runClean(dryRun?: boolean) { const cwd = this.projectFileVars.projectDir @@ -286,18 +360,10 @@ export class Project { } } } +} - async runPython(scriptPath: string, extraArgs: Array) { - const args = [ - '-run=pythonscript', - `-script=${scriptPath}`, - ...extraArgs, - ] - logger.info(`Running Python script: ${scriptPath}`) - await this.runEditor({ extraArgs: args }) - } - - async runBuildGraph(buildGraphScript: string, args: string[] = []) { +export class BuildGraphProject extends Project { + async runBuildGraph(buildGraphScript: string, buildGraphNode: string, buildGraphArgs: BuildGraphArgs) { let bgScriptPath = path.resolve(buildGraphScript) if (!bgScriptPath.endsWith('.xml')) { throw new Error('Invalid buildgraph script') @@ -306,16 +372,195 @@ export class Project { console.log('Buildgraph script is outside of engine folder, copying...') bgScriptPath = await copyBuildGraphScripts(this.engine.enginePath, bgScriptPath) } + + const args = buildCommandLine(buildGraphArgs) + + console.log(args) + const uatArgs = [ - 'BuildGraph', - `-Script=${bgScriptPath}`, + `-Target=${buildGraphNode}`, + this.projectFileVars.projectArgument, ...args, ] - return await this.engine.runUAT(uatArgs) + return await this.runCustomBuildGraph(bgScriptPath, uatArgs) + } + + async compile({ + target = EngineTarget.Editor, + configuration = EngineConfiguration.Development, + extraArgs = [], + dryRun = false, + platform = this.engine.getPlatformName(), + }: { + target?: EngineTarget + configuration?: EngineConfiguration + platform?: EnginePlatform + extraArgs?: string[] + dryRun?: boolean + }) { + console.log('using build graph') + + const args = [ + '-NoUBTMakefiles', + '-NoXGE', + '-NoHotReload', + '-NoCodeSign', + '-NoP4', + '-TraceWrites', + ].concat(extraArgs) + + const projectTarget = `${this.projectFileVars.projectName}${target}` + + await this.checkTarget(projectTarget) + + const targetName = `${this.projectFileVars.projectName}${target}` + + const bgArgs: BuildGraphArgs = { + clientPlatforms: `${platform}`, + clientConfigurations: `${configuration}`, + dryRun: dryRun, + } + + if (extraArgs.length > 0) { + bgArgs.extraCompileArguments = extraArgs + } + + return await this.runBuildGraph( + path.join(this.projectFileVars.projectDir, '..', 'buildgraph', 'CoreBuildGraph.xml'), + `Compile ${targetName} ${platform} ${configuration}`, + bgArgs, + ) + } + + async package({ + configuration = EngineConfiguration.Development, + extraArgs = [], + dryRun = false, + platform = this.engine.getPlatformName(), + zip = false, + buildId, + profile, + archiveDirectory, + }: { + buildId: string + archiveDirectory: string + profile: string + zip?: boolean + configuration?: EngineConfiguration + platform?: EnginePlatform + extraArgs?: string[] + dryRun?: boolean + }) { + const args = [ + '-NoP4', + '-NoCodeSign', + '-stdout', + '-utf8output', + '-unattended', + '-nosplash', + ].concat(extraArgs) + + const bgArgs: BuildGraphArgs = { + outputDir: archiveDirectory, + buildId: buildId, + extraPackageArguments: args, + dryRun: dryRun, + } + + let target = '' + if (profile == 'client' || profile == 'game') { + target = 'Package Clients' + bgArgs.clientPlatforms = platform + bgArgs.clientConfigurations = configuration + + if (profile == 'client') { + bgArgs.clientTargetType = 'Client' + } else { + bgArgs.clientTargetType = 'Game' + } + } else if (profile == 'server') { + target = 'Package Servers' + bgArgs.serverPlatforms = platform + bgArgs.serverConfigurations = configuration + } + + if (extraArgs) { + bgArgs.extraPackageArguments = '' + } + return await this.runBuildGraph( + path.join(this.projectFileVars.projectDir, '..', 'buildgraph', 'CoreBuildGraph.xml'), + `${target}`, + bgArgs, + ) + } + + async runEditor({ + extraArgs = [], + }: { + extraArgs?: string[] + }) { + const args = [ + this.projectFileVars.projectFullPath, + ].concat(extraArgs) + + console.log(`Running editor with: ${this.engine.getEditorBin} ${args.join(' ')}`) + + try { + return await exec(this.engine.getEditorBin(), args) + } catch (error: unknown) { + console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) + Deno.exit(1) + } + } + + async cookContent({ + extraArgs = [], + }: { + extraArgs?: string[] + }) { + const platformTarget = getPlatformCookTarget(this.engine.getPlatformName()) + const args = [ + this.projectFileVars.projectFullPath, + '-run=Cook', + `-targetplatform=${platformTarget}`, + '-fileopenlog', + ].concat(extraArgs) + + console.log(`Running editor with: ${this.engine.getEditorCmdBin} ${args.join(' ')}`) + + try { + return await exec(this.engine.getEditorCmdBin(), args) + } catch (error: unknown) { + console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) + Deno.exit(1) + } + } + + async runClean(dryRun?: boolean) { + const cwd = this.projectFileVars.projectDir + + const iterator = globber({ + cwd, + include: ['**/Binaries/**', '**/Intermediate/**'], + }) + for await (const file of iterator) { + if (dryRun) { + console.log('Would delete:', file.absolute) + continue + } + if (file.isFile) { + console.log('Deleting:', file.absolute) + await Deno.remove(file.absolute) + } + } } } -export async function createProject(enginePath: string, projectPath: string): Promise { +export async function createProject( + enginePath: string, + projectPath: string, + useBuildGraph: boolean = false, +): Promise { const projectFile = await findProjectFile(projectPath).catch(() => null) if (projectFile == null) { @@ -332,7 +577,14 @@ export async function createProject(enginePath: string, projectPath: string): Pr console.log( `projectFullPath=${projectFileVars.projectFullPath} projectName=${projectFileVars.projectName} projectArgument=${projectFileVars.projectArgument} projectDir=${projectFileVars.projectDir}`, ) - const project = new Project(createEngine(enginePath), projectFileVars) + + let project = null + + if (useBuildGraph) { + project = new BuildGraphProject(createEngine(enginePath), projectFileVars) + } else { + project = new ManualProject(createEngine(enginePath), projectFileVars) + } return Promise.resolve(project) }