Skip to content

Commit

Permalink
Merge pull request #11 from holepunchto/fix/windows-path
Browse files Browse the repository at this point in the history
Fix installation to PATH on Windows
  • Loading branch information
davidmarkclements authored Apr 30, 2024
2 parents 87ca04f + d90ec1c commit 4772c08
Showing 1 changed file with 49 additions and 36 deletions.
85 changes: 49 additions & 36 deletions lib/system-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import os from 'os'
import fs from 'fs'
import path from 'path'
import { spawn } from 'child_process'
import { spawnSync } from 'child_process'
const { config } = Pear

const BIN = path.join(config.pearDir, 'bin')
const WIN_REGVAL_MATCHER = /REG_SZ\s+([^\r\n]+)\r?\n/

const isWin = process.platform === 'win32'

customElements.define('pear-welcome', class extends HTMLElement {
Expand Down Expand Up @@ -127,8 +129,8 @@ customElements.define('system-status', class extends HTMLElement {
</blockquote>
<p>To finish installing Pear Runtime set your system path to</p>
<p><code>${BIN}</code></p>
<p>${!isWin ? ' or click the button.' : ''}</p>
${!isWin ? '<p><button id="setup-button"> Automatic Setup Completion </button><p>' : ''}
<p> or click the button.</p>
<p><button id="setup-button"> Automatic Setup Completion </button><p>
`
}
</div>
Expand Down Expand Up @@ -179,6 +181,13 @@ customElements.define('system-status', class extends HTMLElement {
}
}
if (hasPear) process.env.PATH = `${BIN}:${process.env.PATH}`
} else {
const currentPath = spawnSync('reg', ['query', 'HKCU\\Environment', '/v', 'Path'])
.stdout.toString()?.match(WIN_REGVAL_MATCHER)?.[1]

if (!process.env.PATH?.includes(BIN) && currentPath?.includes(BIN)) {
process.env.PATH = `${BIN}${path.delimiter}${process.env.PATH}`
}
}

this.paths = process.env.PATH.split(path.delimiter)
Expand All @@ -189,46 +198,50 @@ customElements.define('system-status', class extends HTMLElement {
}

#install () {
const runtime = path.join('..', 'current', 'by-arch', process.platform + '-' + process.arch, 'bin', 'pear-runtime')
const runtimeSubpath = path.join('current', 'by-arch', process.platform + '-' + process.arch, 'bin', 'pear-runtime')
fs.mkdirSync(BIN, { recursive: true })

if (isWin) {
const ps1tmp = path.join(BIN, Math.floor(Math.random() * 1000) + '.pear')
fs.writeFileSync(ps1tmp, `function pear { & "${runtime}" }; Export-ModuleMember -Function pear`)
fs.renameSync(ps1tmp, path.join(BIN, 'pear.ps1'))
const cmdtmp = path.join(BIN, Math.floor(Math.random() * 1000) + '.pear')
fs.writeFileSync(cmdtmp, `@echo off\n"${runtime}" %*`)
fs.renameSync(cmdtmp, path.join(BIN, 'pear.cmd'))
return new Promise((resolve, reject) => {
spawn('powershell', ['-Command', `[System.Environment]::SetEnvironmentVariables("PATH", "${BIN};${process.env.PATH}", "User")`]).on('exit', (code) => {
if (code !== 0) {
reject(new Error('Failed to set PATH'))
return
}
process.env.PATH = `${BIN};${process.env.PATH}`
resolve()
})
})
}
const comment = '# Added by Pear Runtime, configures system with Pear CLI\n'
const profiles = Object.values(this.shellProfiles)
if (profiles.length > 0) {
for (const { filepath, hasPear } of profiles) {
if (hasPear === false) fs.writeFileSync(filepath, '\n' + comment + this.statement + '\n', { flag: 'a' })
const pearCmd = path.join(BIN, 'pear.cmd')
if (!fs.existsSync(pearCmd)) fs.writeFileSync(path.join(BIN, 'pear.cmd'), `@echo off\r\n"%~dp0..\\${runtimeSubpath}" %*`)

const pearPs1 = path.join(BIN, 'pear.ps1')
if (!fs.existsSync(pearPs1)) fs.writeFileSync(path.join(BIN, 'pear.ps1'), `& "$PSScriptRoot\\..\\${runtimeSubpath}" @args`)

const pathQuery = spawnSync('reg', ['query', 'HKCU\\Environment', '/v', 'Path'])
if (pathQuery.status !== 0 && !pathQuery.stderr.toString().includes('unable to find')) {
throw new Error('Failed to query user PATH.')
}

const originalPath = pathQuery.stdout.toString()?.match(WIN_REGVAL_MATCHER)?.[1]
if (!originalPath || !originalPath.includes(BIN)) {
const newPath = originalPath ? `${BIN};${originalPath}` : BIN
spawnSync('reg', ['add', 'HKCU\\Environment', '/v', 'Path', '/t', 'REG_SZ', '/d', newPath, '/f'])
}
} else {
const bash = this.paths.some((bin) => fs.existsSync(path.join(bin, 'bash')))
const zsh = this.paths.some((bin) => fs.existsSync(path.join(bin, 'zsh')))
fs.writeFileSync(path.join(os.homedir(), bash ? '.bashrc' : '.profile'), this.statement + '\n', { flag: 'a' })
if (zsh) fs.writeFileSync(path.join(os.homedir(), '.zshrc'), '\n' + comment + this.statement + '\n', { flag: 'a' })
const runtime = path.join('..', runtimeSubpath)
const comment = '# Added by Pear Runtime, configures system with Pear CLI\n'
const profiles = Object.values(this.shellProfiles)
if (profiles.length > 0) {
for (const { filepath, hasPear } of profiles) {
if (hasPear === false) fs.writeFileSync(filepath, '\n' + comment + this.statement + '\n', { flag: 'a' })
}
} else {
const bash = this.paths.some((bin) => fs.existsSync(path.join(bin, 'bash')))
const zsh = this.paths.some((bin) => fs.existsSync(path.join(bin, 'zsh')))
fs.writeFileSync(path.join(os.homedir(), bash ? '.bashrc' : '.profile'), this.statement + '\n', { flag: 'a' })
if (zsh) fs.writeFileSync(path.join(os.homedir(), '.zshrc'), '\n' + comment + this.statement + '\n', { flag: 'a' })
}

const pear = path.join(BIN, 'pear')
const tmp = path.join(BIN, Math.floor(Math.random() * 1000) + '.pear')
fs.symlinkSync(runtime, tmp)
fs.renameSync(tmp, pear)
fs.chmodSync(pear, 0o755)
}

const pear = path.join(BIN, 'pear')
const tmp = path.join(BIN, Math.floor(Math.random() * 1000) + '.pear')
fs.symlinkSync(runtime, tmp)
fs.renameSync(tmp, pear)
fs.chmodSync(pear, 0o755)
process.env.PATH = `${BIN}${path.delimiter}${process.env.PATH}`

process.env.PATH = `${BIN}:${process.env.PATH}`
return Promise.resolve()
}
})

0 comments on commit 4772c08

Please sign in to comment.