Skip to content

Commit

Permalink
feat(tooling): flatpak - introduce abstractions to make Flatpak integ…
Browse files Browse the repository at this point in the history
…ration easier (#555 #558)

Co-Authored-By: nullrequest <30698906+advaithm@users.noreply.github.com>
  • Loading branch information
shiftkey and Lunarequest committed Nov 11, 2024
1 parent b454a70 commit 6af9fb0
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 5 deletions.
4 changes: 3 additions & 1 deletion app/src/lib/editors/launch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawn, SpawnOptions } from 'child_process'
import { pathExists } from '../../ui/lib/path-exists'
import { pathExists, spawnEditor } from '../helpers/linux'
import { ExternalEditorError, FoundEditor } from './shared'
import {
expandTargetPathArgument,
Expand Down Expand Up @@ -42,6 +42,8 @@ export async function launchExternalEditor(
// In macOS we can use `open`, which will open the right executable file
// for us, we only need the path to the editor .app folder.
spawn('open', ['-a', editorPath, fullPath], opts)
} else if (__LINUX__) {
spawnEditor(editorPath, fullPath, opts)
} else {
spawn(editorPath, [fullPath], opts)
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/lib/editors/linux.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { pathExists } from '../../ui/lib/path-exists'
import { pathExists } from '../helpers/linux'

import { IFoundEditor } from './found-editor'

/** Represents an external editor on Linux */
Expand Down
98 changes: 98 additions & 0 deletions app/src/lib/helpers/linux.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { join } from 'path'
import { pathExists as pathExistsInternal } from 'fs-extra'
import {
ChildProcess,
spawn as nodeSpawn,
SpawnOptionsWithoutStdio,
SpawnOptions,
} from 'child_process'

export function isFlatpakBuild() {
return __LINUX__ && process.env.FLATPAK_HOST === '1'
}

/**
* Convert an executable path to be relative to the flatpak host
*
* @param path a path to an executable relative to the root of the filesystem
*/
export function convertToFlatpakPath(path: string) {
if (!__LINUX__) {
return path
}

if (path.startsWith('/opt/')) {
return path
}

return join('/var/run/host', path)
}

export function formatWorkingDirectoryForFlatpak(path: string): string {
return path.replace(/(\s)/, ' ')
}

/**
* Checks the file path on disk exists before attempting to launch a specific shell
*
* @param path
*
* @returns `true` if the path can be resolved, or `false` otherwise
*/
export async function pathExists(path: string): Promise<boolean> {
if (isFlatpakBuild()) {
path = convertToFlatpakPath(path)
}

try {
return await pathExistsInternal(path)
} catch {
return false
}
}

/**
* Spawn a particular shell in a way that works for Flatpak-based usage
*
* @param path path to shell, relative to the root of the filesystem
* @param args arguments to provide to the shell
* @param options additional options to provide to spawn function
*
* @returns a child process to observe and monitor
*/
export function spawn(
path: string,
args: ReadonlyArray<string>,
options?: SpawnOptionsWithoutStdio
): ChildProcess {
if (isFlatpakBuild()) {
return nodeSpawn('flatpak-spawn', ['--host', path, ...args], options)
}

return nodeSpawn(path, args, options)
}

/**
* Spawn a given editor in a way that works for Flatpak-based usage
*
* @param path path to editor, relative to the root of the filesystem
* @param workingDirectory working directory to open initially in editor
* @param options additional options to provide to spawn function
*/
export function spawnEditor(
path: string,
workingDirectory: string,
options: SpawnOptions
): ChildProcess {
if (isFlatpakBuild()) {
const EscapedworkingDirectory =
formatWorkingDirectoryForFlatpak(workingDirectory)
return nodeSpawn(
'flatpak-spawn',
['--host', path, EscapedworkingDirectory],
options
)
} else {
return nodeSpawn(path, [workingDirectory], options)
}
}
4 changes: 2 additions & 2 deletions app/src/lib/shells/linux.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { spawn, ChildProcess } from 'child_process'
import { ChildProcess } from 'child_process'
import { assertNever } from '../fatal-error'
import { parseEnumValue } from '../enum'
import { pathExists } from '../../ui/lib/path-exists'
import { FoundShell } from './shared'
import {
expandTargetPathArgument,
ICustomIntegration,
parseCustomIntegrationArguments,
spawnCustomIntegration,
} from '../custom-integration'
import { pathExists, spawn } from '../helpers/linux'

export enum Shell {
Gnome = 'GNOME Terminal',
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/shells/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { ChildProcess } from 'child_process'
import * as Darwin from './darwin'
import * as Win32 from './win32'
import * as Linux from './linux'
import { pathExists } from '../helpers/linux'
import { ShellError } from './error'
import { pathExists } from '../../ui/lib/path-exists'
import { ICustomIntegration } from '../custom-integration'

export type Shell = Darwin.Shell | Win32.Shell | Linux.Shell
Expand Down
47 changes: 47 additions & 0 deletions app/test/unit/helpers/linux-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
convertToFlatpakPath,
formatWorkingDirectoryForFlatpak,
} from '../../../src/lib/helpers/linux'

describe('convertToFlatpakPath()', () => {
if (__LINUX__) {
it('converts /usr paths', () => {
const path = '/usr/bin/subl'
const expectedPath = '/var/run/host/usr/bin/subl'
expect(convertToFlatpakPath(path)).toEqual(expectedPath)
})

it('preserves /opt paths', () => {
const path = '/opt/slickedit-pro2018/bin/vs'
expect(convertToFlatpakPath(path)).toEqual(path)
})
}

if (__WIN32__) {
it('returns same path', () => {
const path = 'C:\\Windows\\System32\\Notepad.exe'
expect(convertToFlatpakPath(path)).toEqual(path)
})
}

if (__DARWIN__) {
it('returns same path', () => {
const path = '/usr/local/bin/code'
expect(convertToFlatpakPath(path)).toEqual(path)
})
}
})

describe('formatWorkingDirectoryForFlatpak()', () => {
if (__LINUX__) {
it('escapes string', () => {
const path = '/home/test/path with space'
const expectedPath = '/home/test/path with space'
expect(formatWorkingDirectoryForFlatpak(path)).toEqual(expectedPath)
})
it('returns same path', () => {
const path = '/home/test/path_wthout_spaces'
expect(formatWorkingDirectoryForFlatpak(path)).toEqual(path)
})
}
})

0 comments on commit 6af9fb0

Please sign in to comment.