Skip to content
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

Spawn processes in Main and Upgrade to Electron 11 #141

Merged
merged 12 commits into from
Oct 29, 2021
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ coverage/
.nyc_output/
.yarn
.yarnrc
.todo
15 changes: 0 additions & 15 deletions packages/git/src/Git.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import _ from 'lodash'
import chokidar from 'chokidar'
import path from 'path'

import fs from 'fs'
Expand All @@ -13,19 +12,15 @@ import type { GetSpawn, StatusFile, Remote, FileInfo } from './types'
import { GitRefs } from './GitRefs'
import { GitCommits } from './GitCommits'
import { GitDiff } from './GitDiff'
import { Watcher } from './Watcher'
import { perfStart, instrumentClass } from './performance'
import { parseDiffNameStatusViewWithNulColumns } from './git-diff-parsing'

export class Git {
rawCwd: string
cwd: string
_watcher: chokidar.FSWatcher | null = null

readonly refs: GitRefs
readonly commits: GitCommits
readonly diff: GitDiff
readonly watcher: Watcher

constructor(cwd: string) {
this.rawCwd = cwd
Expand All @@ -34,12 +29,6 @@ export class Git {
this.refs = new GitRefs(this.cwd, this._getSpawn)
this.commits = new GitCommits(this.cwd, this._getSpawn, this)
this.diff = new GitDiff(this.cwd, this._getSpawn, this)
this.watcher = new Watcher(this.cwd)

instrumentClass(this)
instrumentClass(this.refs)
instrumentClass(this.commits)
instrumentClass(this.diff)
}

_getGitDir = async () => {
Expand All @@ -59,8 +48,6 @@ export class Git {
}

return async (args: string[], { okCodes = [0] } = {}): Promise<string> => {
const perf = perfStart('GIT/spawn/git ' + args.join(' '))

const buffers: Buffer[] = []
const child = spawn('git', args, { cwd: this.cwd })

Expand All @@ -74,8 +61,6 @@ export class Git {
})

child.on('close', (code) => {
perf.done()

const stdtxt = String(Buffer.concat(buffers))
if (okCodes.includes(code ?? 0)) {
resolve(stdtxt)
Expand Down
9 changes: 0 additions & 9 deletions packages/git/src/GitCommits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createHash } from 'crypto'

import { Git } from './Git'
import type { GetSpawn } from './types'
import { perfStart } from './performance'

import { Commits, Commit, LoadCommits } from './GitCommits.types'

Expand Down Expand Up @@ -61,18 +60,13 @@ export class GitCommits {
`--date-order`,
].filter(Boolean) as string[]

const perfSpawn = perfStart('GIT/log/spawn')
const result = await spawn(cmd)
perfSpawn.done()

const perfSanitise = perfStart('GIT/log/sanitise-result')
const tuples = result
.split(/\r\n|\r|\n/g)
.filter(Boolean)
.map((str) => str.split(SEP))
perfSanitise.done()

const perfDeserialise = perfStart('GIT/log/deserialise')
const commits = new Array<Commit>(tuples.length)
const hash = createHash('sha1')
for (let i = 0; i < tuples.length; i++) {
Expand Down Expand Up @@ -106,11 +100,8 @@ export class GitCommits {

hash.update(sha)
}
perfDeserialise.done()

const perfFinalise = perfStart('GIT/digest-finalise')
const digest = hash.digest('hex')
perfFinalise.done()

return {
query: opts,
Expand Down
1 change: 1 addition & 0 deletions packages/git/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Git'
export * from './Watcher'
export * from './constants'
export * from './types'
51 changes: 0 additions & 51 deletions packages/git/src/performance.ts

This file was deleted.

108 changes: 108 additions & 0 deletions packages/giterm/app/main/git-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { ipcMain, ipcRenderer } from 'electron'

import { Git } from '@giterm/git'
import { perfStart } from './performance'

type GitJob =
| 'git/status'
| 'git/status-text'
| 'git/head-sha'
| 'git/remotes'
| 'git/refs/branches'
| 'git/refs/tags'
| 'git/commits/load'
| 'git/diff/load-file-text'
| 'git/diff/by-shas'
| 'git/diff/by-index'

// TODO: TS4.5 has this built in and can be removed
type Awaited<T> = T extends PromiseLike<infer U> ? U : T

const createRpc = <
TFunc extends (...args: any[]) => Promise<any>,
TReturn = Awaited<ReturnType<TFunc>>,
TRequest = Parameters<TFunc>,
>(
eventName: GitJob,
) => {
return async (cwd: string, params: TRequest): Promise<TReturn> => {
const perf = perfStart(eventName)

try {
return await ipcRenderer.invoke(eventName, cwd, params)
} finally {
perf.done()
}
}
}

const createRpcHandler = <
TFunc extends (...args: any[]) => Promise<any>,
TReturn = Awaited<ReturnType<TFunc>>,
TRequest = Parameters<TFunc>,
>(
eventName: GitJob,
getFunc: (git: Git) => TFunc,
) => {
ipcMain.handle(
eventName,
async (ev, cwd: string, params: TRequest): Promise<TReturn> => {
const func = getFunc(new Git(cwd)) as TFunc

if (Array.isArray(params) && params.length > 0) {
return func(...params)
} else {
return func()
}
},
)

return {
dispose: () => ipcMain.removeHandler(eventName),
}
}

export const GitWorker = {
getStatus: createRpc<Git['getStatus']>('git/status'),
getStateText: createRpc<Git['getStateText']>('git/status-text'),
getHeadSha: createRpc<Git['getHeadSHA']>('git/head-sha'),
getAllRemotes: createRpc<Git['getAllRemotes']>('git/remotes'),
commits: {
load: createRpc<Git['commits']['load']>('git/commits/load'),
},
refs: {
getAllBranches:
createRpc<Git['refs']['getAllBranches']>('git/refs/branches'),
getAllTags: createRpc<Git['refs']['getAllTags']>('git/refs/tags'),
},
diff: {
loadFileText: createRpc<Git['diff']['loadFileText']>(
'git/diff/load-file-text',
),
getByShas: createRpc<Git['diff']['getByShas']>('git/diff/by-shas'),
getIndex: createRpc<Git['diff']['getIndex']>('git/diff/by-index'),
},
}

export const startGitWorker = () => {
const handlers = [
createRpcHandler('git/status', (git) => git.getStatus),
createRpcHandler('git/status-text', (git) => git.getStateText),
createRpcHandler('git/head-sha', (git) => git.getHeadSHA),
createRpcHandler('git/remotes', (git) => git.getAllRemotes),
createRpcHandler('git/commits/load', (git) => git.commits.load),
createRpcHandler('git/refs/branches', (git) => git.refs.getAllBranches),
createRpcHandler('git/refs/tags', (git) => git.refs.getAllTags),
createRpcHandler('git/diff/by-index', (git) => git.diff.getIndex),
createRpcHandler('git/diff/by-shas', (git) => git.diff.getByShas),
createRpcHandler('git/diff/load-file-text', (git) => git.diff.loadFileText),
]

return {
dispose: () => {
for (const handler of handlers) {
handler.dispose()
}
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,33 @@ import installExtension, {
REDUX_DEVTOOLS,
} from 'electron-devtools-installer'

import { startGitWorker } from './git-worker'
import { startSpawnWorker } from './spawn-worker'

import '../sentry'

const isDevelopment = process.env.NODE_ENV === 'development'

// autoUpdater.logger = logger
import * as remote from '@electron/remote/main'
remote.initialize()

let mainWindow = null
let mainWindow: BrowserWindow | null = null
const gitWorker = startGitWorker()
const spawnWorker = startSpawnWorker()
let forceQuit = false

const installExtensions = async () => {
const forceDownload = !!process.env.UPGRADE_EXTENSIONS

try {
logger.log('Installing extensions: Started')
await installExtension(
[REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS],
forceDownload,
)
await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], {
loadExtensionOptions: { allowFileAccess: true },
forceDownload: forceDownload,
})
logger.log('Installing extensions: Done')
} catch (e) {
} catch (e: any) {
logger.warn(`Error installing devtools extension: ${e.message}`)
}
}
Expand Down Expand Up @@ -56,11 +63,14 @@ app.on('ready', async () => {
show: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, '../sentry.js'),
},
title: `Giterm ${app.getVersion()}`,
})

remote.enable(mainWindow.webContents)

// Show on currently active screen
const currentScreen = screen.getDisplayNearestPoint(
screen.getCursorScreenPoint(),
Expand All @@ -74,7 +84,7 @@ app.on('ready', async () => {

// show window once on first load
mainWindow.webContents.once('did-finish-load', () => {
mainWindow.show()
mainWindow!.show()
})

mainWindow.webContents.on('did-finish-load', () => {
Expand All @@ -83,23 +93,25 @@ app.on('ready', async () => {
// 2. Click on icon in dock should re-open the window
// 3. ⌘+Q should close the window and quit the app
if (process.platform === 'darwin') {
mainWindow.on('close', function (e) {
mainWindow!.on('close', function (e) {
if (!forceQuit) {
e.preventDefault()
mainWindow.hide()
mainWindow!.hide()
}
})

app.on('activate', () => {
mainWindow.show()
mainWindow!.show()
})

app.on('before-quit', () => {
forceQuit = true
})
} else {
mainWindow.on('closed', () => {
mainWindow!.on('closed', () => {
mainWindow = null
gitWorker.dispose()
spawnWorker.dispose()
})
}
})
Expand All @@ -114,10 +126,10 @@ app.on('ready', async () => {
{
label: 'Inspect element',
click() {
mainWindow.inspectElement(props.x, props.y)
mainWindow!.webContents.inspectElement(props.x, props.y)
},
},
]).popup(mainWindow)
]).popup()
})
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// https://electronjs.org/docs/api/menu-item#roles

import { Menu } from 'electron'
import { Menu, BrowserWindow } from 'electron'

// NOTE
// Accelerators don't work from menu when focus is within xterm.js
// so functionality is handled within app.js as a result
export default function menu(mainWindow) {
export default function menu(mainWindow: BrowserWindow) {
return Menu.buildFromTemplate([
{
label: 'Giterm',
Expand Down Expand Up @@ -64,7 +64,7 @@ export default function menu(mainWindow) {
{
label: 'Window',
submenu: [
{ role: 'toggleFullScreen' },
{ role: 'togglefullscreen' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
Expand Down
Loading