mirror of https://github.com/coder/code-server.git
Implement update service
This commit is contained in:
parent
01a9ab332e
commit
f5a6f14ade
|
@ -74,7 +74,7 @@ function build-code-server() {
|
||||||
cd "${buildPath}" && yarn --production --force --build-from-source
|
cd "${buildPath}" && yarn --production --force --build-from-source
|
||||||
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
|
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
|
||||||
|
|
||||||
local packageJson="{\"codeServerVersion\": \"${codeServerVersion}\"}"
|
local packageJson="{\"codeServerVersion\": \"${codeServerVersion}-vsc${vscodeVersion}\"}"
|
||||||
cp -r "${sourcePath}/.build/extensions" "${buildPath}"
|
cp -r "${sourcePath}/.build/extensions" "${buildPath}"
|
||||||
node "${rootPath}/scripts/merge.js" "${sourcePath}/package.json" "${rootPath}/scripts/package.json" "${buildPath}/package.json" "${packageJson}"
|
node "${rootPath}/scripts/merge.js" "${sourcePath}/package.json" "${rootPath}/scripts/package.json" "${buildPath}/package.json" "${packageJson}"
|
||||||
node "${rootPath}/scripts/merge.js" "${sourcePath}/.build/product.json" "${rootPath}/scripts/product.json" "${buildPath}/product.json"
|
node "${rootPath}/scripts/merge.js" "${sourcePath}/.build/product.json" "${rootPath}/scripts/product.json" "${buildPath}/product.json"
|
||||||
|
|
|
@ -593,6 +593,31 @@ index 9f68b645b6..f0cae7111d 100644
|
||||||
setLevel(level: LogLevel): void {
|
setLevel(level: LogLevel): void {
|
||||||
this.channel.call('setLevel', level);
|
this.channel.call('setLevel', level);
|
||||||
}
|
}
|
||||||
|
diff --git a/src/vs/platform/product/browser/productService.ts b/src/vs/platform/product/browser/productService.ts
|
||||||
|
index 084144d009..d91176c9cd 100644
|
||||||
|
--- a/src/vs/platform/product/browser/productService.ts
|
||||||
|
+++ b/src/vs/platform/product/browser/productService.ts
|
||||||
|
@@ -17,7 +17,7 @@ export class ProductService implements IProductService {
|
||||||
|
|
||||||
|
_serviceBrand: ServiceIdentifier<IProductService>;
|
||||||
|
|
||||||
|
- get version(): string { return '1.35.0'; }
|
||||||
|
+ get version(): string { return this.productConfiguration ? (this.productConfiguration as any).version : 'development'; }
|
||||||
|
|
||||||
|
get commit(): string | undefined { return undefined; }
|
||||||
|
|
||||||
|
diff --git a/src/vs/platform/product/node/package.ts b/src/vs/platform/product/node/package.ts
|
||||||
|
index d39c5877d6..c189d6f19f 100644
|
||||||
|
--- a/src/vs/platform/product/node/package.ts
|
||||||
|
+++ b/src/vs/platform/product/node/package.ts
|
||||||
|
@@ -9,6 +9,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||||
|
export interface IPackageConfiguration {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
+ codeServerVersion: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootPath = path.dirname(getPathFromAmdModule(require, ''));
|
||||||
diff --git a/src/vs/platform/remote/browser/browserWebSocketFactory.ts b/src/vs/platform/remote/browser/browserWebSocketFactory.ts
|
diff --git a/src/vs/platform/remote/browser/browserWebSocketFactory.ts b/src/vs/platform/remote/browser/browserWebSocketFactory.ts
|
||||||
index 6d9ecbcf5a..1b3499dddf 100644
|
index 6d9ecbcf5a..1b3499dddf 100644
|
||||||
--- a/src/vs/platform/remote/browser/browserWebSocketFactory.ts
|
--- a/src/vs/platform/remote/browser/browserWebSocketFactory.ts
|
||||||
|
@ -673,6 +698,98 @@ index 8e1b68eb36..2b6a0d5b15 100644
|
||||||
+ return true;
|
+ return true;
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
|
diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/platform/update/electron-browser/updateService.ts
|
||||||
|
index 023ea3ea7d..455df76ee3 100644
|
||||||
|
--- a/src/vs/platform/update/electron-browser/updateService.ts
|
||||||
|
+++ b/src/vs/platform/update/electron-browser/updateService.ts
|
||||||
|
@@ -6,8 +6,9 @@
|
||||||
|
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
import { IUpdateService, State } from 'vs/platform/update/common/update';
|
||||||
|
-import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||||
|
+// import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||||
|
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
|
|
||||||
|
export class UpdateService implements IUpdateService {
|
||||||
|
|
||||||
|
@@ -21,8 +22,11 @@ export class UpdateService implements IUpdateService {
|
||||||
|
|
||||||
|
private channel: IChannel;
|
||||||
|
|
||||||
|
- constructor(@IMainProcessService mainProcessService: IMainProcessService) {
|
||||||
|
- this.channel = mainProcessService.getChannel('update');
|
||||||
|
+ constructor(
|
||||||
|
+ // @IMainProcessService mainProcessService: IMainProcessService
|
||||||
|
+ @IRemoteAgentService remoteAgentService: IRemoteAgentService
|
||||||
|
+ ) {
|
||||||
|
+ this.channel = remoteAgentService.getConnection()!.getChannel('update');
|
||||||
|
|
||||||
|
// always set this._state as the state changes
|
||||||
|
this.onStateChange(state => this._state = state);
|
||||||
|
diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts
|
||||||
|
index fcca3cbfb9..101f3d33c9 100644
|
||||||
|
--- a/src/vs/platform/update/electron-main/abstractUpdateService.ts
|
||||||
|
+++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts
|
||||||
|
@@ -6,7 +6,7 @@
|
||||||
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
import { timeout } from 'vs/base/common/async';
|
||||||
|
import { IConfigurationService, getMigratedSettingValue } from 'vs/platform/configuration/common/configuration';
|
||||||
|
-import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||||
|
+// import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||||
|
import product from 'vs/platform/product/node/product';
|
||||||
|
import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
@@ -40,7 +40,8 @@ export abstract class AbstractUpdateService implements IUpdateService {
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
- @ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||||
|
+ _placeholder: any, // To prevent errors from the extending classes.
|
||||||
|
+ // @ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||||
|
@IConfigurationService protected configurationService: IConfigurationService,
|
||||||
|
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||||
|
@IRequestService protected requestService: IRequestService,
|
||||||
|
@@ -51,7 +52,7 @@ export abstract class AbstractUpdateService implements IUpdateService {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!product.updateUrl || !product.commit) {
|
||||||
|
+ if (/*!product.updateUrl || */!product.commit) {
|
||||||
|
this.logService.info('update#ctor - updates are disabled as there is no update URL');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -82,7 +83,7 @@ export abstract class AbstractUpdateService implements IUpdateService {
|
||||||
|
}
|
||||||
|
|
||||||
|
private getProductQuality(updateMode: string): string | undefined {
|
||||||
|
- return updateMode === 'none' ? undefined : product.quality;
|
||||||
|
+ return updateMode === 'none' ? undefined : 'quality';
|
||||||
|
}
|
||||||
|
|
||||||
|
private scheduleCheckForUpdates(delay = 60 * 60 * 1000): Promise<void> {
|
||||||
|
@@ -141,15 +142,15 @@ export abstract class AbstractUpdateService implements IUpdateService {
|
||||||
|
|
||||||
|
this.logService.trace('update#quitAndInstall(): before lifecycle quit()');
|
||||||
|
|
||||||
|
- this.lifecycleService.quit(true /* from update */).then(vetod => {
|
||||||
|
- this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`);
|
||||||
|
- if (vetod) {
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
+ // this.quit(true /* from update */).then(vetod => {
|
||||||
|
+ // this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`);
|
||||||
|
+ // if (vetod) {
|
||||||
|
+ // return;
|
||||||
|
+ // }
|
||||||
|
|
||||||
|
this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()');
|
||||||
|
this.doQuitAndInstall();
|
||||||
|
- });
|
||||||
|
+ // });
|
||||||
|
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts
|
diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts
|
||||||
index 8bace46843..b261f40493 100644
|
index 8bace46843..b261f40493 100644
|
||||||
--- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts
|
--- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts
|
||||||
|
@ -801,7 +918,7 @@ index 1986fb6642..70b0c789e3 100644
|
||||||
|
|
||||||
const payload = await this.resolveWorkspaceInitializationPayload();
|
const payload = await this.resolveWorkspaceInitializationPayload();
|
||||||
diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts
|
diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts
|
||||||
index b253e573ae..94b2b7f287 100644
|
index b253e573ae..164e50c3d1 100644
|
||||||
--- a/src/vs/workbench/browser/web.simpleservices.ts
|
--- a/src/vs/workbench/browser/web.simpleservices.ts
|
||||||
+++ b/src/vs/workbench/browser/web.simpleservices.ts
|
+++ b/src/vs/workbench/browser/web.simpleservices.ts
|
||||||
@@ -53,6 +53,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
@@ -53,6 +53,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||||
|
@ -910,6 +1027,15 @@ index b253e573ae..94b2b7f287 100644
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
@@ -714,7 +750,7 @@ export class SimpleUpdateService implements IUpdateService {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-registerSingleton(IUpdateService, SimpleUpdateService);
|
||||||
|
+// registerSingleton(IUpdateService, SimpleUpdateService);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
@@ -888,7 +924,7 @@ export class SimpleWindowService extends Disposable implements IWindowService {
|
@@ -888,7 +924,7 @@ export class SimpleWindowService extends Disposable implements IWindowService {
|
||||||
for (let i = 0; i < _uris.length; i++) {
|
for (let i = 0; i < _uris.length; i++) {
|
||||||
const uri = _uris[i];
|
const uri = _uris[i];
|
||||||
|
@ -1470,6 +1596,297 @@ index 4d8a5d6907..b464d5276f 100644
|
||||||
template.decorationIcon.title = resource.decorations.tooltip || '';
|
template.decorationIcon.title = resource.decorations.tooltip || '';
|
||||||
} else {
|
} else {
|
||||||
template.decorationIcon.style.display = 'none';
|
template.decorationIcon.style.display = 'none';
|
||||||
|
diff --git a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts
|
||||||
|
index e39fa57979..d0548847a4 100644
|
||||||
|
--- a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts
|
||||||
|
+++ b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts
|
||||||
|
@@ -4,26 +4,26 @@
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import 'vs/platform/update/node/update.config.contribution';
|
||||||
|
-import * as platform from 'vs/base/common/platform';
|
||||||
|
+// import * as platform from 'vs/base/common/platform';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
|
-import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||||
|
-import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||||
|
-import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update';
|
||||||
|
+// import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||||
|
+// import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||||
|
+import { /*ShowCurrentReleaseNotesAction, ProductContribution, */UpdateContribution/*, Win3264BitContribution */} from './update';
|
||||||
|
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
|
|
||||||
|
const workbench = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||||
|
|
||||||
|
-workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored);
|
||||||
|
+/* workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored);
|
||||||
|
|
||||||
|
if (platform.isWindows) {
|
||||||
|
if (process.arch === 'ia32') {
|
||||||
|
workbench.registerWorkbenchContribution(Win3264BitContribution, LifecyclePhase.Restored);
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
+} */
|
||||||
|
|
||||||
|
workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored);
|
||||||
|
|
||||||
|
// Editor
|
||||||
|
-Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
|
||||||
|
- .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes');
|
||||||
|
+// Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
|
||||||
|
+// .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes');
|
||||||
|
diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts
|
||||||
|
index 7078a1bb2f..94b1ce31a7 100644
|
||||||
|
--- a/src/vs/workbench/contrib/update/electron-browser/update.ts
|
||||||
|
+++ b/src/vs/workbench/contrib/update/electron-browser/update.ts
|
||||||
|
@@ -7,32 +7,33 @@ import * as nls from 'vs/nls';
|
||||||
|
import severity from 'vs/base/common/severity';
|
||||||
|
import { Action } from 'vs/base/common/actions';
|
||||||
|
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
-import pkg from 'vs/platform/product/node/package';
|
||||||
|
-import product from 'vs/platform/product/node/product';
|
||||||
|
-import { URI } from 'vs/base/common/uri';
|
||||||
|
+// import pkg from 'vs/platform/product/node/package';
|
||||||
|
+// import product from 'vs/platform/product/node/product';
|
||||||
|
+// import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
|
||||||
|
-import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
+// import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
|
||||||
|
-import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
+// import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
|
import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update';
|
||||||
|
-import * as semver from 'semver';
|
||||||
|
-import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
+// import * as semver from 'semver';
|
||||||
|
+// import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { INotificationService, INotificationHandle, Severity } from 'vs/platform/notification/common/notification';
|
||||||
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
-import { ReleaseNotesManager } from './releaseNotesEditor';
|
||||||
|
-import { isWindows } from 'vs/base/common/platform';
|
||||||
|
-import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
+// import { ReleaseNotesManager } from './releaseNotesEditor';
|
||||||
|
+// import { isWindows } from 'vs/base/common/platform';
|
||||||
|
+// import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||||
|
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||||
|
import { FalseContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||||
|
+import { IProductService } from 'vs/platform/product/common/product';
|
||||||
|
|
||||||
|
const CONTEXT_UPDATE_STATE = new RawContextKey<string>('updateState', StateType.Uninitialized);
|
||||||
|
|
||||||
|
-let releaseNotesManager: ReleaseNotesManager | undefined = undefined;
|
||||||
|
+/*let releaseNotesManager: ReleaseNotesManager | undefined = undefined;
|
||||||
|
|
||||||
|
function showReleaseNotes(instantiationService: IInstantiationService, version: string) {
|
||||||
|
if (!releaseNotesManager) {
|
||||||
|
@@ -150,7 +151,7 @@ export class ProductContribution implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
+} */
|
||||||
|
|
||||||
|
class NeverShowAgain {
|
||||||
|
|
||||||
|
@@ -175,7 +176,7 @@ class NeverShowAgain {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-export class Win3264BitContribution implements IWorkbenchContribution {
|
||||||
|
+/* export class Win3264BitContribution implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
private static readonly KEY = 'update/win32-64bits';
|
||||||
|
private static readonly URL = 'https://code.visualstudio.com/updates/v1_15#_windows-64-bit';
|
||||||
|
@@ -214,7 +215,7 @@ export class Win3264BitContribution implements IWorkbenchContribution {
|
||||||
|
{ sticky: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
+} */
|
||||||
|
|
||||||
|
export class UpdateContribution extends Disposable implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
@@ -224,7 +225,8 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
|
- @IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
+ // @IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
+ @IProductService private readonly productService: IProductService,
|
||||||
|
@INotificationService private readonly notificationService: INotificationService,
|
||||||
|
@IDialogService private readonly dialogService: IDialogService,
|
||||||
|
@IUpdateService private readonly updateService: IUpdateService,
|
||||||
|
@@ -247,7 +249,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
updated since 5 days.
|
||||||
|
*/
|
||||||
|
|
||||||
|
- const currentVersion = product.commit;
|
||||||
|
+ const currentVersion = this.productService.commit;
|
||||||
|
const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL);
|
||||||
|
|
||||||
|
// if current version != stored version, clear both fields
|
||||||
|
@@ -292,9 +294,9 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
let clazz: string | undefined;
|
||||||
|
|
||||||
|
if (state.type === StateType.AvailableForDownload || state.type === StateType.Downloaded || state.type === StateType.Ready) {
|
||||||
|
- badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", product.nameShort));
|
||||||
|
+ badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameLong));
|
||||||
|
} else if (state.type === StateType.CheckingForUpdates || state.type === StateType.Downloading || state.type === StateType.Updating) {
|
||||||
|
- badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", product.nameShort));
|
||||||
|
+ badge = new ProgressBadge(() => nls.localize('updateIsReady', "New {0} update available.", this.productService.nameLong));
|
||||||
|
clazz = 'progress-badge';
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -333,21 +335,21 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
|
||||||
|
this.notificationService.prompt(
|
||||||
|
severity.Info,
|
||||||
|
- nls.localize('thereIsUpdateAvailable', "There is an available update."),
|
||||||
|
+ nls.localize('updateAvailable', "There's an update available: {0} {1}", this.productService.nameLong, update.productVersion),
|
||||||
|
[{
|
||||||
|
- label: nls.localize('download update', "Download Update"),
|
||||||
|
+ label: nls.localize('installUpdate', "Install Update"),
|
||||||
|
run: () => this.updateService.downloadUpdate()
|
||||||
|
}, {
|
||||||
|
label: nls.localize('later', "Later"),
|
||||||
|
run: () => { }
|
||||||
|
- }, {
|
||||||
|
+ }/*, {
|
||||||
|
label: nls.localize('releaseNotes', "Release Notes"),
|
||||||
|
run: () => {
|
||||||
|
const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion);
|
||||||
|
action.run();
|
||||||
|
action.dispose();
|
||||||
|
}
|
||||||
|
- }],
|
||||||
|
+ }*/],
|
||||||
|
{ sticky: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@@ -360,30 +362,30 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
|
||||||
|
this.notificationService.prompt(
|
||||||
|
severity.Info,
|
||||||
|
- nls.localize('updateAvailable', "There's an update available: {0} {1}", product.nameLong, update.productVersion),
|
||||||
|
+ nls.localize('updateAvailable', "There's an update available: {0} {1}", this.productService.nameLong, update.productVersion),
|
||||||
|
[{
|
||||||
|
label: nls.localize('installUpdate', "Install Update"),
|
||||||
|
run: () => this.updateService.applyUpdate()
|
||||||
|
}, {
|
||||||
|
label: nls.localize('later', "Later"),
|
||||||
|
run: () => { }
|
||||||
|
- }, {
|
||||||
|
+ }/*, {
|
||||||
|
label: nls.localize('releaseNotes', "Release Notes"),
|
||||||
|
run: () => {
|
||||||
|
const action = this.instantiationService.createInstance(ShowReleaseNotesAction, update.productVersion);
|
||||||
|
action.run();
|
||||||
|
action.dispose();
|
||||||
|
}
|
||||||
|
- }],
|
||||||
|
+ }*/],
|
||||||
|
{ sticky: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// windows fast updates
|
||||||
|
private onUpdateUpdating(update: IUpdate): void {
|
||||||
|
- if (isWindows && product.target === 'user') {
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
+ // if (isWindows && product.target === 'user') {
|
||||||
|
+ // return;
|
||||||
|
+ // }
|
||||||
|
|
||||||
|
// windows fast updates (target === system)
|
||||||
|
const neverShowAgain = new NeverShowAgain('update/win32-fast-updates', this.storageService);
|
||||||
|
@@ -394,7 +396,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
|
||||||
|
const handle = this.notificationService.prompt(
|
||||||
|
severity.Info,
|
||||||
|
- nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", product.nameLong, update.productVersion),
|
||||||
|
+ nls.localize('updateInstalling', "{0} {1} is being installed in the background; we'll let you know when it's done.", this.productService.nameLong, update.productVersion),
|
||||||
|
[{
|
||||||
|
label: nls.localize('neveragain', "Don't Show Again"),
|
||||||
|
isSecondary: true,
|
||||||
|
@@ -408,20 +410,23 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
|
||||||
|
// windows and mac
|
||||||
|
private onUpdateReady(update: IUpdate): void {
|
||||||
|
- if (!(isWindows && product.target !== 'user') && !this.shouldShowNotification()) {
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
+ // if (!(isWindows && product.target !== 'user') && !this.shouldShowNotification()) {
|
||||||
|
+ // return;
|
||||||
|
+ // }
|
||||||
|
|
||||||
|
const actions = [{
|
||||||
|
label: nls.localize('updateNow', "Update Now"),
|
||||||
|
- run: () => this.updateService.quitAndInstall()
|
||||||
|
+ run: () => {
|
||||||
|
+ this.updateService.quitAndInstall();
|
||||||
|
+ window.location.reload();
|
||||||
|
+ }
|
||||||
|
}, {
|
||||||
|
label: nls.localize('later', "Later"),
|
||||||
|
run: () => { }
|
||||||
|
}];
|
||||||
|
|
||||||
|
// TODO@joao check why snap updates send `update` as falsy
|
||||||
|
- if (update.productVersion) {
|
||||||
|
+ /*if (update.productVersion) {
|
||||||
|
actions.push({
|
||||||
|
label: nls.localize('releaseNotes', "Release Notes"),
|
||||||
|
run: () => {
|
||||||
|
@@ -430,19 +435,19 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
action.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
- }
|
||||||
|
+ }*/
|
||||||
|
|
||||||
|
// windows user fast updates and mac
|
||||||
|
this.notificationService.prompt(
|
||||||
|
severity.Info,
|
||||||
|
- nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", product.nameLong),
|
||||||
|
+ nls.localize('updateAvailableAfterRestart', "Restart {0} to apply the latest update.", this.productService.nameLong),
|
||||||
|
actions,
|
||||||
|
{ sticky: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldShowNotification(): boolean {
|
||||||
|
- const currentVersion = product.commit;
|
||||||
|
+ const currentVersion = this.productService.commit;
|
||||||
|
const currentMillis = new Date().getTime();
|
||||||
|
const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.GLOBAL);
|
||||||
|
|
||||||
|
@@ -485,7 +490,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
group: '5_update',
|
||||||
|
command: {
|
||||||
|
id: 'update.downloadNow',
|
||||||
|
- title: nls.localize('download update', "Download Update")
|
||||||
|
+ title: nls.localize('installUpdate...', "Install Update...")
|
||||||
|
},
|
||||||
|
when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.AvailableForDownload)
|
||||||
|
});
|
||||||
|
@@ -522,7 +527,10 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
||||||
|
when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating)
|
||||||
|
});
|
||||||
|
|
||||||
|
- CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall());
|
||||||
|
+ CommandsRegistry.registerCommand('update.restart', () => {
|
||||||
|
+ this.updateService.quitAndInstall();
|
||||||
|
+ window.location.reload();
|
||||||
|
+ });
|
||||||
|
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
|
||||||
|
group: '5_update',
|
||||||
|
command: {
|
||||||
diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js
|
diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js
|
||||||
index a6be033e07..a4dcb7357a 100644
|
index a6be033e07..a4dcb7357a 100644
|
||||||
--- a/src/vs/workbench/contrib/webview/browser/pre/main.js
|
--- a/src/vs/workbench/contrib/webview/browser/pre/main.js
|
||||||
|
@ -1620,10 +2037,10 @@ index 306d58f915..58c603ad3d 100644
|
||||||
if (definition.fontCharacter || definition.fontColor) {
|
if (definition.fontCharacter || definition.fontColor) {
|
||||||
let body = '';
|
let body = '';
|
||||||
diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts
|
diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts
|
||||||
index c28adc0ad9..f76612a4d7 100644
|
index c28adc0ad9..56c86d7e39 100644
|
||||||
--- a/src/vs/workbench/workbench.web.main.ts
|
--- a/src/vs/workbench/workbench.web.main.ts
|
||||||
+++ b/src/vs/workbench/workbench.web.main.ts
|
+++ b/src/vs/workbench/workbench.web.main.ts
|
||||||
@@ -72,8 +72,8 @@ import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycle
|
@@ -72,15 +72,15 @@ import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycle
|
||||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { DialogService } from 'vs/platform/dialogs/browser/dialogService';
|
import { DialogService } from 'vs/platform/dialogs/browser/dialogService';
|
||||||
|
@ -1634,6 +2051,15 @@ index c28adc0ad9..f76612a4d7 100644
|
||||||
// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||||
// import { IProductService } from 'vs/platform/product/common/product';
|
// import { IProductService } from 'vs/platform/product/common/product';
|
||||||
// import { ProductService } from 'vs/platform/product/node/productService';
|
// import { ProductService } from 'vs/platform/product/node/productService';
|
||||||
|
// import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
|
// import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
|
||||||
|
-// import { IUpdateService } from 'vs/platform/update/common/update';
|
||||||
|
-// import { UpdateService } from 'vs/platform/update/electron-browser/updateService';
|
||||||
|
+import { IUpdateService } from 'vs/platform/update/common/update';
|
||||||
|
+import { UpdateService } from 'vs/platform/update/electron-browser/updateService';
|
||||||
|
// import { IIssueService } from 'vs/platform/issue/common/issue';
|
||||||
|
// import { IssueService } from 'vs/platform/issue/electron-browser/issueService';
|
||||||
|
// import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||||
@@ -128,7 +128,7 @@ import 'vs/workbench/services/extensions/browser/extensionService';
|
@@ -128,7 +128,7 @@ import 'vs/workbench/services/extensions/browser/extensionService';
|
||||||
// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
|
// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
|
||||||
// import 'vs/workbench/services/extensions/node/multiExtensionManagement';
|
// import 'vs/workbench/services/extensions/node/multiExtensionManagement';
|
||||||
|
@ -1643,7 +2069,7 @@ index c28adc0ad9..f76612a4d7 100644
|
||||||
// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||||
import 'vs/workbench/services/notification/common/notificationService';
|
import 'vs/workbench/services/notification/common/notificationService';
|
||||||
// import 'vs/workbench/services/window/electron-browser/windowService';
|
// import 'vs/workbench/services/window/electron-browser/windowService';
|
||||||
@@ -156,7 +156,7 @@ registerSingleton(IContextViewService, ContextViewService, true);
|
@@ -156,10 +156,10 @@ registerSingleton(IContextViewService, ContextViewService, true);
|
||||||
// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
|
// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
|
||||||
// registerSingleton(IRequestService, RequestService, true);
|
// registerSingleton(IRequestService, RequestService, true);
|
||||||
registerSingleton(ILifecycleService, BrowserLifecycleService);
|
registerSingleton(ILifecycleService, BrowserLifecycleService);
|
||||||
|
@ -1651,7 +2077,11 @@ index c28adc0ad9..f76612a4d7 100644
|
||||||
+registerSingleton(ILocalizationsService, LocalizationsService);
|
+registerSingleton(ILocalizationsService, LocalizationsService);
|
||||||
// registerSingleton(ISharedProcessService, SharedProcessService, true);
|
// registerSingleton(ISharedProcessService, SharedProcessService, true);
|
||||||
// registerSingleton(IWindowsService, WindowsService);
|
// registerSingleton(IWindowsService, WindowsService);
|
||||||
// registerSingleton(IUpdateService, UpdateService);
|
-// registerSingleton(IUpdateService, UpdateService);
|
||||||
|
+registerSingleton(IUpdateService, UpdateService);
|
||||||
|
// registerSingleton(IIssueService, IssueService);
|
||||||
|
// registerSingleton(IWorkspacesService, WorkspacesService);
|
||||||
|
// registerSingleton(IMenubarService, MenubarService);
|
||||||
@@ -194,7 +194,7 @@ import 'vs/workbench/services/files/common/workspaceWatcher';
|
@@ -194,7 +194,7 @@ import 'vs/workbench/services/files/common/workspaceWatcher';
|
||||||
import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution';
|
import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution';
|
||||||
|
|
||||||
|
@ -1674,3 +2104,12 @@ index c28adc0ad9..f76612a4d7 100644
|
||||||
|
|
||||||
// Output Panel
|
// Output Panel
|
||||||
import 'vs/workbench/contrib/output/browser/output.contribution';
|
import 'vs/workbench/contrib/output/browser/output.contribution';
|
||||||
|
@@ -318,7 +318,7 @@ import 'vs/workbench/contrib/format/browser/format.contribution';
|
||||||
|
// import 'vs/workbench/contrib/feedback/browser/feedback.contribution';
|
||||||
|
|
||||||
|
// Update
|
||||||
|
-// import 'vs/workbench/contrib/update/electron-browser/update.contribution';
|
||||||
|
+import 'vs/workbench/contrib/update/electron-browser/update.contribution';
|
||||||
|
|
||||||
|
// Surveys
|
||||||
|
// import 'vs/workbench/contrib/surveys/electron-browser/nps.contribution';
|
||||||
|
|
183
src/cli.ts
183
src/cli.ts
|
@ -1,16 +1,27 @@
|
||||||
|
import * as cp from "child_process";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
|
|
||||||
|
import { main as vsCli } from "vs/code/node/cliProcessMain";
|
||||||
import { validatePaths } from "vs/code/node/paths";
|
import { validatePaths } from "vs/code/node/paths";
|
||||||
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
|
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
|
||||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
|
||||||
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
|
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
|
||||||
|
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||||
import pkg from "vs/platform/product/node/package";
|
import pkg from "vs/platform/product/node/package";
|
||||||
import product from "vs/platform/product/node/product";
|
import product from "vs/platform/product/node/product";
|
||||||
|
|
||||||
|
import { ipcMain } from "vs/server/src/ipc";
|
||||||
|
|
||||||
|
product.extensionsGallery = {
|
||||||
|
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
|
||||||
|
itemUrl: process.env.ITEM_URL || "",
|
||||||
|
controlUrl: "",
|
||||||
|
recommendationsUrl: "",
|
||||||
|
...(product.extensionsGallery || {}),
|
||||||
|
};
|
||||||
|
|
||||||
import { MainServer } from "vs/server/src/server";
|
import { MainServer } from "vs/server/src/server";
|
||||||
import { enableExtensionTars } from "vs/server/src/tar";
|
import { enableExtensionTars } from "vs/server/src/tar";
|
||||||
import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
|
import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
|
||||||
import { main as vsCli } from "vs/code/node/cliProcessMain";
|
|
||||||
|
|
||||||
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
|
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
|
||||||
|
|
||||||
|
@ -27,12 +38,13 @@ interface Args extends ParsedArgs {
|
||||||
socket?: string;
|
socket?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The last item is _ which is like -- so our options need to come before it.
|
const getArgs = (): Args => {
|
||||||
const last = options.pop()!;
|
// The last item is _ which is like -- so our options need to come before it.
|
||||||
|
const last = options.pop()!;
|
||||||
|
|
||||||
// Remove options that won't work or don't make sense.
|
// Remove options that won't work or don't make sense.
|
||||||
let i = options.length;
|
let i = options.length;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
switch (options[i].id) {
|
switch (options[i].id) {
|
||||||
case "add":
|
case "add":
|
||||||
case "diff":
|
case "diff":
|
||||||
|
@ -51,64 +63,32 @@ while (i--) {
|
||||||
options.splice(i, 1);
|
options.splice(i, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options.push({ id: "base-path", type: "string", cat: "o", description: "Base path of the URL at which code-server is hosted (used for login redirects)." });
|
options.push({ id: "base-path", type: "string", cat: "o", description: "Base path of the URL at which code-server is hosted (used for login redirects)." });
|
||||||
options.push({ id: "cert", type: "string", cat: "o", description: "Path to certificate. If the path is omitted, both this and --cert-key will be generated." });
|
options.push({ id: "cert", type: "string", cat: "o", description: "Path to certificate. If the path is omitted, both this and --cert-key will be generated." });
|
||||||
options.push({ id: "cert-key", type: "string", cat: "o", description: "Path to the certificate's key if one was provided." });
|
options.push({ id: "cert-key", type: "string", cat: "o", description: "Path to the certificate's key if one was provided." });
|
||||||
options.push({ id: "extra-builtin-extensions-dir", type: "string", cat: "o", description: "Path to an extra builtin extension directory." });
|
options.push({ id: "extra-builtin-extensions-dir", type: "string", cat: "o", description: "Path to an extra builtin extension directory." });
|
||||||
options.push({ id: "extra-extensions-dir", type: "string", cat: "o", description: "Path to an extra user extension directory." });
|
options.push({ id: "extra-extensions-dir", type: "string", cat: "o", description: "Path to an extra user extension directory." });
|
||||||
options.push({ id: "host", type: "string", cat: "o", description: "Host for the server." });
|
options.push({ id: "host", type: "string", cat: "o", description: "Host for the server." });
|
||||||
options.push({ id: "auth", type: "string", cat: "o", description: `The type of authentication to use. ${buildAllowedMessage(AuthType)}.` });
|
options.push({ id: "auth", type: "string", cat: "o", description: `The type of authentication to use. ${buildAllowedMessage(AuthType)}.` });
|
||||||
options.push({ id: "open", type: "boolean", cat: "o", description: "Open in the browser on startup." });
|
options.push({ id: "open", type: "boolean", cat: "o", description: "Open in the browser on startup." });
|
||||||
options.push({ id: "port", type: "string", cat: "o", description: "Port for the main server." });
|
options.push({ id: "port", type: "string", cat: "o", description: "Port for the main server." });
|
||||||
options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." });
|
options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." });
|
||||||
|
|
||||||
options.push(last);
|
options.push(last);
|
||||||
|
|
||||||
const main = async (): Promise<void | void[]> => {
|
|
||||||
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
||||||
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
|
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
|
||||||
if (typeof args[key] === "string") {
|
if (typeof args[key] === "string") {
|
||||||
args[key] = [args[key]];
|
args[key] = [args[key]];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
|
||||||
if (!product.extensionsGallery) {
|
const startVscode = async (): Promise<void | void[]> => {
|
||||||
product.extensionsGallery = {
|
const args = getArgs();
|
||||||
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
|
|
||||||
itemUrl: process.env.ITEM_URL || "",
|
|
||||||
controlUrl: "",
|
|
||||||
recommendationsUrl: "",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const version = `${(pkg as any).codeServerVersion || "development"}-vsc${pkg.version}`;
|
|
||||||
if (args.help) {
|
|
||||||
const executable = `${product.applicationName}${os.platform() === "win32" ? ".exe" : ""}`;
|
|
||||||
return console.log(buildHelpMessage(product.nameLong, executable, version, undefined, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.version) {
|
|
||||||
return buildVersionMessage(version, product.commit).split("\n").map((line) => logger.info(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
enableExtensionTars();
|
|
||||||
|
|
||||||
const shouldSpawnCliProcess = (): boolean => {
|
|
||||||
return !!args["install-source"]
|
|
||||||
|| !!args["list-extensions"]
|
|
||||||
|| !!args["install-extension"]
|
|
||||||
|| !!args["uninstall-extension"]
|
|
||||||
|| !!args["locate-extension"]
|
|
||||||
|| !!args["telemetry"];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (shouldSpawnCliProcess()) {
|
|
||||||
await vsCli(args);
|
|
||||||
return process.exit(0); // There is a WriteStream instance keeping it open.
|
|
||||||
}
|
|
||||||
|
|
||||||
const extra = args["_"] || [];
|
const extra = args["_"] || [];
|
||||||
const options = {
|
const options = {
|
||||||
auth: args.auth,
|
auth: args.auth,
|
||||||
|
@ -136,6 +116,8 @@ const main = async (): Promise<void | void[]> => {
|
||||||
options.certKey = certKey;
|
options.certKey = certKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableExtensionTars();
|
||||||
|
|
||||||
const server = new MainServer({
|
const server = new MainServer({
|
||||||
...options,
|
...options,
|
||||||
port: typeof args.port !== "undefined" && parseInt(args.port, 10) || 8443,
|
port: typeof args.port !== "undefined" && parseInt(args.port, 10) || 8443,
|
||||||
|
@ -168,14 +150,99 @@ const main = async (): Promise<void | void[]> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server.options.socket && args.open) {
|
if (!server.options.socket && args.open) {
|
||||||
// The web socket doesn't seem to work if using 0.0.0.0.
|
// The web socket doesn't seem to work if browsing with 0.0.0.0.
|
||||||
const openAddress = `http://localhost:${server.options.port}`;
|
const openAddress = `http://localhost:${server.options.port}`;
|
||||||
await open(openAddress).catch(console.error);
|
await open(openAddress).catch(console.error);
|
||||||
logger.info(` - Opened ${openAddress}`);
|
logger.info(` - Opened ${openAddress}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const startCli = (): boolean | Promise<void> => {
|
||||||
|
const args = getArgs();
|
||||||
|
if (args.help) {
|
||||||
|
const executable = `${product.applicationName}${os.platform() === "win32" ? ".exe" : ""}`;
|
||||||
|
console.log(buildHelpMessage(product.nameLong, executable, pkg.codeServerVersion, undefined, false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.version) {
|
||||||
|
buildVersionMessage(pkg.codeServerVersion, product.commit).split("\n").map((line) => logger.info(line));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldSpawnCliProcess = (): boolean => {
|
||||||
|
return !!args["install-source"]
|
||||||
|
|| !!args["list-extensions"]
|
||||||
|
|| !!args["install-extension"]
|
||||||
|
|| !!args["uninstall-extension"]
|
||||||
|
|| !!args["locate-extension"]
|
||||||
|
|| !!args["telemetry"];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (shouldSpawnCliProcess()) {
|
||||||
|
enableExtensionTars();
|
||||||
|
return vsCli(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WrapperProcess {
|
||||||
|
private process?: cp.ChildProcess;
|
||||||
|
private started?: Promise<void>;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
ipcMain.onMessage(async (message) => {
|
||||||
|
switch (message) {
|
||||||
|
case "relaunch":
|
||||||
|
logger.info("Relaunching...");
|
||||||
|
this.started = undefined;
|
||||||
|
if (this.process) {
|
||||||
|
this.process.kill();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.start();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message);
|
||||||
|
process.exit(typeof error.code === "number" ? error.code : 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.error(`Unrecognized message ${message}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(): Promise<void> {
|
||||||
|
if (!this.started) {
|
||||||
|
const child = this.spawn();
|
||||||
|
this.started = ipcMain.handshake(child);
|
||||||
|
this.process = child;
|
||||||
|
}
|
||||||
|
return this.started;
|
||||||
|
}
|
||||||
|
|
||||||
|
private spawn(): cp.ChildProcess {
|
||||||
|
return cp.spawn(process.argv[0], process.argv.slice(1), {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
LAUNCH_VSCODE: "true",
|
||||||
|
},
|
||||||
|
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const main = async(): Promise<boolean | void | void[]> => {
|
||||||
|
if (process.env.LAUNCH_VSCODE) {
|
||||||
|
await ipcMain.handshake();
|
||||||
|
return startVscode();
|
||||||
|
}
|
||||||
|
return startCli() || new WrapperProcess().start();
|
||||||
|
};
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error(error);
|
logger.error(error.message);
|
||||||
process.exit(1);
|
process.exit(typeof error.code === "number" ? error.code : 1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import * as cp from "child_process";
|
||||||
|
|
||||||
|
import { Emitter } from "vs/base/common/event";
|
||||||
|
|
||||||
|
enum ControlMessage {
|
||||||
|
okToChild = "ok>",
|
||||||
|
okFromChild = "ok<",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Message = "relaunch";
|
||||||
|
|
||||||
|
class IpcMain {
|
||||||
|
protected readonly _onMessage = new Emitter<Message>();
|
||||||
|
public readonly onMessage = this._onMessage.event;
|
||||||
|
|
||||||
|
public handshake(child?: cp.ChildProcess): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const target = child || process;
|
||||||
|
if (!target.send) {
|
||||||
|
throw new Error("Not spawned with IPC enabled");
|
||||||
|
}
|
||||||
|
target.on("message", (message) => {
|
||||||
|
if (message === child ? ControlMessage.okFromChild : ControlMessage.okToChild) {
|
||||||
|
target.removeAllListeners();
|
||||||
|
target.on("message", (msg) => this._onMessage.fire(msg));
|
||||||
|
if (child) {
|
||||||
|
target.send!(ControlMessage.okToChild);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (child) {
|
||||||
|
child.once("error", reject);
|
||||||
|
child.once("exit", (code) => {
|
||||||
|
const error = new Error(`Unexpected exit with code ${code}`);
|
||||||
|
(error as any).code = code;
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
target.send(ControlMessage.okFromChild);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public relaunch(): void {
|
||||||
|
if (!process.send) {
|
||||||
|
throw new Error("Not a child process with IPC enabled");
|
||||||
|
}
|
||||||
|
process.send("relaunch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ipcMain = new IpcMain();
|
|
@ -53,6 +53,7 @@ import { AppInsightsAppender } from "vs/platform/telemetry/node/appInsightsAppen
|
||||||
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
|
import { resolveCommonProperties } from "vs/platform/telemetry/node/commonProperties";
|
||||||
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
|
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
|
||||||
import { TelemetryChannel } from "vs/platform/telemetry/node/telemetryIpc";
|
import { TelemetryChannel } from "vs/platform/telemetry/node/telemetryIpc";
|
||||||
|
import { UpdateChannel } from "vs/platform/update/node/updateIpc";
|
||||||
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
|
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
|
||||||
|
|
||||||
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
|
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
|
||||||
|
@ -60,6 +61,7 @@ import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/sr
|
||||||
import { TelemetryClient } from "vs/server/src/insights";
|
import { TelemetryClient } from "vs/server/src/insights";
|
||||||
import { getNlsConfiguration, getLocaleFromConfig } from "vs/server/src/nls";
|
import { getNlsConfiguration, getLocaleFromConfig } from "vs/server/src/nls";
|
||||||
import { Protocol } from "vs/server/src/protocol";
|
import { Protocol } from "vs/server/src/protocol";
|
||||||
|
import { UpdateService } from "vs/server/src/update";
|
||||||
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
|
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
|
||||||
|
|
||||||
export enum HttpCode {
|
export enum HttpCode {
|
||||||
|
@ -482,7 +484,11 @@ export class MainServer extends Server {
|
||||||
REMOTE_USER_DATA_URI: transformer.transformOutgoing(
|
REMOTE_USER_DATA_URI: transformer.transformOutgoing(
|
||||||
(this.services.get(IEnvironmentService) as EnvironmentService).webUserDataHome,
|
(this.services.get(IEnvironmentService) as EnvironmentService).webUserDataHome,
|
||||||
),
|
),
|
||||||
PRODUCT_CONFIGURATION: product,
|
PRODUCT_CONFIGURATION: {
|
||||||
|
...product,
|
||||||
|
// @ts-ignore workaround for getting the VS Code version to the browser.
|
||||||
|
version: pkg.version,
|
||||||
|
},
|
||||||
CONNECTION_AUTH_TOKEN: "",
|
CONNECTION_AUTH_TOKEN: "",
|
||||||
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
|
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
|
||||||
};
|
};
|
||||||
|
@ -560,14 +566,13 @@ export class MainServer extends Server {
|
||||||
this.services.set(IRequestService, new SyncDescriptor(RequestService));
|
this.services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
||||||
if (!environmentService.args["disable-telemetry"]) {
|
if (!environmentService.args["disable-telemetry"]) {
|
||||||
const version = `${(pkg as any).codeServerVersion || "development"}-vsc${pkg.version}`;
|
|
||||||
this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{
|
this.services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [{
|
||||||
appender: combinedAppender(
|
appender: combinedAppender(
|
||||||
new AppInsightsAppender("code-server", null, () => new TelemetryClient(), logService),
|
new AppInsightsAppender("code-server", null, () => new TelemetryClient(), logService),
|
||||||
new LogAppender(logService),
|
new LogAppender(logService),
|
||||||
),
|
),
|
||||||
commonProperties: resolveCommonProperties(
|
commonProperties: resolveCommonProperties(
|
||||||
product.commit, version, await getMachineId(),
|
product.commit, pkg.codeServerVersion, await getMachineId(),
|
||||||
environmentService.installSourcePath, "code-server",
|
environmentService.installSourcePath, "code-server",
|
||||||
),
|
),
|
||||||
piiPaths: [
|
piiPaths: [
|
||||||
|
@ -601,6 +606,8 @@ export class MainServer extends Server {
|
||||||
this.ipc.registerChannel("gallery", galleryChannel);
|
this.ipc.registerChannel("gallery", galleryChannel);
|
||||||
const telemetryChannel = new TelemetryChannel(telemetryService);
|
const telemetryChannel = new TelemetryChannel(telemetryService);
|
||||||
this.ipc.registerChannel("telemetry", telemetryChannel);
|
this.ipc.registerChannel("telemetry", telemetryChannel);
|
||||||
|
const updateChannel = new UpdateChannel(instantiationService.createInstance(UpdateService));
|
||||||
|
this.ipc.registerChannel("update", updateChannel);
|
||||||
resolve(new ErrorTelemetry(telemetryService));
|
resolve(new ErrorTelemetry(telemetryService));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
import * as cp from "child_process";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as path from "path";
|
||||||
|
import * as util from "util";
|
||||||
|
import * as zlib from 'zlib';
|
||||||
|
|
||||||
|
import { CancellationToken } from "vs/base/common/cancellation";
|
||||||
|
import * as pfs from "vs/base/node/pfs";
|
||||||
|
import { asJson, download } from "vs/base/node/request";
|
||||||
|
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
|
||||||
|
import { IEnvironmentService } from "vs/platform/environment/common/environment";
|
||||||
|
import { ILogService } from "vs/platform/log/common/log";
|
||||||
|
import pkg from "vs/platform/product/node/package";
|
||||||
|
import { IRequestService } from "vs/platform/request/node/request";
|
||||||
|
import { State, UpdateType, StateType, AvailableForDownload } from "vs/platform/update/common/update";
|
||||||
|
import { AbstractUpdateService } from "vs/platform/update/electron-main/abstractUpdateService";
|
||||||
|
|
||||||
|
import { ipcMain } from "vs/server/src/ipc";
|
||||||
|
import { tmpdir } from "vs/server/src/util";
|
||||||
|
import { extract } from "vs/server/src/tar";
|
||||||
|
|
||||||
|
interface IUpdate {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateService extends AbstractUpdateService {
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
|
@IEnvironmentService environmentService: IEnvironmentService,
|
||||||
|
@IRequestService requestService: IRequestService,
|
||||||
|
@ILogService logService: ILogService
|
||||||
|
) {
|
||||||
|
super(null, configurationService, environmentService, requestService, logService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async isLatestVersion(): Promise<boolean | undefined> {
|
||||||
|
const latest = await this.getLatestVersion();
|
||||||
|
return !latest || latest.name === pkg.codeServerVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected buildUpdateFeedUrl(): string {
|
||||||
|
return "https://api.github.com/repos/cdr/code-server/releases/latest";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doQuitAndInstall(): void {
|
||||||
|
ipcMain.relaunch();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async doCheckForUpdates(context: any): Promise<void> {
|
||||||
|
if (this.state.type !== StateType.Idle) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
this.setState(State.CheckingForUpdates(context));
|
||||||
|
try {
|
||||||
|
const update = await this.getLatestVersion();
|
||||||
|
if (!update || !update.name || update.name === pkg.codeServerVersion) {
|
||||||
|
this.setState(State.Idle(UpdateType.Archive));
|
||||||
|
} else {
|
||||||
|
this.setState(State.AvailableForDownload({
|
||||||
|
version: update.name,
|
||||||
|
productVersion: update.name,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.onRequestError(error, !!context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getLatestVersion(): Promise<IUpdate | null> {
|
||||||
|
const data = await this.requestService.request({
|
||||||
|
url: this.url,
|
||||||
|
headers: {
|
||||||
|
"User-Agent": "code-server",
|
||||||
|
},
|
||||||
|
}, CancellationToken.None);
|
||||||
|
return asJson(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async doDownloadUpdate(state: AvailableForDownload): Promise<void> {
|
||||||
|
this.setState(State.Updating(state.update));
|
||||||
|
const target = os.platform();
|
||||||
|
const releaseName = await this.buildReleaseName(state.update.version);
|
||||||
|
const url = "https://github.com/cdr/code-server/releases/download/"
|
||||||
|
+ `${state.update.version}/${releaseName}`
|
||||||
|
+ `.${target === "darwin" ? "zip" : "tar.gz"}`;
|
||||||
|
const downloadPath = path.join(tmpdir, `${state.update.version}-archive`);
|
||||||
|
const extractPath = path.join(tmpdir, state.update.version);
|
||||||
|
try {
|
||||||
|
await pfs.mkdirp(tmpdir);
|
||||||
|
const context = await this.requestService.request({ url }, CancellationToken.None);
|
||||||
|
// Decompress the gzip as we download. If the gzip encoding is set then
|
||||||
|
// the request service already does this.
|
||||||
|
if (target !== "darwin" && context.res.headers["content-encoding"] !== "gzip") {
|
||||||
|
context.stream = context.stream.pipe(zlib.createGunzip());
|
||||||
|
}
|
||||||
|
await download(downloadPath, context);
|
||||||
|
await extract(downloadPath, extractPath, undefined, CancellationToken.None);
|
||||||
|
const newBinary = path.join(extractPath, releaseName, "code-server");
|
||||||
|
if (!pfs.exists(newBinary)) {
|
||||||
|
throw new Error("No code-server binary in extracted archive");
|
||||||
|
}
|
||||||
|
await pfs.unlink(process.argv[0]); // Must unlink first to avoid ETXTBSY.
|
||||||
|
await pfs.move(newBinary, process.argv[0]);
|
||||||
|
this.setState(State.Ready(state.update));
|
||||||
|
} catch (error) {
|
||||||
|
this.onRequestError(error, true);
|
||||||
|
}
|
||||||
|
await Promise.all([downloadPath, extractPath].map((p) => pfs.rimraf(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRequestError(error: Error, showNotification?: boolean): void {
|
||||||
|
this.logService.error(error);
|
||||||
|
const message: string | undefined = showNotification ? (error.message || error.toString()) : undefined;
|
||||||
|
this.setState(State.Idle(UpdateType.Archive, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async buildReleaseName(release: string): Promise<string> {
|
||||||
|
let target: string = os.platform();
|
||||||
|
if (target === "linux") {
|
||||||
|
const result = await util.promisify(cp.exec)("ldd --version");
|
||||||
|
if (result.stderr) {
|
||||||
|
throw new Error(result.stderr);
|
||||||
|
}
|
||||||
|
if (result.stdout.indexOf("musl") !== -1) {
|
||||||
|
target = "alpine";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arch = os.arch();
|
||||||
|
if (arch === "x64") {
|
||||||
|
arch = "x86_64";
|
||||||
|
}
|
||||||
|
return `code-server${release}-${target}-${arch}`;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue