mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 06:56:04 +02:00
feat: download and include dotnet runtime in the appimage on linux (#1289)
This commit is contained in:
+8
-3
@@ -10,7 +10,7 @@
|
|||||||
"localization": "node ./src/localization/localizationHelperCLI.js",
|
"localization": "node ./src/localization/localizationHelperCLI.js",
|
||||||
"prod": "cross-env PLATFORM=windows webpack --config webpack.config.js --mode production",
|
"prod": "cross-env PLATFORM=windows webpack --config webpack.config.js --mode production",
|
||||||
"prod-linux": "cross-env PLATFORM=linux webpack --config webpack.config.js --mode production",
|
"prod-linux": "cross-env PLATFORM=linux webpack --config webpack.config.js --mode production",
|
||||||
"build-electron": "node ./src-electron/patch-package-version.js && electron-builder --publish never",
|
"build-electron": "node ./src-electron/download-dotnet-runtime.js && node ./src-electron/patch-package-version.js && electron-builder --publish never",
|
||||||
"postbuild-electron": "node ./src-electron/patch-node-api-dotnet.js && node ./src-electron/rename-builds.js",
|
"postbuild-electron": "node ./src-electron/patch-node-api-dotnet.js && node ./src-electron/rename-builds.js",
|
||||||
"start-electron": "electron ."
|
"start-electron": "electron ."
|
||||||
},
|
},
|
||||||
@@ -91,7 +91,8 @@
|
|||||||
"node_modules/node-api-dotnet/**/*",
|
"node_modules/node-api-dotnet/**/*",
|
||||||
"node_modules/node-api-dotnet/net9.0/**/*",
|
"node_modules/node-api-dotnet/net9.0/**/*",
|
||||||
"build/Electron/*",
|
"build/Electron/*",
|
||||||
"build/Electron/**"
|
"build/Electron/**",
|
||||||
|
"build/Electron/dotnet-runtime/**/*"
|
||||||
],
|
],
|
||||||
"extraResources": [
|
"extraResources": [
|
||||||
{
|
{
|
||||||
@@ -109,6 +110,10 @@
|
|||||||
{
|
{
|
||||||
"from": "node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll",
|
"from": "node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll",
|
||||||
"to": "app.asar.unpacked/node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll"
|
"to": "app.asar.unpacked/node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "build/Electron/dotnet-runtime/",
|
||||||
|
"to": "dotnet-runtime/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -140,4 +145,4 @@
|
|||||||
"hazardous": "^0.3.0",
|
"hazardous": "^0.3.0",
|
||||||
"node-api-dotnet": "^0.9.12"
|
"node-api-dotnet": "^0.9.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const https = require('https');
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
|
const DOTNET_VERSION = '9.0.7';
|
||||||
|
const DOTNET_RUNTIME_URL = `https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/dotnet-runtime-${DOTNET_VERSION}-linux-x64.tar.gz`;
|
||||||
|
const DOTNET_RUNTIME_DIR = path.join(__dirname, '..', 'build', 'Electron', 'dotnet-runtime');
|
||||||
|
const DOTNET_BIN_DIR = path.join(DOTNET_RUNTIME_DIR, 'bin');
|
||||||
|
|
||||||
|
async function downloadFile(url, targetPath) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const file = fs.createWriteStream(targetPath);
|
||||||
|
https.get(url, (response) => {
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
reject(new Error(`Failed to download, status code: ${response.statusCode}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.pipe(file);
|
||||||
|
file.on('finish', () => {
|
||||||
|
file.close(resolve);
|
||||||
|
});
|
||||||
|
}).on('error', (err) => {
|
||||||
|
fs.unlink(targetPath, () => reject(err));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function extractTarGz(tarGzPath, extractDir) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const tar = spawnSync('tar', ['-xzf', tarGzPath, '-C', extractDir, '--strip-components=1'], {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tar.status === 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(new Error(`tar extraction failed with status ${tar.status}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log(`Downloading .NET ${DOTNET_VERSION} runtime...`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(DOTNET_RUNTIME_DIR)) {
|
||||||
|
fs.mkdirSync(DOTNET_RUNTIME_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(DOTNET_BIN_DIR)) {
|
||||||
|
fs.mkdirSync(DOTNET_BIN_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tarGzPath = path.join(DOTNET_RUNTIME_DIR, 'dotnet-runtime.tar.gz');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Download .NET runtime
|
||||||
|
await downloadFile(DOTNET_RUNTIME_URL, tarGzPath);
|
||||||
|
console.log('Download completed');
|
||||||
|
|
||||||
|
// Extract .NET runtime to a temporary directory first
|
||||||
|
const tempExtractDir = path.join(DOTNET_RUNTIME_DIR, 'temp');
|
||||||
|
if (!fs.existsSync(tempExtractDir)) {
|
||||||
|
fs.mkdirSync(tempExtractDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Extracting .NET runtime...');
|
||||||
|
await extractTarGz(tarGzPath, tempExtractDir);
|
||||||
|
console.log('Extraction completed');
|
||||||
|
|
||||||
|
// Clean up tar.gz file
|
||||||
|
fs.unlinkSync(tarGzPath);
|
||||||
|
console.log('Cleanup completed');
|
||||||
|
|
||||||
|
// Move dotnet executable to bin directory
|
||||||
|
const extractedDotnet = path.join(tempExtractDir, 'dotnet');
|
||||||
|
const targetDotnet = path.join(DOTNET_BIN_DIR, 'dotnet');
|
||||||
|
|
||||||
|
if (fs.existsSync(extractedDotnet)) {
|
||||||
|
fs.renameSync(extractedDotnet, targetDotnet);
|
||||||
|
fs.chmodSync(targetDotnet, 0o755);
|
||||||
|
console.log('Moved dotnet executable to bin directory');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move all other files to the root of dotnet-runtime
|
||||||
|
const files = fs.readdirSync(tempExtractDir);
|
||||||
|
for (const file of files) {
|
||||||
|
const sourcePath = path.join(tempExtractDir, file);
|
||||||
|
const targetPath = path.join(DOTNET_RUNTIME_DIR, file);
|
||||||
|
|
||||||
|
if (fs.existsSync(targetPath)) {
|
||||||
|
if (fs.lstatSync(sourcePath).isDirectory()) {
|
||||||
|
// Remove existing directory and move new one
|
||||||
|
fs.rmSync(targetPath, { recursive: true, force: true });
|
||||||
|
} else {
|
||||||
|
// Remove existing file
|
||||||
|
fs.unlinkSync(targetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.renameSync(sourcePath, targetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up temp directory
|
||||||
|
fs.rmSync(tempExtractDir, { recursive: true, force: true });
|
||||||
|
|
||||||
|
console.log(`.NET runtime downloaded and extracted to: ${DOTNET_RUNTIME_DIR}`);
|
||||||
|
console.log(`dotnet executable available at: ${targetDotnet}`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { downloadFile, extractTarGz };
|
||||||
+18
-1
@@ -13,6 +13,15 @@ const { spawn, spawnSync } = require('child_process');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
|
|
||||||
|
// Include bundled .NET runtime
|
||||||
|
const bundledDotNetPath = path.join(process.resourcesPath, 'dotnet-runtime');
|
||||||
|
const bundledDotnet = path.join(bundledDotNetPath, 'bin', 'dotnet');
|
||||||
|
|
||||||
|
if (fs.existsSync(bundledDotnet)) {
|
||||||
|
process.env.DOTNET_ROOT = bundledDotNetPath;
|
||||||
|
process.env.PATH = `${path.dirname(bundledDotnet)}:${process.env.PATH}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDotNetInstalled()) {
|
if (!isDotNetInstalled()) {
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
dialog.showErrorBox(
|
dialog.showErrorBox(
|
||||||
@@ -24,7 +33,7 @@ if (!isDotNetInstalled()) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get launch arguments
|
// Get launch arguments
|
||||||
let appImagePath = process.env.APPIMAGE;
|
let appImagePath = process.env.APPIMAGE;
|
||||||
const args = process.argv.slice(1);
|
const args = process.argv.slice(1);
|
||||||
const noInstall = args.includes('--no-install');
|
const noInstall = args.includes('--no-install');
|
||||||
@@ -527,6 +536,14 @@ function isDotNetInstalled() {
|
|||||||
// Assume .NET is already installed on macOS
|
// Assume .NET is already installed on macOS
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for bundled .NET runtime
|
||||||
|
if (fs.existsSync(bundledDotnet)) {
|
||||||
|
console.log('Using bundled .NET runtime at:', bundledDotNetPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to system .NET runtime
|
||||||
const result = spawnSync('dotnet', ['--list-runtimes'], {
|
const result = spawnSync('dotnet', ['--list-runtimes'], {
|
||||||
encoding: 'utf-8'
|
encoding: 'utf-8'
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user