From 4232ade31bc4da6c68e924fa5a6145a6b6dc0e4f Mon Sep 17 00:00:00 2001 From: KevalPrajapati Date: Tue, 23 Apr 2024 11:19:11 +0530 Subject: [PATCH 1/4] fix: fixes permission issue when renaming executable for windows --- .../utilities/commanddash-integration/dart-cli-client.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts index b75e8407..3800a87f 100644 --- a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts +++ b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts @@ -13,7 +13,7 @@ import { ExtensionVersionManager } from '../update-check'; import { logError, logEvent } from '../telemetry-reporter'; import { error } from 'console'; -async function setupExecutable(clientVersion: string, executablePath: string, executableVersion: string | undefined, onProgress: (progress: number) => void) { +async function setupExecutable(clientVersion: string, executablePath: string, executableVersion: string | undefined, onProgress: (progress: number) => void,proc:child_process.ChildProcessWithoutNullStreams|undefined) { const platform = os.platform(); const slug = platform === 'win32' ? 'windows' : platform === 'darwin' ? 'macos' : platform === 'linux' ? 'linux' : 'unsupported'; const config: AxiosRequestConfig = { @@ -25,6 +25,9 @@ async function setupExecutable(clientVersion: string, executablePath: string, ex console.log('Executable is already up to date.'); return; } + if(proc && proc.connected){ + proc.kill() + } await downloadFile(response['url'], executablePath, onProgress); if (platform === 'darwin' || platform === 'linux') { // Downloaded file is required to be coverted to an executable. @@ -103,12 +106,12 @@ export class DartCLIClient { } public async installExecutable(onProgress: (progress: number) => void) { - await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, undefined, onProgress); + await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, undefined, onProgress,this.proc); } // Install the updated executable in the background which will be kicked off on next extension activation. public async backgroundUpdateExecutable(): Promise { - await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, await this.executableVersion(), () => { }); + await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, await this.executableVersion(), () => { },this.proc); } public async deleteExecutable(): Promise { From 2e0d1495270f6ee7d2f6ff17743b29688e3bdc0e Mon Sep 17 00:00:00 2001 From: KevalPrajapati Date: Tue, 23 Apr 2024 11:35:16 +0530 Subject: [PATCH 2/4] Updated executables are replaced in the next IDE session --- vscode/src/repository/http-utils.ts | 5 ++--- .../commanddash-integration/dart-cli-client.ts | 18 +++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/vscode/src/repository/http-utils.ts b/vscode/src/repository/http-utils.ts index 7b9a8b6f..d4221c5b 100644 --- a/vscode/src/repository/http-utils.ts +++ b/vscode/src/repository/http-utils.ts @@ -97,6 +97,5 @@ export async function downloadFile(url: string, destinationPath: string, onProgr writer.on('finish', resolve); writer.on('error', reject); }); - - fs.renameSync(tempFilePath, destinationPath); // Only write file to destination path once download finishes -} + // Downloaded executable is saved as a temporory file. This will be renamed in the next session. +} \ No newline at end of file diff --git a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts index 3800a87f..e4ff71d2 100644 --- a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts +++ b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts @@ -2,7 +2,7 @@ import * as child_process from 'child_process'; import { EventEmitter } from 'events'; import { Task } from './task'; import { join } from 'path'; -import { chmod, existsSync, unlink } from 'fs'; +import { chmod, existsSync, renameSync, unlink } from 'fs'; import { downloadFile, makeHttpRequest } from '../../repository/http-utils'; import { AxiosRequestConfig } from 'axios'; import * as vscode from 'vscode'; @@ -13,7 +13,7 @@ import { ExtensionVersionManager } from '../update-check'; import { logError, logEvent } from '../telemetry-reporter'; import { error } from 'console'; -async function setupExecutable(clientVersion: string, executablePath: string, executableVersion: string | undefined, onProgress: (progress: number) => void,proc:child_process.ChildProcessWithoutNullStreams|undefined) { +async function setupExecutable(clientVersion: string, executablePath: string, executableVersion: string | undefined, onProgress: (progress: number) => void) { const platform = os.platform(); const slug = platform === 'win32' ? 'windows' : platform === 'darwin' ? 'macos' : platform === 'linux' ? 'linux' : 'unsupported'; const config: AxiosRequestConfig = { @@ -25,9 +25,6 @@ async function setupExecutable(clientVersion: string, executablePath: string, ex console.log('Executable is already up to date.'); return; } - if(proc && proc.connected){ - proc.kill() - } await downloadFile(response['url'], executablePath, onProgress); if (platform === 'darwin' || platform === 'linux') { // Downloaded file is required to be coverted to an executable. @@ -106,12 +103,12 @@ export class DartCLIClient { } public async installExecutable(onProgress: (progress: number) => void) { - await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, undefined, onProgress,this.proc); + await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, undefined, onProgress); } // Install the updated executable in the background which will be kicked off on next extension activation. public async backgroundUpdateExecutable(): Promise { - await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, await this.executableVersion(), () => { },this.proc); + await setupExecutable(ExtensionVersionManager.getExtensionVersion(), this.executablePath, await this.executableVersion(), () => { }); } public async deleteExecutable(): Promise { @@ -120,6 +117,13 @@ export class DartCLIClient { public connect() { + // Verify the presence of the temporary file, indicating a downloaded update during the last IDE session. + // Proceed with updating the executable if applicable. + const tempFilePath = `${this.executablePath}.tmp`; + if(existsSync(tempFilePath)){ + renameSync(tempFilePath, this.executablePath); + } + this.proc = child_process.spawn(this.executablePath, ['process']); let buffer = ''; From 3fa8bc0aae88cd66146ee71c4d8b0fb4d694af91 Mon Sep 17 00:00:00 2001 From: Keval Prajapati Date: Tue, 23 Apr 2024 12:05:16 +0530 Subject: [PATCH 3/4] fix: file rename in next session for mac and linux --- .../dart-cli-client.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts index e4ff71d2..b233db61 100644 --- a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts +++ b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts @@ -2,7 +2,7 @@ import * as child_process from 'child_process'; import { EventEmitter } from 'events'; import { Task } from './task'; import { join } from 'path'; -import { chmod, existsSync, renameSync, unlink } from 'fs'; +import { chmod, chmodSync, existsSync, renameSync, unlink } from 'fs'; import { downloadFile, makeHttpRequest } from '../../repository/http-utils'; import { AxiosRequestConfig } from 'axios'; import * as vscode from 'vscode'; @@ -26,16 +26,7 @@ async function setupExecutable(clientVersion: string, executablePath: string, ex return; } await downloadFile(response['url'], executablePath, onProgress); - if (platform === 'darwin' || platform === 'linux') { - // Downloaded file is required to be coverted to an executable. - return new Promise((resolve, reject) => { - chmod(executablePath, '755', (err) => { - if (err) { reject(err); } - console.log('The permissions for the executable have been set'); - resolve(); - }); - }); - } + } export async function deleteExecutable(executablePath: string): Promise { @@ -115,15 +106,24 @@ export class DartCLIClient { await deleteExecutable(this.executablePath); } + private renameTempToExecutable(tempFilePath: string) { + renameSync(tempFilePath, this.executablePath); + const platform = os.platform(); + if (platform === 'darwin' || platform === 'linux') { + // Downloaded file is required to be coverted to an executable. + chmodSync(this.executablePath, '755'); + } + } public connect() { // Verify the presence of the temporary file, indicating a downloaded update during the last IDE session. // Proceed with updating the executable if applicable. const tempFilePath = `${this.executablePath}.tmp`; - if(existsSync(tempFilePath)){ - renameSync(tempFilePath, this.executablePath); + if (existsSync(tempFilePath)) { + this.renameTempToExecutable(tempFilePath); } + this.proc = child_process.spawn(this.executablePath, ['process']); let buffer = ''; From fb5d55edb118e80265d14c01656c7a7ecba18ec9 Mon Sep 17 00:00:00 2001 From: Samyak Jain <56000318+samyakkkk@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:26:17 +0530 Subject: [PATCH 4/4] (fix): handled partial download failure case --- vscode/src/repository/http-utils.ts | 4 +++- .../src/utilities/commanddash-integration/dart-cli-client.ts | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vscode/src/repository/http-utils.ts b/vscode/src/repository/http-utils.ts index d4221c5b..de3fbf14 100644 --- a/vscode/src/repository/http-utils.ts +++ b/vscode/src/repository/http-utils.ts @@ -67,6 +67,7 @@ export async function refreshAccessToken(refreshToken: string): Promise export async function downloadFile(url: string, destinationPath: string, onProgress: (progress: number) => void): Promise { + /// First download on a temp path. This prevents from converting partial downloaded files (due to interruption) into executables. const tempFilePath = `${destinationPath}.tmp`; const response = await axios({ @@ -97,5 +98,6 @@ export async function downloadFile(url: string, destinationPath: string, onProgr writer.on('finish', resolve); writer.on('error', reject); }); - // Downloaded executable is saved as a temporory file. This will be renamed in the next session. + // Downloaded executable is saved as a pre-downloaded file which will be renamed in the next session. + fs.renameSync(tempFilePath, `${destinationPath}.pre-downloaded`); } \ No newline at end of file diff --git a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts index b233db61..33683f99 100644 --- a/vscode/src/utilities/commanddash-integration/dart-cli-client.ts +++ b/vscode/src/utilities/commanddash-integration/dart-cli-client.ts @@ -26,7 +26,6 @@ async function setupExecutable(clientVersion: string, executablePath: string, ex return; } await downloadFile(response['url'], executablePath, onProgress); - } export async function deleteExecutable(executablePath: string): Promise { @@ -118,7 +117,7 @@ export class DartCLIClient { public connect() { // Verify the presence of the temporary file, indicating a downloaded update during the last IDE session. // Proceed with updating the executable if applicable. - const tempFilePath = `${this.executablePath}.tmp`; + const tempFilePath = `${this.executablePath}.pre-downloaded`; if (existsSync(tempFilePath)) { this.renameTempToExecutable(tempFilePath); }