Skip to content

Commit

Permalink
refactor version detection
Browse files Browse the repository at this point in the history
  • Loading branch information
QbDesu committed Jun 1, 2021
1 parent b9cf067 commit f4d21dc
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 133 deletions.
133 changes: 0 additions & 133 deletions src/renderer/actions/paths.js

This file was deleted.

45 changes: 45 additions & 0 deletions src/renderer/actions/paths/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const fs = require("fs");
const path = require("path");
import {remote} from "electron";

import {validate as validateWindows, getDiscordPath as getWindowsDiscordPath} from "./windows";
import {validate as validateMac, getDiscordPath as getMacDiscordPath} from "./mac";
import {validate as validateLinux, getDiscordPath as getLinuxDiscordPath} from "./linux";

export const platforms = {stable: "Discord", ptb: "Discord PTB", canary: "Discord Canary"};
export const locations = {stable: "", ptb: "", canary: ""};

const getDiscordPath = function(releaseChannel) {
let resourcePath = "";
if (process.platform === "win32") {
resourcePath = getWindowsDiscordPath(releaseChannel);
}
else if (process.platform === "darwin") {
resourcePath = getMacDiscordPath(releaseChannel);
}
else {
resourcePath = getLinuxDiscordPath(releaseChannel);
}

if (fs.existsSync(resourcePath)) {
console.info(`Detected path "${resourcePath}" for channel "${releaseChannel}".`);
return resourcePath;
}
return "";
};

for (const channel in platforms) {
locations[channel] = getDiscordPath(platforms[channel]);
}

export const getBrowsePath = function(channel) {
if (process.platform === "win32") return path.join(process.env.LOCALAPPDATA, platforms[channel].replace(" ", ""));
else if (process.platform === "darwin") return path.join("/Applications", `${platforms[channel]}.app`);
return path.join(remote.app.getPath("userData"), "..", platforms[channel].toLowerCase().replace(" ", ""));
};

export const validatePath = function(channel, proposedPath) {
if (process.platform === "win32") return validateWindows(channel, proposedPath);
else if (process.platform === "darwin") return validateMac(channel, proposedPath);
return validateLinux(channel, proposedPath);
};
71 changes: 71 additions & 0 deletions src/renderer/actions/paths/linux.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const fs = require("fs");
const path = require("path");
import {remote} from "electron";
const semverRcompare = require("semver/functions/rcompare");
const semverValid = require("semver/functions/valid");

/** @typedef {{basedir: string, dir: string, version: string}} VersionPath */

/**
* @param {string} basedir
* @returns {VersionPath[]}
*/
const getDiscordVersionsForBaseDir = function(basedir) {
return fs.readdirSync(basedir).filter(
dir =>
fs.lstatSync(path.join(basedir, dir)).isDirectory() && // filter for directories
semverValid(dir.replace("app-","")) && // which have valid semver name (ignoring the app- prefix)
fs.existsSync(path.join(basedir, dir, "modules", "discord_desktop_core")) // that have a modules/discord_desktop_core folder
).map(
dir => ({
basedir,
dir,
version: dir.replace("app-","")
})
);
};

// TODO: try some deduplication with the windows version
/**
* @param {VersionPath[]} versions
* @returns {string} path
*/
const getHighestVersion = function(versions) {
const highest = versions.sort((v1,v2)=>semverRcompare(v1.version,v2.version))[0];
return path.join(highest.basedir, highest.dir, "modules", "discord_desktop_core");
};

export const getDiscordPath = function(releaseChannel) {
const basedir = path.join(remote.app.getPath("appData"), releaseChannel.toLowerCase().replace(" ", ""));
if (!fs.existsSync(basedir)) return "";

const detectedVersions = getDiscordVersionsForBaseDir(basedir);
console.debug(`Detected versions for channel "${releaseChannel}":`, detectedVersions);

if (!detectedVersions.length) return "";

return getHighestVersion(detectedVersions);
};

