164 lines
5.3 KiB
JavaScript
164 lines
5.3 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { spawnSync } from 'node:child_process'
|
|
import { existsSync, realpathSync } from 'node:fs'
|
|
import {
|
|
chmod,
|
|
mkdir,
|
|
mkdtemp,
|
|
readFile,
|
|
symlink,
|
|
writeFile,
|
|
} from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { basename, dirname, join } from 'node:path'
|
|
import process from 'node:process'
|
|
import test from 'node:test'
|
|
|
|
import {
|
|
BROKEN_LINUXDEPLOY_APPRUN_DIR_LINE,
|
|
FIXED_LINUXDEPLOY_APPRUN_DIR_LINE,
|
|
appImagePluginWrapperSource,
|
|
patchAppRunText,
|
|
} from './appimage-launcher-tools.mjs'
|
|
|
|
function brokenResolverDir(invokedPath) {
|
|
return realpathSync(dirname(invokedPath))
|
|
}
|
|
|
|
function fixedResolverDir(invokedPath) {
|
|
return dirname(realpathSync(invokedPath))
|
|
}
|
|
|
|
test('patches linuxdeploy AppRun wrapper to resolve the invoked path before dirname', () => {
|
|
const original = [
|
|
'#! /usr/bin/env bash',
|
|
'# autogenerated by linuxdeploy',
|
|
BROKEN_LINUXDEPLOY_APPRUN_DIR_LINE,
|
|
'exec "$this_dir"/AppRun.wrapped "$@"',
|
|
].join('\n')
|
|
|
|
const patched = patchAppRunText(original)
|
|
|
|
assert.equal(patched.changed, true)
|
|
assert.equal(patched.text.includes(BROKEN_LINUXDEPLOY_APPRUN_DIR_LINE), false)
|
|
assert.equal(patched.text.includes(FIXED_LINUXDEPLOY_APPRUN_DIR_LINE), true)
|
|
})
|
|
|
|
test('fixed resolver follows absolute and relative symlinks before choosing AppDir', async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'tolaria-apprun-resolver-'))
|
|
const appDir = join(root, 'Tolaria.AppDir')
|
|
const binDir = join(root, 'bin')
|
|
const relativeDir = join(root, 'relative-bin')
|
|
const appRun = join(appDir, 'AppRun')
|
|
|
|
await mkdir(appDir)
|
|
await mkdir(binDir)
|
|
await mkdir(relativeDir)
|
|
await writeFile(appRun, '#! /usr/bin/env bash\n', 'utf8')
|
|
|
|
const absoluteSymlink = join(binDir, 'tolaria')
|
|
const relativeSymlink = join(relativeDir, 'tolaria')
|
|
|
|
await symlink(appRun, absoluteSymlink)
|
|
await symlink(`../${basename(appDir)}/AppRun`, relativeSymlink)
|
|
|
|
assert.equal(brokenResolverDir(absoluteSymlink), realpathSync(binDir))
|
|
assert.equal(fixedResolverDir(absoluteSymlink), realpathSync(appDir))
|
|
assert.equal(brokenResolverDir(relativeSymlink), realpathSync(relativeDir))
|
|
assert.equal(fixedResolverDir(relativeSymlink), realpathSync(appDir))
|
|
})
|
|
|
|
test('plugin wrapper patches AppRun before delegating to the real output plugin', async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'tolaria-appimage-plugin-'))
|
|
const appDir = join(root, 'Tolaria.AppDir')
|
|
const appRun = join(appDir, 'AppRun')
|
|
const wrapper = join(root, 'linuxdeploy-plugin-appimage.AppImage')
|
|
const realPlugin = join(root, 'linuxdeploy-plugin-appimage.real.AppImage')
|
|
const pluginMarker = join(root, 'plugin-ran')
|
|
|
|
await mkdir(appDir)
|
|
await writeFile(
|
|
appRun,
|
|
[
|
|
'#! /usr/bin/env bash',
|
|
'# autogenerated by linuxdeploy',
|
|
BROKEN_LINUXDEPLOY_APPRUN_DIR_LINE,
|
|
'exec "$this_dir"/AppRun.wrapped "$@"',
|
|
].join('\n'),
|
|
'utf8',
|
|
)
|
|
await writeFile(wrapper, appImagePluginWrapperSource(), 'utf8')
|
|
await chmod(wrapper, 0o755)
|
|
await writeFile(
|
|
realPlugin,
|
|
`#!/usr/bin/env bash\nset -euo pipefail\ntouch "${pluginMarker}"\n`,
|
|
'utf8',
|
|
)
|
|
await chmod(realPlugin, 0o755)
|
|
|
|
const result = spawnSync(wrapper, [], {
|
|
encoding: 'utf8',
|
|
env: {
|
|
...process.env,
|
|
APPDIR: appDir,
|
|
TOLARIA_APPIMAGE_REAL_PLUGIN: realPlugin,
|
|
},
|
|
})
|
|
|
|
assert.equal(result.status, 0, result.stderr)
|
|
assert.equal(existsSync(pluginMarker), true)
|
|
|
|
const patched = await readFile(appRun, 'utf8')
|
|
assert.equal(patched.includes(BROKEN_LINUXDEPLOY_APPRUN_DIR_LINE), false)
|
|
assert.equal(patched.includes(FIXED_LINUXDEPLOY_APPRUN_DIR_LINE), true)
|
|
})
|
|
|
|
test('plugin wrapper bundles fcitx GTK3 input module before sealing AppImage', async () => {
|
|
const root = await mkdtemp(join(tmpdir(), 'tolaria-appimage-fcitx-'))
|
|
const appDir = join(root, 'Tolaria.AppDir')
|
|
const wrapper = join(root, 'linuxdeploy-plugin-appimage.AppImage')
|
|
const realPlugin = join(root, 'linuxdeploy-plugin-appimage.real.AppImage')
|
|
const pluginMarker = join(root, 'plugin-ran')
|
|
const hostModule = join(root, 'host', 'im-fcitx5.so')
|
|
const hostLibraryDir = join(root, 'host-lib')
|
|
const hostLibrary = join(hostLibraryDir, 'libFcitx5GClient.so.2')
|
|
|
|
await mkdir(appDir)
|
|
await mkdir(dirname(hostModule), { recursive: true })
|
|
await mkdir(hostLibraryDir)
|
|
await writeFile(hostModule, 'fake fcitx gtk module', 'utf8')
|
|
await writeFile(hostLibrary, 'fake fcitx client library', 'utf8')
|
|
await writeFile(wrapper, appImagePluginWrapperSource(), 'utf8')
|
|
await chmod(wrapper, 0o755)
|
|
await writeFile(
|
|
realPlugin,
|
|
`#!/usr/bin/env bash\nset -euo pipefail\ntouch "${pluginMarker}"\n`,
|
|
'utf8',
|
|
)
|
|
await chmod(realPlugin, 0o755)
|
|
|
|
const result = spawnSync(wrapper, [], {
|
|
encoding: 'utf8',
|
|
env: {
|
|
...process.env,
|
|
APPDIR: appDir,
|
|
TOLARIA_APPIMAGE_REAL_PLUGIN: realPlugin,
|
|
TOLARIA_FCITX_GTK3_IM_MODULE: hostModule,
|
|
TOLARIA_FCITX_LIBRARY_DIR: hostLibraryDir,
|
|
},
|
|
})
|
|
|
|
assert.equal(result.status, 0, result.stderr)
|
|
assert.equal(existsSync(pluginMarker), true)
|
|
assert.equal(
|
|
existsSync(
|
|
join(
|
|
appDir,
|
|
'usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules/im-fcitx5.so',
|
|
),
|
|
),
|
|
true,
|
|
)
|
|
assert.equal(existsSync(join(appDir, 'usr/lib/x86_64-linux-gnu/libFcitx5GClient.so.2')), true)
|
|
})
|