Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TEMP] temp updater to force download from purple-a11y repo #79

Closed
wants to merge 17 commits into from
Closed
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
4 changes: 2 additions & 2 deletions .github/workflows/image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- name: Download Purple HATS Backend
shell: pwsh
run: |
$PHbackendUrl = "https://github.com/GovTechSG/purple-hats/releases/download/${{ vars.BE_TAG }}/purple-hats-portable-windows.zip"
$PHbackendUrl = "https://github.com/GovTechSG/purple-hats/releases/download/0.9.36/purple-hats-portable-windows.zip"
$BEdestinationPath = "${{github.workspace}}\PHLatest.zip"
$BEextractPath = "D:\a\Purple HATS Backend"
Invoke-WebRequest -Uri $PHbackendUrl -OutFile $BEdestinationPath
Expand Down Expand Up @@ -128,7 +128,7 @@ jobs:
npm run make-mac
env:
CI: ""
BE_TAG: "${{ vars.BE_TAG }}"
BE_TAG: "0.9.36"
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "purplehatsdesktop",
"productName": "Purple HATS",
"version": "0.9.35",
"version": "0.9.40-transition",
"private": true,
"dependencies": {
"axios": "^1.6.0",
Expand Down
4 changes: 2 additions & 2 deletions public/electron/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const allReleasesUrl = "https://api.github.com/repos/GovTechSG/purple-hats/relea

const frontendReleaseUrl =
os.platform() === "win32"
? "https://github.com/GovTechSG/purple-hats-desktop/releases/latest/download/purple-hats-desktop-windows.zip"
: "https://github.com/GovTechSG/purple-hats-desktop/releases/latest/download/purple-hats-desktop-macos.zip";
? "https://github.com/GovTechSG/purple-a11y-desktop/releases/latest/download/purple-a11y-desktop-windows.zip"
: "https://github.com/GovTechSG/purple-a11y-desktop/releases/latest/download/purple-a11y-desktop-macos.zip";

const backendPath = path.join(appPath, "Purple HATS Backend");
const frontendPath = path.join(appPath, "Purple HATS Frontend");
Expand Down
2 changes: 1 addition & 1 deletion public/electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ app.on("ready", async () => {
}),
});

