Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"dsh-desktop-market-installer": "file:packages/dsh-desktop-market-installer",
"electron-updater": "^6.8.9",
"node": "24.9.0",
"pnpm": "10.34.5",
"qrcode": "^1.5.4"
},
"devDependencies": {
Expand Down
61 changes: 51 additions & 10 deletions packages/dsh-desktop-market-installer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,46 @@ export async function ensurePnpmShim(home = dshHome()) {
const executable = process.execPath

if (process.platform === 'win32') {
const path = join(directory, 'pnpm.cmd')
await writeFile(path, `@\"${executable}\" \"${pnpmEntry}\" %*\r\n`, 'utf8')
const pnpmPath = join(directory, 'pnpm.cmd')
await writeFile(
pnpmPath,
`@chcp 65001 >nul\r\n@echo off\r\n\"${executable}\" \"${pnpmEntry}\" %*\r\n`,
'utf8'
)
const nodePath = join(directory, 'node.cmd')
await writeFile(
nodePath,
`@chcp 65001 >nul\r\n@echo off\r\n\"${executable}\" %*\r\n`,
'utf8'
)
} else {
const path = join(directory, 'pnpm')
const pnpmPath = join(directory, 'pnpm')
await writeFile(
path,
pnpmPath,
`#!/bin/sh\nexec ${shellQuote(executable)} ${shellQuote(pnpmEntry)} \"$@\"\n`,
{ encoding: 'utf8', mode: 0o755 }
)
await chmod(path, 0o755)
await chmod(pnpmPath, 0o755)
const nodePath = join(directory, 'node')
await writeFile(
nodePath,
`#!/bin/sh\nexec ${shellQuote(executable)} \"$@\"\n`,
{ encoding: 'utf8', mode: 0o755 }
)
await chmod(nodePath, 0o755)
}

const current = process.env.PATH ?? ''
if (!current.split(delimiter).includes(directory)) {
process.env.PATH = current ? `${directory}${delimiter}${current}` : directory
const nodeDir = dirname(executable)
const pathKey = process.platform === 'win32' ? 'Path' : 'PATH'
const current = process.env[pathKey] ?? process.env.PATH ?? process.env.Path ?? ''
const parts = current.split(delimiter).filter(Boolean)
const additions = [directory, nodeDir].filter((dir) => !parts.includes(dir))
if (additions.length > 0) {
const updated = [...additions, current].filter(Boolean).join(delimiter)
process.env.PATH = updated
if (process.platform === 'win32') {
process.env.Path = updated
}
}
return directory
}
Expand Down Expand Up @@ -258,9 +283,17 @@ export function apply(ctx) {
if (error?.code !== 'ENOENT') throw error
}

const pathKey = process.platform === 'win32' ? 'Path' : 'PATH'
const envPath = process.env[pathKey] ?? process.env.PATH ?? process.env.Path ?? ''
const child = spawn(process.execPath, buildInstallArguments(), {
cwd: directory,
env: { ...process.env, CI: 'true', NO_COLOR: '1' },
env: {
...process.env,
PATH: envPath,
Path: envPath,
CI: 'true',
NO_COLOR: '1'
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
detached: process.platform !== 'win32'
Expand Down Expand Up @@ -334,9 +367,17 @@ export function apply(ctx) {
if (error?.code !== 'ENOENT') throw error
}

const pathKey = process.platform === 'win32' ? 'Path' : 'PATH'
const envPath = process.env[pathKey] ?? process.env.PATH ?? process.env.Path ?? ''
const child = spawn(process.execPath, buildUninstallArguments(), {
cwd: directory,
env: { ...process.env, CI: 'true', NO_COLOR: '1' },
env: {
...process.env,
PATH: envPath,
Path: envPath,
CI: 'true',
NO_COLOR: '1'
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
detached: process.platform !== 'win32'
Expand Down
21 changes: 21 additions & 0 deletions test/market-installer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
UNINSTALL_PATH,
buildInstallArguments,
buildUninstallArguments,
ensurePnpmShim,
isTrustedRequest,
readMarketInstallation,
resolvePnpmEntry
Expand Down Expand Up @@ -45,6 +46,26 @@ describe('desktop plugin market installer', () => {
expect(resolvePnpmEntry()).toMatch(/node_modules[/\\]pnpm[/\\]bin[/\\]pnpm\.(c|m)js$/u)
})

it('generates packaged node and pnpm shims in desktop-bin', async () => {
const home = await mkdtemp(join(tmpdir(), 'dsh-market-shim-'))
const binDir = await ensurePnpmShim(home)
expect(binDir).toBe(join(home, '.desktop-bin'))

if (process.platform === 'win32') {
const pnpmCmd = await readFile(join(binDir, 'pnpm.cmd'), 'utf8')
const nodeCmd = await readFile(join(binDir, 'node.cmd'), 'utf8')
expect(pnpmCmd).toContain(process.execPath)
expect(pnpmCmd).toContain('pnpm')
expect(nodeCmd).toContain(process.execPath)
} else {
const pnpmScript = await readFile(join(binDir, 'pnpm'), 'utf8')
const nodeScript = await readFile(join(binDir, 'node'), 'utf8')
expect(pnpmScript).toContain(process.execPath)
expect(pnpmScript).toContain('pnpm')
expect(nodeScript).toContain(process.execPath)
}
})

it('reports both the requested dependency and installed package version', async () => {
const home = await mkdtemp(join(tmpdir(), 'dsh-market-status-'))
const profile = join(home, 'profiles', 'web')
Expand Down
Loading