send begin/end notifications when installing types packages (#12551)

This commit is contained in:
Vladimir Matveev
2016-11-29 10:14:22 -08:00
committed by GitHub
parent e313fef683
commit 1418fd170d
8 changed files with 243 additions and 64 deletions

View File

@@ -2117,6 +2117,40 @@ namespace ts.server.protocol {
typingsInstallerVersion: string;
}
export type BeginInstallTypesEventName = "beginInstallTypes";
export type EndInstallTypesEventName = "endInstallTypes";
export interface BeginInstallTypesEvent extends Event {
event: BeginInstallTypesEventName;
body: BeginInstallTypesEventBody;
}
export interface EndInstallTypesEvent extends Event {
event: EndInstallTypesEventName;
body: EndInstallTypesEventBody;
}
export interface InstallTypesEventBody {
/**
* correlation id to match begin and end events
*/
eventId: number;
/**
* list of packages to install
*/
packages: ReadonlyArray<string>;
}
export interface BeginInstallTypesEventBody extends InstallTypesEventBody {
}
export interface EndInstallTypesEventBody extends InstallTypesEventBody {
/**
* true if installation succeeded, otherwise false
*/
success: boolean;
}
export interface NavBarResponse extends Response {
body?: NavigationBarItem[];
}

View File

@@ -198,7 +198,7 @@ namespace ts.server {
private socket: NodeSocket;
private projectService: ProjectService;
private throttledOperations: ThrottledOperations;
private telemetrySender: EventSender;
private eventSender: EventSender;
constructor(
private readonly telemetryEnabled: boolean,
@@ -231,7 +231,7 @@ namespace ts.server {
}
setTelemetrySender(telemetrySender: EventSender) {
this.telemetrySender = telemetrySender;
this.eventSender = telemetrySender;
}
attach(projectService: ProjectService) {
@@ -291,12 +291,30 @@ namespace ts.server {
});
}
private handleMessage(response: SetTypings | InvalidateCachedTypings | TypingsInstallEvent) {
private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) {
if (this.logger.hasLevel(LogLevel.verbose)) {
this.logger.info(`Received response: ${JSON.stringify(response)}`);
}
if (response.kind === EventInstall) {
if (this.telemetrySender) {
if (response.kind === EventBeginInstallTypes) {
if (!this.eventSender) {
return;
}
const body: protocol.BeginInstallTypesEventBody = {
eventId: response.eventId,
packages: response.packagesToInstall,
};
const eventName: protocol.BeginInstallTypesEventName = "beginInstallTypes";
this.eventSender.event(body, eventName);
return;
}
if (response.kind === EventEndInstallTypes) {
if (!this.eventSender) {
return;
}
if (this.telemetryEnabled) {
const body: protocol.TypingsInstalledTelemetryEventBody = {
telemetryEventName: "typingsInstalled",
payload: {
@@ -306,10 +324,19 @@ namespace ts.server {
}
};
const eventName: protocol.TelemetryEventName = "telemetry";
this.telemetrySender.event(body, eventName);
this.eventSender.event(body, eventName);
}
const body: protocol.EndInstallTypesEventBody = {
eventId: response.eventId,
packages: response.packagesToInstall,
success: response.installSuccess,
};
const eventName: protocol.EndInstallTypesEventName = "endInstallTypes";
this.eventSender.event(body, eventName);
return;
}
this.projectService.updateTypingsForProject(response);
if (response.kind == ActionSet && this.socket) {
this.sendEvent(0, "setTypings", response);

View File

@@ -3,7 +3,8 @@
namespace ts.server {
export const ActionSet: ActionSet = "action::set";
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
export const EventInstall: EventInstall = "event::install";
export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes";
export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes";
export namespace Arguments {
export const GlobalCacheLocation = "--globalTypingsCacheLocation";

22
src/server/types.d.ts vendored
View File

@@ -43,10 +43,11 @@ declare namespace ts.server {
export type ActionSet = "action::set";
export type ActionInvalidate = "action::invalidate";
export type EventInstall = "event::install";
export type EventBeginInstallTypes = "event::beginInstallTypes";
export type EventEndInstallTypes = "event::endInstallTypes";
export interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventInstall;
readonly kind: ActionSet | ActionInvalidate | EventBeginInstallTypes | EventEndInstallTypes;
}
export interface ProjectResponse extends TypingInstallerResponse {
@@ -65,11 +66,20 @@ declare namespace ts.server {
readonly kind: ActionInvalidate;
}
export interface TypingsInstallEvent extends TypingInstallerResponse {
readonly packagesToInstall: ReadonlyArray<string>;
readonly kind: EventInstall;
readonly installSuccess: boolean;
export interface InstallTypes extends ProjectResponse {
readonly kind: EventBeginInstallTypes | EventEndInstallTypes;
readonly eventId: number;
readonly typingsInstallerVersion: string;
readonly packagesToInstall: ReadonlyArray<string>;
}
export interface BeginInstallTypes extends InstallTypes {
readonly kind: EventBeginInstallTypes;
}
export interface EndInstallTypes extends InstallTypes {
readonly kind: EventEndInstallTypes;
readonly installSuccess: boolean;
}
export interface InstallTypingHost extends JsTyping.TypingResolutionHost {

View File

@@ -70,13 +70,12 @@ namespace ts.server.typingsInstaller {
private readonly npmPath: string;
readonly typesRegistry: Map<void>;
constructor(globalTypingsCacheLocation: string, throttleLimit: number, telemetryEnabled: boolean, log: Log) {
constructor(globalTypingsCacheLocation: string, throttleLimit: number, log: Log) {
super(
sys,
globalTypingsCacheLocation,
toPath("typingSafeList.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
throttleLimit,
telemetryEnabled,
log);
if (this.log.isEnabled()) {
this.log.writeLine(`Process id: ${process.pid}`);
@@ -113,7 +112,7 @@ namespace ts.server.typingsInstaller {
});
}
protected sendResponse(response: SetTypings | InvalidateCachedTypings) {
protected sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) {
if (this.log.isEnabled()) {
this.log.writeLine(`Sending response: ${JSON.stringify(response)}`);
}
@@ -149,7 +148,6 @@ namespace ts.server.typingsInstaller {
const logFilePath = findArgument(server.Arguments.LogFile);
const globalTypingsCacheLocation = findArgument(server.Arguments.GlobalCacheLocation);
const telemetryEnabled = hasArgument(server.Arguments.EnableTelemetry);
const log = new FileLog(logFilePath);
if (log.isEnabled()) {
@@ -163,6 +161,6 @@ namespace ts.server.typingsInstaller {
}
process.exit(0);
});
const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, /*throttleLimit*/5, telemetryEnabled, log);
const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, /*throttleLimit*/5, log);
installer.listen();
}

View File

@@ -97,7 +97,6 @@ namespace ts.server.typingsInstaller {
readonly globalCachePath: string,
readonly safeListPath: Path,
readonly throttleLimit: number,
readonly telemetryEnabled: boolean,
protected readonly log = nullLog) {
if (this.log.isEnabled()) {
this.log.writeLine(`Global cache location '${globalCachePath}', safe file path '${safeListPath}'`);
@@ -309,47 +308,58 @@ namespace ts.server.typingsInstaller {
const requestId = this.installRunCount;
this.installRunCount++;
// send progress event
this.sendResponse(<BeginInstallTypes>{
kind: EventBeginInstallTypes,
eventId: requestId,
typingsInstallerVersion: ts.version, // qualified explicitly to prevent occasional shadowing
projectName: req.projectName
});
this.installTypingsAsync(requestId, scopedTypings, cachePath, ok => {
if (this.telemetryEnabled) {
this.sendResponse(<TypingsInstallEvent>{
kind: EventInstall,
try {
if (!ok) {
if (this.log.isEnabled()) {
this.log.writeLine(`install request failed, marking packages as missing to prevent repeated requests: ${JSON.stringify(filteredTypings)}`);
}
for (const typing of filteredTypings) {
this.missingTypingsSet[typing] = true;
}
return;
}
// TODO: watch project directory
if (this.log.isEnabled()) {
this.log.writeLine(`Installed typings ${JSON.stringify(scopedTypings)}`);
}
const installedTypingFiles: string[] = [];
for (const packageName of filteredTypings) {
const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost, this.log);
if (!typingFile) {
this.missingTypingsSet[packageName] = true;
continue;
}
if (!this.packageNameToTypingLocation[packageName]) {
this.packageNameToTypingLocation[packageName] = typingFile;
}
installedTypingFiles.push(typingFile);
}
if (this.log.isEnabled()) {
this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`);
}
this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles)));
}
finally {
this.sendResponse(<EndInstallTypes>{
kind: EventEndInstallTypes,
eventId: requestId,
projectName: req.projectName,
packagesToInstall: scopedTypings,
installSuccess: ok,
typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing
});
}
if (!ok) {
if (this.log.isEnabled()) {
this.log.writeLine(`install request failed, marking packages as missing to prevent repeated requests: ${JSON.stringify(filteredTypings)}`);
}
for (const typing of filteredTypings) {
this.missingTypingsSet[typing] = true;
}
return;
}
// TODO: watch project directory
if (this.log.isEnabled()) {
this.log.writeLine(`Installed typings ${JSON.stringify(scopedTypings)}`);
}
const installedTypingFiles: string[] = [];
for (const packageName of filteredTypings) {
const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost, this.log);
if (!typingFile) {
this.missingTypingsSet[packageName] = true;
continue;
}
if (!this.packageNameToTypingLocation[packageName]) {
this.packageNameToTypingLocation[packageName] = typingFile;
}
installedTypingFiles.push(typingFile);
}
if (this.log.isEnabled()) {
this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`);
}
this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles)));
});
}
@@ -417,6 +427,6 @@ namespace ts.server.typingsInstaller {
}
protected abstract installWorker(requestId: number, args: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void;
protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | TypingsInstallEvent): void;
protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes): void;
}
}