-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing Electron runner #5633
Merged
wdanilo
merged 63 commits into
develop
from
wip/wdanilo/shader-compilation-improvement-184304289
Feb 19, 2023
Merged
Fixing Electron runner #5633
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
54e933d
Refactoring config options
wdanilo cd8a27d
Refactoring opts parsing in electron app
wdanilo cb85fae
Refactoring
wdanilo 9baa8a8
refactoring
wdanilo d24bcb8
Refactoring
wdanilo e8ffe42
Making nested config work
wdanilo 3f105e8
Refactoring
wdanilo 130bfd2
Refactoring
wdanilo 35e4223
Revert "Refactoring"
wdanilo 3c0037f
Refactoring
wdanilo 2a3a2fc
Refactoring
wdanilo ccdda51
Making it work again
wdanilo defe1f0
Refactoring
wdanilo 1670acd
Refactoring
wdanilo cd86f7f
refactoring
wdanilo 18f02e3
Making content typechecking in TS
wdanilo a113539
Making electron compile again
wdanilo 0675ca1
Refactoring
wdanilo b34caa5
Refactoring
wdanilo 8098bde
Refactoring
wdanilo 45b772b
Refactoring
wdanilo db1f35e
Refactoring
wdanilo 607ed24
Refactoring
wdanilo 0a8d057
Refactoring
wdanilo 4595393
Refactoring
wdanilo a09ad58
Refactoring
wdanilo bf832de
Refactoring
wdanilo 68d19c7
Refactoring
wdanilo 2011ece
Refactoring
wdanilo 26ec66a
Adding Chrome options
wdanilo 0263406
Refactoring
wdanilo 0685854
Refactoring
wdanilo e9d27e2
Refactoring, applying review
wdanilo 2be4549
Refactoring
wdanilo e5a8eb2
Refactoring, linting
wdanilo b954b66
Refactoring, applying review comments
wdanilo 40018a1
Refactoring, extracting app configs to json files
wdanilo 871098f
Merge branch 'develop' into wip/wdanilo/shader-compilation-improvemen…
wdanilo 8830e95
Removing old files
wdanilo cbba1ed
Refactoring
wdanilo 1776bc5
Refactoring
wdanilo 26c81d6
Refactoring
wdanilo 1122556
Refactoring
wdanilo fcd691f
Connecting new arg parser to Rust
wdanilo 8e65da3
Refactoring
wdanilo d7ca350
Merge branch 'develop' into wip/wdanilo/shader-compilation-improvemen…
wdanilo bdba0e3
Linting
wdanilo 2a57a59
Cleaning the code
wdanilo bc7a223
Applying review
wdanilo a5ebcf3
Merge branch 'develop' into wip/wdanilo/shader-compilation-improvemen…
wdanilo a97ac54
Fixing build
wdanilo 2f5f4d9
Refactoring
wdanilo 9ebbd3c
fixes #5664
wdanilo c2a42d2
Merge branch 'develop' into wip/wdanilo/shader-compilation-improvemen…
wdanilo a5812f0
Refactoring
wdanilo 0ed3f8a
Improving json reading macro so it is re-evaluated when json files ch…
wdanilo 130aea4
Attempt to fix builds of ide with non-local gui source.
mwu-tow 1c29315
Merge remote-tracking branch 'origin/wip/wdanilo/shader-compilation-i…
mwu-tow 9210aaa
one more take
mwu-tow 25da309
Merge branch 'develop' into wip/wdanilo/shader-compilation-improvemen…
wdanilo a5924e4
another take
mwu-tow ce683f4
Merge remote-tracking branch 'origin/wip/wdanilo/shader-compilation-i…
mwu-tow 2f69bf3
Linting
wdanilo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Refactoring
- Loading branch information
commit a09ad58a05f52029a6143f61372c812b1940ae7c
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
import chalk from 'chalk' | ||
import buildCfg from '../../../build.json' | ||
import * as config from './config' | ||
const yargs = require('yargs') | ||
import * as naming from './naming' | ||
import stringLength from 'string-length' | ||
import { hideBin } from 'yargs/helpers' | ||
|
||
// ============ | ||
// === Help === | ||
// ============ | ||
|
||
const FULL_HELP_OPTION = 'full-help' | ||
|
||
let usage = chalk.bold( | ||
` | ||
Enso ${buildCfg.version} command line interface. | ||
Usage: enso [options] [--] [backend args]` | ||
) | ||
|
||
class Section { | ||
entries: any[] = [] | ||
description = '' | ||
constructor(entries: any[] = []) { | ||
this.entries = entries | ||
} | ||
} | ||
|
||
/** We use custom help printer because Yargs has many issues: | ||
* 1. The option ordering is random and there is no way to enforce it. | ||
* 2. The option groups ordering is random and there is no way to enforce it. | ||
* 3. Every option has a `[type`] annotation and there is no API to disable it. | ||
* 4. There is no option to print commands with single dash instead of double-dash. | ||
* 5. Help coloring is not supported, and they do not want to support it: | ||
* https://github.com/yargs/yargs/issues/251 | ||
*/ | ||
function printHelp(cfg: { | ||
args: config.Args | ||
groupsOrdering: string[] | ||
secondaryGroups: string[] | ||
fullHelp: boolean | ||
}) { | ||
console.log(usage) | ||
const terminalWidth = yargs.terminalWidth() | ||
const indentSize = 0 | ||
const optionPrefix = '-' | ||
const spacing = 2 | ||
const sections: { [key: string]: Section } = {} | ||
for (const groupName of cfg.groupsOrdering) { | ||
if (cfg.fullHelp || !cfg.secondaryGroups.includes(groupName)) { | ||
sections[groupName] = new Section() | ||
} | ||
} | ||
let maxOptionLength = 0 | ||
|
||
for (const [groupName, group] of Object.entries(cfg.args.groups)) { | ||
let section = sections[groupName] | ||
if (section == null) { | ||
section = new Section() | ||
sections[groupName] = section | ||
} | ||
section.description = group.description | ||
for (const option of group.optionsRecursive()) { | ||
const cmdOption = naming.camelToKebabCase(option.qualifiedName()) | ||
maxOptionLength = Math.max(maxOptionLength, stringLength(cmdOption)) | ||
const entry = [cmdOption, option] | ||
section.entries.push(entry) | ||
} | ||
} | ||
|
||
for (const [optionName, option] of Object.entries(cfg.args.options)) { | ||
const cmdOption = naming.camelToKebabCase(optionName) | ||
maxOptionLength = Math.max(maxOptionLength, stringLength(cmdOption)) | ||
const entry = [cmdOption, option] | ||
const section = sections[option.name] | ||
if (section != null) { | ||
section.entries.unshift(entry) | ||
} | ||
// sections['global'].entries.push(entry) | ||
} | ||
|
||
const borderStyle = (s: string) => chalk.gray(chalk.bold(s)) | ||
|
||
const leftWidth = maxOptionLength + indentSize + stringLength(optionPrefix) + spacing | ||
const rightWidth = terminalWidth - leftWidth | ||
|
||
for (const [groupName, section] of Object.entries(sections)) { | ||
console.log('\n\n') | ||
const groupTitle = chalk.bold(`${naming.camelCaseToTitle(groupName)} Options `) | ||
console.log(groupTitle) | ||
const description = wordWrap(section.description, terminalWidth).join('\n') | ||
console.log(description) | ||
console.log() | ||
for (const [cmdOption, option] of section.entries) { | ||
if (cfg.fullHelp || option.primary) { | ||
const indent = ' '.repeat(indentSize) | ||
let left = indent + chalk.bold(chalk.green(optionPrefix + cmdOption)) | ||
const spaces = ' '.repeat(leftWidth - stringLength(left)) | ||
left = left + spaces | ||
|
||
let firstSentenceSplit = option.description.indexOf('. ') | ||
let firstSentence = | ||
firstSentenceSplit == -1 | ||
? option.description | ||
: option.description.slice(0, firstSentenceSplit + 1) | ||
let otherSentences = option.description.slice(firstSentence.length) | ||
|
||
const def = option.defaultDescription ?? option.default | ||
let defaults = '' | ||
if (def != null && def !== '') { | ||
defaults = ` Defaults to ${chalk.green(def)}.` | ||
} | ||
let description = firstSentence + defaults + chalk.gray(otherSentences) | ||
const lines = wordWrap(description, rightWidth).map( | ||
line => line + ' '.repeat(rightWidth - stringLength(line)) | ||
) | ||
const right = lines.join('\n' + ' '.repeat(leftWidth)) | ||
console.log(left + right) | ||
} | ||
} | ||
} | ||
} | ||
|
||
function wordWrap(str: string, width: number): string[] { | ||
if (width <= 0) { | ||
return [] | ||
} | ||
let line = '' | ||
const lines = [] | ||
const inputLines = str.split('\n') | ||
for (const inputLine of inputLines) { | ||
for (let word of inputLine.split(' ')) { | ||
if (stringLength(word) > width) { | ||
if (line.length > 0) { | ||
lines.push(line) | ||
line = '' | ||
} | ||
const wordChunks = [] | ||
while (stringLength(word) > width) { | ||
wordChunks.push(word.slice(0, width)) | ||
word = word.slice(width) | ||
} | ||
wordChunks.push(word) | ||
for (const wordChunk of wordChunks) { | ||
lines.push(wordChunk) | ||
} | ||
} else { | ||
if (stringLength(line) + stringLength(word) >= width) { | ||
lines.push(line) | ||
line = '' | ||
} | ||
if (line.length != 0) { | ||
line += ' ' | ||
} | ||
line += word | ||
} | ||
} | ||
} | ||
if (line) { | ||
lines.push(line) | ||
} | ||
return lines | ||
} | ||
|
||
// ===================== | ||
// === Option Parser === | ||
// ===================== | ||
|
||
export function parseArgs() { | ||
const args = config.my_args | ||
let argv = hideBin(process.argv) | ||
|
||
const yargOptions = args.optionsRecursive().reduce((opts: { [key: string]: any }, option) => { | ||
const yargsParam = Object.assign({}, option) | ||
// @ts-ignore | ||
yargsParam.requiresArg = ['string', 'array'].includes(yargsParam.type) | ||
// @ts-ignore | ||
yargsParam.default = undefined | ||
// @ts-ignore | ||
opts[naming.camelToKebabCase(option.qualifiedName())] = yargsParam | ||
return opts | ||
}, {}) | ||
|
||
let optParser = yargs() | ||
.version(false) | ||
.parserConfiguration({ | ||
'short-option-groups': false, | ||
'dot-notation': false, | ||
// Makes all flags passed after '--' be one string. | ||
'populate--': true, | ||
}) | ||
.strict() | ||
.options(yargOptions) | ||
|
||
// === Parsing === | ||
|
||
let xargs = optParser.parse(argv, {}, (err: any, argsDict: any, help: string) => { | ||
console.log('!!!', err, help) | ||
if (help) { | ||
printHelp({ | ||
args, | ||
groupsOrdering: [], | ||
secondaryGroups: ['Electron Options'], | ||
fullHelp: argsDict[FULL_HELP_OPTION], | ||
}) | ||
process.exit() | ||
} | ||
}) | ||
|
||
for (const option of args.optionsRecursive()) { | ||
const arg = xargs[naming.camelToKebabCase(option.qualifiedName())] | ||
if (arg != null) { | ||
option.value = arg | ||
option.setByUser = true | ||
} | ||
} | ||
|
||
let windowSize = config.WindowSize.default() | ||
const parsedWindowSize = config.WindowSize.parse(args.groups.window.options.size.value) | ||
|
||
if (parsedWindowSize instanceof Error) { | ||
throw 'wrong window size' | ||
} else { | ||
windowSize = parsedWindowSize | ||
} | ||
|
||
if (args.options.help.value || args.options.fullHelp.value) { | ||
printHelp({ | ||
args, | ||
groupsOrdering: [], | ||
secondaryGroups: ['Electron Options'], | ||
fullHelp: args.options.fullHelp.value, | ||
}) | ||
process.exit() | ||
} | ||
|
||
const backendOptions = xargs['--'] | ||
|
||
return { args, windowSize, backendOptions } | ||
} |
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,60 @@ | ||
import child_process, { SpawnOptions } from 'child_process' | ||
import * as config from 'config' | ||
import fss from 'node:fs' | ||
import { logger } from '../../../content/src/config' | ||
import util from 'node:util' | ||
const execFile = util.promisify(child_process.execFile) | ||
|
||
// ======================= | ||
// === Project Manager === | ||
// ======================= | ||
|
||
/** Return the Project Manager path if it is valid. Otherwise, report an error and close the | ||
* application. */ | ||
export function pathOrPanic(args: config.Args): string { | ||
let binPath = args.groups.engine.options.projectManagerPath.value | ||
let binExists = fss.existsSync(binPath) | ||
if (!binExists) { | ||
logger.error(`Could not find the project manager binary at ${binPath}.`) | ||
process.exit(1) | ||
} | ||
return binPath | ||
} | ||
|
||
/** Executes the Project Manager with given arguments. */ | ||
async function exec(args: config.Args, processArgs: string[]) { | ||
let binPath = pathOrPanic(args) | ||
return await execFile(binPath, processArgs).catch(function (err) { | ||
throw err | ||
}) | ||
} | ||
|
||
/** Spawn Project Manager process. | ||
* | ||
* The standard output and error handles will be inherited, i.e. will be redirected to the | ||
* electron's app output and error handles. Input is piped to this process, so it will not be | ||
* closed, until this process finished. */ | ||
export function spawn(args: config.Args, processArgs: string[]) { | ||
return logger.groupMeasured( | ||
`Starting the backend process with the following options: ${processArgs}`, | ||
() => { | ||
const binPath = pathOrPanic(args) | ||
const stdin = 'pipe' as const | ||
const stdout = 'inherit' as const | ||
const stderr = 'inherit' as const | ||
const stdio = [stdin, stdout, stderr] | ||
const out = child_process.spawn(binPath, processArgs, { stdio }) | ||
logger.log(`Project Manager has been spawned (pid = ${out.pid}).`) | ||
out.on('exit', code => { | ||
logger.log(`Project Manager exited with code ${code}.`) | ||
}) | ||
return out | ||
} | ||
) | ||
} | ||
|
||
export async function version(args: config.Args) { | ||
if (args.groups.engine.options.backend.value) { | ||
return await exec(args, ['--version']).then(t => t.stdout) | ||
} | ||
} |
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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import * as content from '../../content/src/config' | ||
import * as paths from './paths' | ||
|
||
// ================== | ||
// === WindowSize === | ||
|
@@ -38,7 +39,7 @@ export class WindowSize { | |
// === Config === | ||
// ============== | ||
|
||
export const options = content.options.merge( | ||
export const my_args = content.options.merge( | ||
new content.Group({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General comment: language style of descriptions is inconsistent ("do" vs. "does"). |
||
options: { | ||
window: new content.Option({ | ||
|
@@ -135,7 +136,7 @@ export const options = content.options.merge( | |
description: 'Start the backend process.', | ||
}), | ||
projectManagerPath: new content.Option({ | ||
default: '', | ||
default: paths.projectManager, | ||
description: | ||
'Set the path of a local project manager to use for running projects', | ||
}), | ||
|
@@ -353,5 +354,7 @@ export const options = content.options.merge( | |
}, | ||
}) | ||
) | ||
options.groups.startup.options.platform.default = process.platform | ||
options.groups.startup.options.platform.value = process.platform | ||
my_args.groups.startup.options.platform.default = process.platform | ||
my_args.groups.startup.options.platform.value = process.platform | ||
|
||
export type Args = typeof my_args |
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,36 @@ | ||
import buildCfg from '../../../build.json' | ||
|
||
export const versionInfo = { | ||
version: buildCfg.version, | ||
build: buildCfg.commit, | ||
electron: process.versions.electron, | ||
chrome: process.versions.chrome, | ||
} | ||
|
||
async function getDebugInfo() { | ||
let procMemInfo = await process.getProcessMemoryInfo() | ||
return { | ||
version: versionInfo, | ||
creation: process.getCreationTime(), | ||
perf: { | ||
cpu: process.getCPUUsage(), | ||
}, | ||
memory: { | ||
heap: process.getHeapStatistics(), | ||
blink: process.getBlinkMemoryInfo(), | ||
process: procMemInfo, | ||
system: process.getSystemMemoryInfo(), | ||
}, | ||
system: { | ||
platform: process.platform, | ||
arch: process.arch, | ||
version: process.getSystemVersion(), | ||
}, | ||
} | ||
} | ||
|
||
export async function printDebugInfo() { | ||
let info = await getDebugInfo() | ||
console.log(JSON.stringify(info, undefined, 4)) | ||
process.exit() | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a matter of taste but I don't really like sthOrPanic style of functions, I'd rather throw an exception and allow caller to decide how it should be handled. (And also allow to provide more context information to be logged along the way.)
Also, it is not clear to me why "file not existing" is a panic, while other spawning issue "like file missing appropriate permission" is an exception?