export const validate = function(channel, proposedPath) {
if (proposedPath.includes("/snap/")) {
remote.dialog.showErrorBox("BetterDiscord Incompatible", "BetterDiscord is currently incompatible with Snap installs of Discord. Support for snap installs is coming soon!");
return "";
}
const channelName = platforms[channel].toLowerCase().replace(" ", "");

let resourcePath = "";
const selected = path.basename(proposedPath);
if (selected === channelName) {
const version = fs.readdirSync(proposedPath).filter(f => fs.lstatSync(path.join(proposedPath, f)).isDirectory() && f.split(".").length > 1).sort().reverse()[0];
if (!version) return "";
resourcePath = path.join(proposedPath, version, "modules", "discord_desktop_core");
}
if (semverValid(selected)) resourcePath = path.join(proposedPath, "modules", "discord_desktop_core");
if (selected === "modules") resourcePath = path.join(proposedPath, "discord_desktop_core");
if (selected === "discord_desktop_core") resourcePath = proposedPath;

const asarPath = path.join(resourcePath, "core.asar");
if (fs.existsSync(asarPath)) return resourcePath;
return "";
};
21 changes: 21 additions & 0 deletions src/renderer/actions/paths/mac.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const fs = require("fs");
const path = require("path");

// FIXME: use the same platforms object as index.js
const platforms = {stable: "Discord", ptb: "Discord PTB", canary: "Discord Canary"};

export const getDiscordPath = function(releaseChannel) {
return path.join("/Applications", `${releaseChannel}.app`, "Contents", "Resources");
};

export const validate = function(channel, proposedPath) {
let resourcePath = "";
const selected = path.basename(proposedPath);
if (selected === `${platforms[channel]}.app`) resourcePath = path.join(proposedPath, "Contents", "Resources");
if (selected === "Contents") resourcePath = path.join(proposedPath, "Resources");
if (selected === "Resources") resourcePath = proposedPath;

const executablePath = path.join(resourcePath, "..", "MacOS", platforms[channel]);
if (fs.existsSync(executablePath)) return resourcePath;
return "";
};
75 changes: 75 additions & 0 deletions src/renderer/actions/paths/windows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const fs = require("fs");
const path = require("path");
const semverRcompare = require("semver/functions/rcompare");
const semverValid = require("semver/functions/valid");

/** @typedef {{basedir: string, dir: string, version: string}} VersionPath */

/**
* @param {string} basedir
* @returns {VersionPath[]}
*/
const getDiscordVersionsForBaseDir = function(basedir) {
return fs.readdirSync(basedir).filter(
dir =>
fs.lstatSync(path.join(basedir, dir)).isDirectory() && // filter for directories
semverValid(dir.replace("app-","")) && // which have valid semver name (ignoring the app- prefix)
fs.existsSync(path.join(basedir, dir, "resources")) // that have a resources folder
).map(
dir => ({
basedir,
dir,
version: dir.replace("app-","")
})
);
};

/**
* @param {VersionPath[]} versions
* @returns {string} path
*/
const getHighestVersion = function(versions) {
const highest = versions.sort((v1,v2)=>semverRcompare(v1.version,v2.version))[0];
return path.join(highest.basedir, highest.dir, "resources");
};

export const getDiscordPath = function(releaseChannel) {
const releaseChannelFolder = releaseChannel.replace(" ", "");

const basedirs = [
path.join(process.env.PROGRAMDATA, process.env.USERNAME, releaseChannelFolder),
path.join(process.env.LOCALAPPDATA, releaseChannelFolder)
].filter(dir => fs.existsSync(dir));
if (!basedirs.length) return "";

const detectedVersions = basedirs.map(getDiscordVersionsForBaseDir).flat();
console.debug(`Detected versions for channel "${releaseChannel}":`, detectedVersions);

if (!detectedVersions.length) return "";

return getHighestVersion(detectedVersions);
};

export const validate = function(channel, proposedPath) {
const channelName = platforms[channel].replace(" ", "");

const isParentDir = fs.existsSync(path.join(proposedPath, channelName));
if (isParentDir) proposedPath = path.join(proposedPath, channelName);

let resourcePath = "";
const selected = path.basename(proposedPath);
if (selected === channelName) {
const detectedVersions = getDiscordVersionsForBaseDir(proposedPath)
if (!detectedVersions.length) return "";
resourcePath = getHighestVersion(detectedVersions);
}

if (selected.startsWith("app-") && semverValid(selected.replace("app-", ""))) {
resourcePath = path.join(proposedPath, "resources");
}
if (selected === "resources") resourcePath = proposedPath;

const executablePath = path.join(resourcePath, "..", `${channelName}.exe`);
if (fs.existsSync(executablePath)) return resourcePath;
return "";
};

0 comments on commit f4d21dc

Please sign in to comment.