(folderName, filePattern)
| 148 | // --------------------------------------------------------------------------- |
| 149 | |
| 150 | async function runLinux (folderName, filePattern) { |
| 151 | const rawVer = await getVer() |
| 152 | const ver = sanitizeVersion(rawVer) |
| 153 | |
| 154 | console.log(` Version: ${ver}`) |
| 155 | console.log(` Target: ${folderName}`) |
| 156 | |
| 157 | const target = join(packageRoot, `electerm-${ver}-${folderName}`) |
| 158 | |
| 159 | // Clean up old installations |
| 160 | rm('-rf', [target, extractDir]) |
| 161 | |
| 162 | console.log(' Fetching release info...') |
| 163 | const releaseInfo = await getReleaseInfo(r => r.name.includes(filePattern)) |
| 164 | if (!releaseInfo) { |
| 165 | throw new Error(`No release found for pattern: ${filePattern}`) |
| 166 | } |
| 167 | |
| 168 | // Download without extracting to packageRoot directly |
| 169 | // We'll extract to a temp location first |
| 170 | const tmpDir = join(packageRoot, '.electerm-tmp') |
| 171 | rm('-rf', tmpDir) |
| 172 | fs.mkdirSync(tmpDir, { recursive: true }) |
| 173 | |
| 174 | const proxyUrl = applyProxy(releaseInfo.browser_download_url) |
| 175 | console.log(` URL: ${proxyUrl}`) |
| 176 | |
| 177 | const { filepath } = await download(releaseInfo.browser_download_url, tmpDir, { extract: false, displayName: releaseInfo.name }) |
| 178 | |
| 179 | // Extract to tmpDir (keeps top-level folder name) |
| 180 | await extractTarGz(filepath, tmpDir) |
| 181 | |
| 182 | // Find the extracted folder (should be the only directory) |
| 183 | const entries = fs.readdirSync(tmpDir) |
| 184 | const extractedFolder = entries.find(e => fs.statSync(join(tmpDir, e)).isDirectory()) |
| 185 | |
| 186 | if (!extractedFolder) { |
| 187 | throw new Error('No folder found in extracted archive') |
| 188 | } |
| 189 | |
| 190 | // Move to extractDir |
| 191 | console.log(` Installing to: ${extractDir}`) |
| 192 | mv(join(tmpDir, extractedFolder), extractDir) |
| 193 | |
| 194 | // Fix chrome-sandbox permissions on Linux (Electron requires specific permissions) |
| 195 | // Note: setting the setuid bit requires root ownership, which npm install cannot provide. |
| 196 | // The launcher handles this by passing --no-sandbox when the sandbox is not root-owned. |
| 197 | if (plat === 'linux') { |
| 198 | const chromeSandboxPath = join(extractDir, 'chrome-sandbox') |
| 199 | if (fs.existsSync(chromeSandboxPath)) { |
| 200 | console.log(' Note: To enable the Electron sandbox, run:') |
| 201 | console.log(` sudo chown root:root "${chromeSandboxPath}"`) |
| 202 | console.log(` sudo chmod 4755 "${chromeSandboxPath}"`) |
| 203 | console.log(' Otherwise, electerm will launch with --no-sandbox automatically.') |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | // Clean up temp files |
no test coverage detected