const { data: releaseInfo } = await axiosInstance.get('https://govtechsg.github.io/purple-hats-desktop/latest-release.json')
const { data: releaseInfo } = await axiosInstance.get('https://govtechsg.github.io/purple-a11y-desktop/latest-release.json')
.catch((e) => {
console.log("Unable to get release info");
return { data: undefined };
Expand Down
168 changes: 79 additions & 89 deletions public/electron/updateManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,14 @@ const hashPrepackage = async (prepackagePath) => {

// unzip backend zip for mac
const unzipBackendAndCleanUp = async (zipPath=phZipPath) => {
let unzipCommand = `mkdir -p '${backendPath}' && tar -xf '${zipPath}' -C '${backendPath}' &&
cd '${backendPath}' &&
const tempBackendPath = path.join(
os.homedir(),
"Library",
"Application Support",
"Purple HATS",
"Purple HATS Backend");
let unzipCommand = `mkdir -p '${tempBackendPath}' && tar -xf '${zipPath}' -C '${tempBackendPath}' &&
cd '${tempBackendPath}' &&
'./hats_shell.sh' echo "Initialise"
`;

Expand All @@ -91,7 +97,7 @@ const unzipBackendAndCleanUp = async (zipPath=phZipPath) => {
}
};

const getLatestFrontendVersion = async (latestRelease, latestPreRelease) => {
const getLatestFrontendVersion = (latestRelease, latestPreRelease) => {
try {
let verToCompare;
if (isLabMode) {
Expand All @@ -102,10 +108,7 @@ const getLatestFrontendVersion = async (latestRelease, latestPreRelease) => {
} else {
verToCompare = latestRelease;
}
if (versionComparator(appFrontendVer, verToCompare) === -1) {
return verToCompare;
}
return undefined; // no need for update
return verToCompare;
} catch (e) {
console.log(`Unable to check latest frontend version, skipping\n${e.toString()}`);
return undefined;
Expand All @@ -118,20 +121,24 @@ const getLatestFrontendVersion = async (latestRelease, latestPreRelease) => {
*/
const downloadAndUnzipFrontendWindows = async (tag=undefined) => {
const downloadUrl = tag
? `https://github.com/GovTechSG/purple-hats-desktop/releases/download/${tag}/purple-hats-desktop-windows.zip`
? `https://github.com/GovTechSG/purple-a11y-desktop/releases/download/${tag}/purple-a11y-desktop-windows.zip`
: frontendReleaseUrl;
const tempResultsPath = path.join(process.env.APPDATA, "Purple A11y");
const shellScript = `
$webClient = New-Object System.Net.WebClient
try {
$webClient.DownloadFile("${downloadUrl}", "${resultsPath}\\purple-hats-desktop-windows.zip")
If (!(Test-Path -Path "${tempResultsPath}")) {
New-Item -ItemType Directory -Path "${tempResultsPath}"
}
$webClient.DownloadFile("${downloadUrl}", "${tempResultsPath}\\purple-a11y-desktop-windows.zip")
} catch {
Write-Host "Error: Unable to download frontend"
throw "Unable to download frontend"
exit 1
}

try {
Expand-Archive -Path "${resultsPath}\\purple-hats-desktop-windows.zip" -DestinationPath "${resultsPath}\\purple-hats-desktop-windows" -Force
Expand-Archive -Path "${tempResultsPath}\\purple-a11y-desktop-windows.zip" -DestinationPath "${tempResultsPath}\\purple-a11y-desktop-windows" -Force
} catch {
Write-Host "Error: Unable to unzip frontend"
throw "Unable to unzip frontend"
Expand All @@ -143,7 +150,7 @@ const downloadAndUnzipFrontendWindows = async (tag=undefined) => {
currentChildProcess = ps;

ps.stdout.on("data", (data) => {
silentLogger.log(data.toString());
silentLogger.debug(data.toString());
});

// Log any errors from the PowerShell script
Expand All @@ -166,26 +173,51 @@ const downloadAndUnzipFrontendWindows = async (tag=undefined) => {
});
};

/**
* Spawns a Shell Command process to make Purple A11y directory and copy over userData.txt
*/
const createNewAppDir = async (appDirPath) => {
const oldUserDataPath = path.join(
os.homedir(),
"Library",
"Application Support",
"Purple HATS",
"userData.txt",
);
const command = `
mkdir -p '${appDirPath}' &&
[ -f '${oldUserDataPath}' ] && cp '${oldUserDataPath}' '${appDirPath}'
`

await execCommand(command);
};

/**
* Spawns a Shell Command process to download and unzip the frontend
*/
const downloadAndUnzipFrontendMac = async (tag=undefined) => {
const downloadUrl = tag
? `https://github.com/GovTechSG/purple-hats-desktop/releases/download/${tag}/purple-hats-desktop-macos.zip`
? `https://github.com/GovTechSG/purple-a11y-desktop/releases/download/${tag}/purple-a11y-desktop-macos.zip`
: frontendReleaseUrl;
const tempResultsPath = path.join(
os.homedir(),
"Library",
"Application Support",
"Purple A11y"
)

await createNewAppDir(tempResultsPath);

const command = `
curl -L '${downloadUrl}' -o '${resultsPath}/purple-hats-desktop-mac.zip' &&
mv '${macOSExecutablePath}' '${path.join(
macOSExecutablePath,
".."
)}/Purple Hats Old.app' &&
ditto -xk '${resultsPath}/purple-hats-desktop-mac.zip' '${path.join(
curl -L '${downloadUrl}' -o '${tempResultsPath}/purple-a11y-desktop-mac.zip' &&
ditto -xk '${tempResultsPath}/purple-a11y-desktop-mac.zip' '${path.join(
macOSExecutablePath,
".."
)}' &&
rm '${resultsPath}/purple-hats-desktop-mac.zip' &&
rm -rf '${path.join(macOSExecutablePath, "..")}/Purple Hats Old.app' &&
xattr -rd com.apple.quarantine '${path.join(macOSExecutablePath, "..")}/Purple HATS.app' `;
rm '${tempResultsPath}/purple-a11y-desktop-mac.zip' &&
xattr -rd com.apple.quarantine '${path.join(macOSExecutablePath, "..")}/Purple A11y.app' &&
open '${path.join(macOSExecutablePath, "..")}/Purple A11y.app' &&
rm -rf '${macOSExecutablePath}'`;

await execCommand(command);

Expand All @@ -197,7 +229,13 @@ const downloadAndUnzipFrontendMac = async (tag=undefined) => {
* @returns {Promise<boolean>} true if the installer executable was launched successfully, false otherwise
*/
const spawnScriptToLaunchInstaller = () => {
const shellScript = `Start-Process -FilePath "${installerExePath}"`;
const tempResultsPath = path.join(process.env.APPDATA, "Purple A11y");
const tempInstallerExePath = path.join(
tempResultsPath,
"purple-a11y-desktop-windows",
"Purple-A11y-Setup.exe"
);
const shellScript = `Start-Process -FilePath "${tempInstallerExePath}"`;

return new Promise((resolve, reject) => {
const ps = spawn("powershell.exe", ["-Command", shellScript]);
Expand Down Expand Up @@ -271,7 +309,7 @@ const downloadAndUnzipBackendWindows = async (tag=undefined) => {
};

const downloadBackend = async (tag=undefined) => {
const downloadUrl = `https://github.com/GovTechSG/purple-hats/releases/download/${tag}/purple-hats-portable-mac.zip`;
const downloadUrl = `https://github.com/GovTechSG/purple-a11y/releases/download/${tag}/purple-a11y-portable-mac.zip`;
const command = `curl '${downloadUrl}' -o '${phZipPath}' -L && rm -rf '${backendPath}' && mkdir '${backendPath}'`;

return async () => await execCommand(command);
Expand Down Expand Up @@ -307,7 +345,8 @@ const run = async (updaterEventEmitter, latestRelease, latestPreRelease) => {

const backendExists = fs.existsSync(backendPath);
const phZipExists = fs.existsSync(phZipPath);
const toUpdateFrontendVer = await getLatestFrontendVersion(latestRelease, latestPreRelease);

const toUpdateFrontendVer = getLatestFrontendVersion(latestRelease, latestPreRelease);

// Auto updates via installer is only applicable for Windows
// Auto updates for backend on Windows will be done via a powershell script due to %ProgramFiles% permission
Expand Down Expand Up @@ -342,7 +381,8 @@ const run = async (updaterEventEmitter, latestRelease, latestPreRelease) => {
const isInstallerScriptLaunched =
await spawnScriptToLaunchInstaller();
if (isInstallerScriptLaunched) {
writeUserDetailsToFile({ firstLaunchOnUpdate: true });
// TODO: Should not need this, basically fresh install because userData.txt should not exist
// writeUserDetailsToFile({ firstLaunchOnUpdate: true });
updaterEventEmitter.emit("installerLaunched");
}
}
Expand All @@ -351,78 +391,28 @@ const run = async (updaterEventEmitter, latestRelease, latestPreRelease) => {
}
}
} else if (!backendExists) {
// TODO: should not enter here
console.log("Should not enter backend does not exist block")
updaterEventEmitter.emit('settingUp');
// Trigger download for backend via Github if backend does not exist
// TODO: Did not work on this for updater (old impl)
await downloadAndUnzipBackendWindows(appFrontendVer);
}
} else {
// user is on mac
if (toUpdateFrontendVer) {
const userResponse = new Promise((resolve) => {
updaterEventEmitter.emit("promptFrontendUpdate", resolve);
});
updaterEventEmitter.emit("updatingFrontend");
// Relaunch the app with new binaries if the frontend update is successful
// If unsuccessful, the app will be launched with existing frontend
try {
// downloads and opens the new frontend
await downloadAndUnzipFrontendMac(toUpdateFrontendVer);

const proceedUpdate = await userResponse;

if (proceedUpdate) {
updaterEventEmitter.emit("updatingFrontend");

// Relaunch the app with new binaries if the frontend update is successful
// If unsuccessful, the app will be launched with existing frontend
try {
await downloadAndUnzipFrontendMac(toUpdateFrontendVer);
currentChildProcess = null;

if (await validateZipFile(macOSPrepackageBackend)) {
processesToRun.push(hashAndSaveZip(macOSPrepackageBackend));
processesToRun.push(await unzipBackendAndCleanUp(macOSPrepackageBackend));
} else {
processesToRun.push(
await downloadBackend(toUpdateFrontendVer),
hashAndSaveZip(phZipPath),
await unzipBackendAndCleanUp()
);
}
currentChildProcess = null;

writeUserDetailsToFile({ firstLaunchOnUpdate: true });
processesToRun.push(() => updaterEventEmitter.emit("restartTriggered"));
} catch (e) {
silentLogger.error(e.toString());
}
}
} else if (!backendExists) {
updaterEventEmitter.emit('settingUp');
if (await validateZipFile(macOSPrepackageBackend)) {
// Trigger an unzip from Resources folder if backend does not exist or backend is older
processesToRun.push(
await unzipBackendAndCleanUp(macOSPrepackageBackend),
hashAndSaveZip(macOSPrepackageBackend)
);
} else {
processesToRun.push(
await downloadBackend(appFrontendVer),
hashAndSaveZip(phZipPath),
await unzipBackendAndCleanUp()
);
}
} else if (backendExists && await validateZipFile(macOSPrepackageBackend)) {
// compare zip file hash to determine whether to unzip
// current hash of prepackage
const currHash = await hashPrepackage(macOSPrepackageBackend);
if (fs.existsSync(hashPath)) {
// check if match
const hash = fs.readFileSync(hashPath, "utf-8"); // stored hash
// compare
if (hash === currHash) {
// dont unzip
return;
}
}
processesToRun.push(() => updaterEventEmitter.emit('settingUp'));
// unzip
processesToRun.push(await unzipBackendAndCleanUp(macOSPrepackageBackend));
// write hash
processesToRun.push(() => fs.writeFileSync(hashPath, currHash));
// exit the old (current) app
processesToRun.push(() => updaterEventEmitter.emit("installerLaunched"));
} catch (e) {
silentLogger.error(e.toString());
}

for (const proc of processesToRun) {
Expand Down
4 changes: 3 additions & 1 deletion src/MainWindow/HomePage/AboutModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ const AboutModal = ({
const toCompare = isLabMode ? latestVerForLab : latestVer;
const isNeedUpdate = versionComparator(appVersion, toCompare) === -1;

if (isNeedUpdate) {
if (toCompare === "0.9.40" && appVersion === "0.9.40-transition") {
setToUpdateVer(toCompare);
} else if (isNeedUpdate) {
setToUpdateVer(toCompare);
} else {
setToUpdateVer(undefined);
Expand Down
Loading