version-1-update.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 48d0d86..d16dce7 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. -export function createUpdateURL(platform: string, quality: string, productService: IProductService): string {
  60. - return `${productService.updateUrl}/api/update/${platform}/${quality}/${productService.commit}`;
  61. +export function createUpdateURL(productService: IProductService, quality: string, platform: Platform, architecture: Architecture, target?: Target): string {
  62. + if (target) {
  63. + return `${productService.updateUrl}/${quality}/${platform}/${architecture}/${target}/latest.json`;
  64. + } else {
  65. + return `${productService.updateUrl}/${quality}/${platform}/${architecture}/latest.json`;
  66. + }
  67. }
  68. @@ -203,3 +207,3 @@ export abstract class AbstractUpdateService implements IUpdateService {
  69. - if (mode === 'none') {
  70. + if (mode === 'none' || mode === 'manual') {
  71. return false;
  72. diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts
  73. index b78ebc5..a4a3b1d 100644
  74. --- a/src/vs/platform/update/electron-main/updateService.darwin.ts
  75. +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts
  76. @@ -15,3 +15,3 @@ import { ILogService } from '../../log/common/log.js';
  77. import { IProductService } from '../../product/common/productService.js';
  78. -import { IRequestService } from '../../request/common/request.js';
  79. +import { IRequestService, asJson } from '../../request/common/request.js';
  80. import { ITelemetryService } from '../../telemetry/common/telemetry.js';
  81. @@ -19,2 +19,4 @@ import { IUpdate, State, StateType, UpdateType } from '../common/update.js';
  82. import { AbstractUpdateService, createUpdateURL, UpdateErrorClassification } from './abstractUpdateService.js';
  83. +import { CancellationToken } from '../../../base/common/cancellation.js';
  84. +import * as semver from 'semver';
  85. @@ -76,17 +78,3 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau
  86. protected buildUpdateFeedUrl(quality: string): string | undefined {
  87. - let assetID: string;
  88. - if (!this.productService.darwinUniversalAssetId) {
  89. - assetID = process.arch === 'x64' ? 'darwin' : 'darwin-arm64';
  90. - } else {
  91. - assetID = this.productService.darwinUniversalAssetId;
  92. - }
  93. - const url = createUpdateURL(assetID, quality, this.productService);
  94. - try {
  95. - electron.autoUpdater.setFeedURL({ url });
  96. - } catch (e) {
  97. - // application is very likely not signed
  98. - this.logService.error('Failed to set update feed URL', e);
  99. - return undefined;
  100. - }
  101. - return url;
  102. + return createUpdateURL(this.productService, quality, process.platform, process.arch);
  103. }
  104. @@ -100,5 +88,30 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau
  105. - const url = explicit ? this.url : `${this.url}?bg=true`;
  106. - electron.autoUpdater.setFeedURL({ url });
  107. - electron.autoUpdater.checkForUpdates();
  108. + this.requestService.request({ url: this.url }, CancellationToken.None)
  109. + .then<IUpdate | null>(asJson)
  110. + .then(update => {
  111. + if (!update || !update.url || !update.version || !update.productVersion) {
  112. + this.setState(State.Idle(UpdateType.Setup));
  113. +
  114. + return Promise.resolve(null);
  115. + }
  116. +
  117. + const fetchedVersion = /\d+\.\d+\.\d+\.\d+/.test(update.productVersion) ? update.productVersion.replace(/(\d+\.\d+\.\d+)\.\d+(\-\w+)?/, '$1$2') : update.productVersion.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  118. + const currentVersion = this.productService.version.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  119. +
  120. + if(semver.compareBuild(currentVersion, fetchedVersion) >= 0) {
  121. + this.setState(State.Idle(UpdateType.Setup));
  122. + }
  123. + else {
  124. + electron.autoUpdater.setFeedURL({ url: this.url! });
  125. + electron.autoUpdater.checkForUpdates();
  126. + }
  127. +
  128. + return Promise.resolve(null);
  129. + })
  130. + .then(undefined, err => {
  131. + this.logService.error(err);
  132. + // only show message when explicitly checking for updates
  133. + const message: string | undefined = explicit ? (err.message || err) : undefined;
  134. + this.setState(State.Idle(UpdateType.Setup, message));
  135. + });
  136. }
  137. diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts
  138. index 8550ace..c2fddcb 100644
  139. --- a/src/vs/platform/update/electron-main/updateService.linux.ts
  140. +++ b/src/vs/platform/update/electron-main/updateService.linux.ts
  141. @@ -15,2 +15,3 @@ import { AvailableForDownload, IUpdate, State, UpdateType } from '../common/upda
  142. import { AbstractUpdateService, createUpdateURL } from './abstractUpdateService.js';
  143. +import * as semver from 'semver';
  144. @@ -31,3 +32,3 @@ export class LinuxUpdateService extends AbstractUpdateService {
  145. protected buildUpdateFeedUrl(quality: string): string {
  146. - return createUpdateURL(`linux-${process.arch}`, quality, this.productService);
  147. + return createUpdateURL(this.productService, quality, process.platform, process.arch);
  148. }
  149. @@ -39,6 +40,5 @@ export class LinuxUpdateService extends AbstractUpdateService {
  150. - const url = explicit ? this.url : `${this.url}?bg=true`;
  151. this.setState(State.CheckingForUpdates(explicit));
  152. - this.requestService.request({ url }, CancellationToken.None)
  153. + this.requestService.request({ url: this.url }, CancellationToken.None)
  154. .then<IUpdate | null>(asJson)
  155. @@ -47,5 +47,17 @@ export class LinuxUpdateService extends AbstractUpdateService {
  156. this.setState(State.Idle(UpdateType.Archive));
  157. - } else {
  158. +
  159. + return Promise.resolve(null);
  160. + }
  161. +
  162. + const fetchedVersion = /\d+\.\d+\.\d+\.\d+/.test(update.productVersion) ? update.productVersion.replace(/(\d+\.\d+\.\d+)\.\d+(\-\w+)?/, '$1$2') : update.productVersion.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  163. + const currentVersion = this.productService.version.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  164. +
  165. + if(semver.compareBuild(currentVersion, fetchedVersion) >= 0) {
  166. + this.setState(State.Idle(UpdateType.Archive));
  167. + }
  168. + else {
  169. this.setState(State.AvailableForDownload(update));
  170. }
  171. +
  172. + return Promise.resolve(null);
  173. })
  174. diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts
  175. index 8f92a3e..020e690 100644
  176. --- a/src/vs/platform/update/electron-main/updateService.win32.ts
  177. +++ b/src/vs/platform/update/electron-main/updateService.win32.ts
  178. @@ -11,3 +11,2 @@ import { CancellationToken } from '../../../base/common/cancellation.js';
  179. import { memoize } from '../../../base/common/decorators.js';
  180. -import { hash } from '../../../base/common/hash.js';
  181. import * as path from '../../../base/common/path.js';
  182. @@ -25,4 +24,5 @@ import { asJson, IRequestService } from '../../request/common/request.js';
  183. import { ITelemetryService } from '../../telemetry/common/telemetry.js';
  184. -import { AvailableForDownload, DisablementReason, IUpdate, State, StateType, UpdateType } from '../common/update.js';
  185. -import { AbstractUpdateService, createUpdateURL, UpdateErrorClassification } from './abstractUpdateService.js';
  186. +import { AvailableForDownload, DisablementReason, IUpdate, State, StateType, Target, UpdateType } from '../common/update.js';
  187. +import { AbstractUpdateService, createUpdateURL} from './abstractUpdateService.js';
  188. +import * as semver from 'semver';
  189. @@ -42,5 +42,9 @@ function getUpdateType(): UpdateType {
  190. if (typeof _updateType === 'undefined') {
  191. - _updateType = fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe'))
  192. - ? UpdateType.Setup
  193. - : UpdateType.Archive;
  194. + if (fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe'))) {
  195. + _updateType = UpdateType.Setup;
  196. + } else if (path.basename(path.normalize(path.join(process.execPath, '..', '..'))) === 'Program Files') {
  197. + _updateType = UpdateType.WindowsInstaller;
  198. + } else {
  199. + _updateType = UpdateType.Archive;
  200. + }
  201. }
  202. @@ -63,2 +67,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  203. @IConfigurationService configurationService: IConfigurationService,
  204. + // @ts-expect-error
  205. @ITelemetryService private readonly telemetryService: ITelemetryService,
  206. @@ -102,11 +107,21 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  207. protected buildUpdateFeedUrl(quality: string): string | undefined {
  208. - let platform = `win32-${process.arch}`;
  209. -
  210. - if (getUpdateType() === UpdateType.Archive) {
  211. - platform += '-archive';
  212. - } else if (this.productService.target === 'user') {
  213. - platform += '-user';
  214. + let target: Target;
  215. +
  216. + switch (getUpdateType()) {
  217. + case UpdateType.Archive:
  218. + target = "archive"
  219. + break;
  220. + case UpdateType.WindowsInstaller:
  221. + target = "msi"
  222. + break;
  223. + default:
  224. + if (this.productService.target === 'user') {
  225. + target = "user"
  226. + }
  227. + else {
  228. + target = "system"
  229. + }
  230. }
  231. - return createUpdateURL(platform, quality, this.productService);
  232. + return createUpdateURL(this.productService, quality, process.platform, process.arch, target);
  233. }
  234. @@ -131,2 +146,10 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  235. + const fetchedVersion = /\d+\.\d+\.\d+\.\d+/.test(update.productVersion) ? update.productVersion.replace(/(\d+\.\d+\.\d+)\.\d+(\-\w+)?/, '$1$2') : update.productVersion.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  236. + const currentVersion = this.productService.version.replace(/(\d+\.\d+\.)0+(\d+)(\-\w+)?/, '$1$2$3')
  237. +
  238. + if(semver.compareBuild(currentVersion, fetchedVersion) >= 0) {
  239. + this.setState(State.Idle(updateType));
  240. + return Promise.resolve(null);
  241. + }
  242. +
  243. if (updateType === UpdateType.Archive) {
  244. @@ -157,3 +180,3 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  245. - const fastUpdatesEnabled = this.configurationService.getValue('update.enableWindowsBackgroundUpdates');
  246. + const fastUpdatesEnabled = getUpdateType() == UpdateType.Setup && this.configurationService.getValue('update.enableWindowsBackgroundUpdates');
  247. if (fastUpdatesEnabled) {
  248. @@ -169,3 +192,2 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  249. .then(undefined, err => {
  250. - this.telemetryService.publicLog2<{ messageHash: string }, UpdateErrorClassification>('update:error', { messageHash: String(hash(String(err))) });
  251. this.logService.error(err);
  252. @@ -253,6 +275,14 @@ export class Win32UpdateService extends AbstractUpdateService implements IRelaun
  253. } else {
  254. - spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], {
  255. - detached: true,
  256. - stdio: ['ignore', 'ignore', 'ignore']
  257. - });
  258. + const type = getUpdateType();
  259. + if (type == UpdateType.WindowsInstaller) {
  260. + spawn('msiexec.exe', ['/i', this.availableUpdate.packagePath], {
  261. + detached: true,
  262. + stdio: ['ignore', 'ignore', 'ignore']
  263. + });
  264. + } else {
  265. + spawn(this.availableUpdate.packagePath, ['/silent', '/log', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], {
  266. + detached: true,
  267. + stdio: ['ignore', 'ignore', 'ignore']
  268. + });
  269. + }
  270. }