|
| 1 | +diff --git a/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts |
| 2 | +index 199f433..a6cbb10 100644 |
| 3 | +--- a/src/vs/platform/update/common/update.ts |
| 4 | ++++ b/src/vs/platform/update/common/update.ts |
| 5 | +@@ -51,3 +51,4 @@ export const enum UpdateType { |
| 6 | + Archive, |
| 7 | +- Snap |
| 8 | ++ Snap, |
| 9 | ++ WindowsInstaller, |
| 10 | + } |
| 11 | +@@ -110 +111,38 @@ export interface IUpdateService { |
| 12 | + } |
| 13 | ++ |
| 14 | ++export type Architecture = |
| 15 | ++ | "arm" |
| 16 | ++ | "arm64" |
| 17 | ++ | "ia32" |
| 18 | ++ | "loong64" |
| 19 | ++ | "mips" |
| 20 | ++ | "mipsel" |
| 21 | ++ | "ppc" |
| 22 | ++ | "ppc64" |
| 23 | ++ | "riscv64" |
| 24 | ++ | "s390" |
| 25 | ++ | "s390x" |
| 26 | ++ | "x64"; |
| 27 | ++ |
| 28 | ++export type Platform = |
| 29 | ++ | "aix" |
| 30 | ++ | "android" |
| 31 | ++ | "darwin" |
| 32 | ++ | "freebsd" |
| 33 | ++ | "haiku" |
| 34 | ++ | "linux" |
| 35 | ++ | "openbsd" |
| 36 | ++ | "sunos" |
| 37 | ++ | "win32" |
| 38 | ++ | "cygwin" |
| 39 | ++ | "netbsd"; |
| 40 | ++ |
| 41 | ++export type Quality = |
| 42 | ++ | "insider" |
| 43 | ++ | "stable"; |
| 44 | ++ |
| 45 | ++export type Target = |
| 46 | ++ | "archive" |
| 47 | ++ | "msi" |
| 48 | ++ | "system" |
| 49 | ++ | "user"; |
| 50 | +\ No newline at end of file |
| 51 | +diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts |
| 52 | +index 48638aa..8f738e7 100644 |
| 53 | +--- a/src/vs/platform/update/electron-main/abstractUpdateService.ts |
| 54 | ++++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts |
| 55 | +@@ -14,6 +14,10 @@ import { IProductService } from '../../product/common/productService.js'; |
| 56 | + import { IRequestService } from '../../request/common/request.js'; |
| 57 | +-import { AvailableForDownload, DisablementReason, IUpdateService, State, StateType, UpdateType } from '../common/update.js'; |
| 58 | ++import { Architecture, AvailableForDownload, DisablementReason, IUpdateService, Platform, State, StateType, Target, UpdateType } from '../common/update.js'; |
| 59 | + |
| 60 | +-export function createUpdateURL(platform: string, quality: string, productService: IProductService): string { |
| 61 | +- return `${productService.updateUrl}/api/update/${platform}/${quality}/${productService.commit}`; |
| 62 | ++export function createUpdateURL(productService: IProductService, quality: string, platform: Platform, architecture: Architecture, target?: Target): string { |
| 63 | ++ if (target) { |
| 64 | ++ return `${productService.updateUrl}/${quality}/${platform}/${architecture}/${target}/latest.json`; |
| 65 | ++ } else { |
| 66 | ++ return `${productService.updateUrl}/${quality}/${platform}/${architecture}/latest.json`; |
| 67 | ++ } |
| 68 | + } |
| 69 | +diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts |
| 70 | +index d3f27d3..8454ff3 100644 |
| 71 | +--- a/src/vs/platform/update/electron-main/updateService.darwin.ts |
| 72 | ++++ b/src/vs/platform/update/electron-main/updateService.darwin.ts |
| 73 | +@@ -15,3 +15,3 @@ import { ILogService } from '../../log/common/log.js'; |
| 74 | + import { IProductService } from '../../product/common/productService.js'; |
| 75 | +-import { IRequestService } from '../../request/common/request.js'; |
| 76 | ++import { IRequestService, asJson } from '../../request/common/request.js'; |
| 77 | + import { ITelemetryService } from '../../telemetry/common/telemetry.js'; |
| 78 | +@@ -19,2 +19,4 @@ import { IUpdate, State, StateType, UpdateType } from '../common/update.js'; |
| 79 | + import { AbstractUpdateService, createUpdateURL, UpdateErrorClassification, UpdateNotAvailableClassification } from './abstractUpdateService.js'; |
| 80 | ++import { CancellationToken } from '../../../base/common/cancellation.js'; |
| 81 | ++import * as semver from 'semver'; |
| 82 | + |
| 83 | +@@ -76,9 +78,3 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau |
| 84 | + protected buildUpdateFeedUrl(quality: string): string | undefined { |
| 85 | +- let assetID: string; |
| 86 | +- if (!this.productService.darwinUniversalAssetId) { |
| 87 | +- assetID = process.arch === 'x64' ? 'darwin' : 'darwin-arm64'; |
| 88 | +- } else { |
| 89 | +- assetID = this.productService.darwinUniversalAssetId; |
| 90 | +- } |
| 91 | +- const url = createUpdateURL(assetID, quality, this.productService); |
| 92 | ++ const url = createUpdateURL(this.productService, quality, process.platform, process.arch); |
| 93 | + try { |
| 94 | +@@ -94,4 +90,29 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau |
| 95 | + protected doCheckForUpdates(context: any): void { |
| 96 | ++ if (!this.url) { |
| 97 | ++ return; |
| 98 | ++ } |
| 99 | ++ |
| 100 | + this.setState(State.CheckingForUpdates(context)); |
| 101 | +- electron.autoUpdater.checkForUpdates(); |
| 102 | ++ |
| 103 | ++ this.requestService.request({ url: this.url }, CancellationToken.None) |
| 104 | ++ .then<IUpdate | null>(asJson) |
| 105 | ++ .then(update => { |
| 106 | ++ if (!update || !update.url || !update.version || !update.productVersion) { |
| 107 | ++ this.setState(State.Idle(UpdateType.Setup)); |
| 108 | ++ |
| 109 | ++ return Promise.resolve(null); |
| 110 | ++ } |
| 111 | ++ |
| 112 | ++ const fetchedVersion = update.productVersion.replace(/(\d+\.\d+\.\d+)(?:\.(\d+))(\-\w+)?/, '$1$3+$2'); |
| 113 | ++ const currentVersion = `${this.productService.version}+${this.productService.release}`; |
| 114 | ++ |
| 115 | ++ if(semver.compareBuild(currentVersion, fetchedVersion) >= 0) { |
| 116 | ++ this.setState(State.Idle(UpdateType.Setup)); |
| 117 | ++ } |
| 118 | ++ else { |
| 119 | ++ electron.autoUpdater.checkForUpdates(); |
| 120 | ++ } |
| 121 | ++ |
| 122 | ++ return Promise.resolve(null); |
| 123 | ++ }) |
| 124 | + } |
| 125 | +diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts |
| 126 | +index 6e076c7..81556b6 100644 |
| 127 | +--- a/src/vs/platform/update/electron-main/updateService.linux.ts |
| 128 | ++++ b/src/vs/platform/update/electron-main/updateService.linux.ts |
| 129 | +@@ -33,3 +33,3 @@ export class LinuxUpdateService extends AbstractUpdateService { |
| 130 | + protected buildUpdateFeedUrl(quality: string): string { |
| 131 | +- return createUpdateURL(`linux-${process.arch}`, quality, this.productService); |
| 132 | ++ return createUpdateURL(this.productService, quality, process.platform, process.arch); |
| 133 | + } |
| 134 | +diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts |
| 135 | +index 61109e5..06981b3 100644 |
| 136 | +--- a/src/vs/platform/update/electron-main/updateService.win32.ts |
| 137 | ++++ b/src/vs/platform/update/electron-main/updateService.win32.ts |
| 138 | +@@ -11,3 +11,2 @@ import { CancellationToken } from '../../../base/common/cancellation.js'; |
| 139 | + import { memoize } from '../../../base/common/decorators.js'; |
| 140 | +-import { hash } from '../../../base/common/hash.js'; |
| 141 | + import * as path from '../../../base/common/path.js'; |
| 142 | +@@ -25,4 +24,5 @@ import { asJson, IRequestService } from '../../request/common/request.js'; |
| 143 | + import { ITelemetryService } from '../../telemetry/common/telemetry.js'; |
| 144 | +-import { AvailableForDownload, DisablementReason, IUpdate, State, StateType, UpdateType } from '../common/update.js'; |
| 145 | +-import { AbstractUpdateService, createUpdateURL, UpdateErrorClassification, UpdateNotAvailableClassification } from './abstractUpdateService.js'; |
| 146 | ++import { AvailableForDownload, DisablementReason, IUpdate, State, StateType, Target, UpdateType } from '../common/update.js'; |
| 147 | ++import { AbstractUpdateService, createUpdateURL} from './abstractUpdateService.js'; |
| 148 | ++import * as semver from 'semver'; |
| 149 | + |
| 150 | +@@ -42,5 +42,9 @@ function getUpdateType(): UpdateType { |
| 151 | + if (typeof _updateType === 'undefined') { |
| 152 | +- _updateType = fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe')) |
| 153 | +- ? UpdateType.Setup |
| 154 | +- : UpdateType.Archive; |
| 155 | ++ if (fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe'))) { |
| 156 | ++ _updateType = UpdateType.Setup; |
| 157 | ++ } else if (path.basename(path.normalize(path.join(process.execPath, '..', '..'))) === 'Program Files') { |
| 158 | ++ _updateType = UpdateType.WindowsInstaller; |
| 159 | ++ } else { |
| 160 | ++ _updateType = UpdateType.Archive; |
| 161 | ++ } |
| 162 | + } |
| 163 | +@@ -63,2 +67,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 164 | + @IConfigurationService configurationService: IConfigurationService, |
| 165 | ++ // @ts-expect-error |
| 166 | + @ITelemetryService private readonly telemetryService: ITelemetryService, |
| 167 | +@@ -102,11 +107,21 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 168 | + protected buildUpdateFeedUrl(quality: string): string | undefined { |
| 169 | +- let platform = `win32-${process.arch}`; |
| 170 | +- |
| 171 | +- if (getUpdateType() === UpdateType.Archive) { |
| 172 | +- platform += '-archive'; |
| 173 | +- } else if (this.productService.target === 'user') { |
| 174 | +- platform += '-user'; |
| 175 | ++ let target: Target; |
| 176 | ++ |
| 177 | ++ switch (getUpdateType()) { |
| 178 | ++ case UpdateType.Archive: |
| 179 | ++ target = "archive" |
| 180 | ++ break; |
| 181 | ++ case UpdateType.WindowsInstaller: |
| 182 | ++ target = "msi" |
| 183 | ++ break; |
| 184 | ++ default: |
| 185 | ++ if (this.productService.target === 'user') { |
| 186 | ++ target = "user" |
| 187 | ++ } |
| 188 | ++ else { |
| 189 | ++ target = "system" |
| 190 | ++ } |
| 191 | + } |
| 192 | + |
| 193 | +- return createUpdateURL(platform, quality, this.productService); |
| 194 | ++ return createUpdateURL(this.productService, quality, process.platform, process.arch, target); |
| 195 | + } |
| 196 | +@@ -126,4 +141,10 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 197 | + if (!update || !update.url || !update.version || !update.productVersion) { |
| 198 | +- this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); |
| 199 | ++ this.setState(State.Idle(updateType)); |
| 200 | ++ return Promise.resolve(null); |
| 201 | ++ } |
| 202 | ++ |
| 203 | ++ const fetchedVersion = update.productVersion.replace(/(\d+\.\d+\.\d+)(?:\.(\d+))(\-\w+)?/, '$1$3+$2'); |
| 204 | ++ const currentVersion = `${this.productService.version}+${this.productService.release}`; |
| 205 | + |
| 206 | ++ if(semver.compareBuild(currentVersion, fetchedVersion) >= 0) { |
| 207 | + this.setState(State.Idle(updateType)); |
| 208 | +@@ -158,3 +179,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 209 | + |
| 210 | +- const fastUpdatesEnabled = this.configurationService.getValue('update.enableWindowsBackgroundUpdates'); |
| 211 | ++ const fastUpdatesEnabled = getUpdateType() == UpdateType.Setup && this.configurationService.getValue('update.enableWindowsBackgroundUpdates'); |
| 212 | + if (fastUpdatesEnabled) { |
| 213 | +@@ -170,3 +191,2 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 214 | + .then(undefined, err => { |
| 215 | +- this.telemetryService.publicLog2<{ messageHash: string }, UpdateErrorClassification>('update:error', { messageHash: String(hash(String(err))) }); |
| 216 | + this.logService.error(err); |
| 217 | +@@ -254,6 +274,14 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun |
| 218 | + } else { |
| 219 | +- spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { |
| 220 | +- detached: true, |
| 221 | +- stdio: ['ignore', 'ignore', 'ignore'] |
| 222 | +- }); |
| 223 | ++ const type = getUpdateType(); |
| 224 | ++ if (type == UpdateType.WindowsInstaller) { |
| 225 | ++ spawn('msiexec.exe', ['/i', this.availableUpdate.packagePath], { |
| 226 | ++ detached: true, |
| 227 | ++ stdio: ['ignore', 'ignore', 'ignore'] |
| 228 | ++ }); |
| 229 | ++ } else { |
| 230 | ++ spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], { |
| 231 | ++ detached: true, |
| 232 | ++ stdio: ['ignore', 'ignore', 'ignore'] |
| 233 | ++ }); |
| 234 | ++ } |
| 235 | + } |
0 commit comments