mirror of https://github.com/coder/code-server.git
Include code in stringified errors
This is done by returning the entire error stringified instead of just the message. This fixes the issue with the "save as" dialog.
This commit is contained in:
parent
be3f0c437f
commit
d556e110cb
|
@ -496,8 +496,9 @@ describe("fs", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail to stat nonexistent file", async () => {
|
it("should fail to stat nonexistent file", async () => {
|
||||||
await expect(util.promisify(fs.stat)(tmpFile()))
|
const error = await util.promisify(fs.stat)(tmpFile()).catch((e) => e);
|
||||||
.rejects.toThrow("ENOENT");
|
expect(error.message).toContain("ENOENT");
|
||||||
|
expect(error.code).toBe("ENOENT");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ export class Client {
|
||||||
const eventsMsg = new EvalEventMessage();
|
const eventsMsg = new EvalEventMessage();
|
||||||
eventsMsg.setId(doEval.id);
|
eventsMsg.setId(doEval.id);
|
||||||
eventsMsg.setEvent(event);
|
eventsMsg.setEvent(event);
|
||||||
eventsMsg.setArgsList(args.map(stringify));
|
eventsMsg.setArgsList(args.map((a) => stringify(a)));
|
||||||
const clientMsg = new ClientMessage();
|
const clientMsg = new ClientMessage();
|
||||||
clientMsg.setEvalEvent(eventsMsg);
|
clientMsg.setEvalEvent(eventsMsg);
|
||||||
this.connection.send(clientMsg.serializeBinary());
|
this.connection.send(clientMsg.serializeBinary());
|
||||||
|
@ -140,7 +140,7 @@ export class Client {
|
||||||
const id = this.evalId++;
|
const id = this.evalId++;
|
||||||
newEval.setId(id);
|
newEval.setId(id);
|
||||||
newEval.setActive(active);
|
newEval.setActive(active);
|
||||||
newEval.setArgsList([a1, a2, a3, a4, a5, a6].map(stringify));
|
newEval.setArgsList([a1, a2, a3, a4, a5, a6].map((a) => stringify(a)));
|
||||||
newEval.setFunction(func.toString());
|
newEval.setFunction(func.toString());
|
||||||
|
|
||||||
const clientMsg = new ClientMessage();
|
const clientMsg = new ClientMessage();
|
||||||
|
@ -155,16 +155,15 @@ export class Client {
|
||||||
|
|
||||||
const d1 = this.evalDoneEmitter.event((doneMsg) => {
|
const d1 = this.evalDoneEmitter.event((doneMsg) => {
|
||||||
if (doneMsg.getId() === id) {
|
if (doneMsg.getId() === id) {
|
||||||
const resp = doneMsg.getResponse();
|
|
||||||
dispose();
|
dispose();
|
||||||
resolve(parse(resp));
|
resolve(parse(doneMsg.getResponse()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const d2 = this.evalFailedEmitter.event((failedMsg) => {
|
const d2 = this.evalFailedEmitter.event((failedMsg) => {
|
||||||
if (failedMsg.getId() === id) {
|
if (failedMsg.getId() === id) {
|
||||||
dispose();
|
dispose();
|
||||||
reject(new Error(failedMsg.getMessage()));
|
reject(parse(failedMsg.getResponse()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,17 +25,19 @@ export type IEncodingOptions = {
|
||||||
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void);
|
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stringify an event argument.
|
* Stringify an event argument. isError is because although methods like
|
||||||
|
* `fs.stat` are supposed to throw Error objects, they currently throw regular
|
||||||
|
* objects when running tests through Jest.
|
||||||
*/
|
*/
|
||||||
export const stringify = (arg: any): string => { // tslint:disable-line no-any
|
export const stringify = (arg: any, isError?: boolean): string => { // tslint:disable-line no-any
|
||||||
if (arg instanceof Error) {
|
if (arg instanceof Error || isError) {
|
||||||
// Errors don't stringify at all. They just become "{}".
|
// Errors don't stringify at all. They just become "{}".
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
type: "Error",
|
type: "Error",
|
||||||
data: {
|
data: {
|
||||||
message: arg.message,
|
message: arg.message,
|
||||||
name: arg.name,
|
|
||||||
stack: arg.stack,
|
stack: arg.stack,
|
||||||
|
code: (arg as NodeJS.ErrnoException).code,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (arg instanceof Uint8Array) {
|
} else if (arg instanceof Uint8Array) {
|
||||||
|
@ -74,7 +76,16 @@ export const parse = (arg: string): any => { // tslint:disable-line no-any
|
||||||
// what happens to buffers and stringify them as regular objects.
|
// what happens to buffers and stringify them as regular objects.
|
||||||
case "Error":
|
case "Error":
|
||||||
if (result.data.message) {
|
if (result.data.message) {
|
||||||
return new Error(result.data.message);
|
const error = new Error(result.data.message);
|
||||||
|
// TODO: Can we set the stack? Doing so seems to make it into an
|
||||||
|
// "invalid object".
|
||||||
|
if (typeof result.data.code !== "undefined") {
|
||||||
|
(error as NodeJS.ErrnoException).code = result.data.code;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line no-any
|
||||||
|
(error as any).originalStack = result.data.stack;
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
const sendException = (error: Error): void => {
|
const sendException = (error: Error): void => {
|
||||||
const evalFailed = new EvalFailedMessage();
|
const evalFailed = new EvalFailedMessage();
|
||||||
evalFailed.setId(message.getId());
|
evalFailed.setId(message.getId());
|
||||||
evalFailed.setReason(EvalFailedMessage.Reason.EXCEPTION);
|
evalFailed.setResponse(stringify(error, true));
|
||||||
evalFailed.setMessage(error.toString() + " " + error.stack);
|
|
||||||
|
|
||||||
const serverMsg = new ServerMessage();
|
const serverMsg = new ServerMessage();
|
||||||
serverMsg.setEvalFailed(evalFailed);
|
serverMsg.setEvalFailed(evalFailed);
|
||||||
|
@ -58,7 +57,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
logger.trace(() => [
|
logger.trace(() => [
|
||||||
`${event}`,
|
`${event}`,
|
||||||
field("id", message.getId()),
|
field("id", message.getId()),
|
||||||
field("args", args.map(stringify)),
|
field("args", args.map((a) => stringify(a))),
|
||||||
]);
|
]);
|
||||||
cb(...args);
|
cb(...args);
|
||||||
});
|
});
|
||||||
|
@ -67,11 +66,11 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
logger.trace(() => [
|
logger.trace(() => [
|
||||||
`emit ${event}`,
|
`emit ${event}`,
|
||||||
field("id", message.getId()),
|
field("id", message.getId()),
|
||||||
field("args", args.map(stringify)),
|
field("args", args.map((a) => stringify(a))),
|
||||||
]);
|
]);
|
||||||
const eventMsg = new EvalEventMessage();
|
const eventMsg = new EvalEventMessage();
|
||||||
eventMsg.setEvent(event);
|
eventMsg.setEvent(event);
|
||||||
eventMsg.setArgsList(args.map(stringify));
|
eventMsg.setArgsList(args.map((a) => stringify(a)));
|
||||||
eventMsg.setId(message.getId());
|
eventMsg.setId(message.getId());
|
||||||
const serverMsg = new ServerMessage();
|
const serverMsg = new ServerMessage();
|
||||||
serverMsg.setEvalEvent(eventMsg);
|
serverMsg.setEvalEvent(eventMsg);
|
||||||
|
|
|
@ -19,13 +19,7 @@ message EvalEventMessage {
|
||||||
|
|
||||||
message EvalFailedMessage {
|
message EvalFailedMessage {
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
enum Reason {
|
string response = 2;
|
||||||
Timeout = 0;
|
|
||||||
Exception = 1;
|
|
||||||
Conflict = 2;
|
|
||||||
}
|
|
||||||
Reason reason = 2;
|
|
||||||
string message = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message EvalDoneMessage {
|
message EvalDoneMessage {
|
||||||
|
|
|
@ -75,11 +75,8 @@ export class EvalFailedMessage extends jspb.Message {
|
||||||
getId(): number;
|
getId(): number;
|
||||||
setId(value: number): void;
|
setId(value: number): void;
|
||||||
|
|
||||||
getReason(): EvalFailedMessage.Reason;
|
getResponse(): string;
|
||||||
setReason(value: EvalFailedMessage.Reason): void;
|
setResponse(value: string): void;
|
||||||
|
|
||||||
getMessage(): string;
|
|
||||||
setMessage(value: string): void;
|
|
||||||
|
|
||||||
serializeBinary(): Uint8Array;
|
serializeBinary(): Uint8Array;
|
||||||
toObject(includeInstance?: boolean): EvalFailedMessage.AsObject;
|
toObject(includeInstance?: boolean): EvalFailedMessage.AsObject;
|
||||||
|
@ -94,14 +91,7 @@ export class EvalFailedMessage extends jspb.Message {
|
||||||
export namespace EvalFailedMessage {
|
export namespace EvalFailedMessage {
|
||||||
export type AsObject = {
|
export type AsObject = {
|
||||||
id: number,
|
id: number,
|
||||||
reason: EvalFailedMessage.Reason,
|
response: string,
|
||||||
message: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Reason {
|
|
||||||
TIMEOUT = 0,
|
|
||||||
EXCEPTION = 1,
|
|
||||||
CONFLICT = 2,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ var global = Function('return this')();
|
||||||
goog.exportSymbol('proto.EvalDoneMessage', null, global);
|
goog.exportSymbol('proto.EvalDoneMessage', null, global);
|
||||||
goog.exportSymbol('proto.EvalEventMessage', null, global);
|
goog.exportSymbol('proto.EvalEventMessage', null, global);
|
||||||
goog.exportSymbol('proto.EvalFailedMessage', null, global);
|
goog.exportSymbol('proto.EvalFailedMessage', null, global);
|
||||||
goog.exportSymbol('proto.EvalFailedMessage.Reason', null, global);
|
|
||||||
goog.exportSymbol('proto.NewEvalMessage', null, global);
|
goog.exportSymbol('proto.NewEvalMessage', null, global);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -554,8 +553,7 @@ proto.EvalFailedMessage.prototype.toObject = function(opt_includeInstance) {
|
||||||
proto.EvalFailedMessage.toObject = function(includeInstance, msg) {
|
proto.EvalFailedMessage.toObject = function(includeInstance, msg) {
|
||||||
var f, obj = {
|
var f, obj = {
|
||||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||||
reason: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
response: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||||
message: jspb.Message.getFieldWithDefault(msg, 3, "")
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (includeInstance) {
|
if (includeInstance) {
|
||||||
|
@ -597,12 +595,8 @@ proto.EvalFailedMessage.deserializeBinaryFromReader = function(msg, reader) {
|
||||||
msg.setId(value);
|
msg.setId(value);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
var value = /** @type {!proto.EvalFailedMessage.Reason} */ (reader.readEnum());
|
|
||||||
msg.setReason(value);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
var value = /** @type {string} */ (reader.readString());
|
var value = /** @type {string} */ (reader.readString());
|
||||||
msg.setMessage(value);
|
msg.setResponse(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reader.skipField();
|
reader.skipField();
|
||||||
|
@ -640,32 +634,16 @@ proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) {
|
||||||
f
|
f
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
f = message.getReason();
|
f = message.getResponse();
|
||||||
if (f !== 0.0) {
|
if (f.length > 0) {
|
||||||
writer.writeEnum(
|
writer.writeString(
|
||||||
2,
|
2,
|
||||||
f
|
f
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
f = message.getMessage();
|
|
||||||
if (f.length > 0) {
|
|
||||||
writer.writeString(
|
|
||||||
3,
|
|
||||||
f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @enum {number}
|
|
||||||
*/
|
|
||||||
proto.EvalFailedMessage.Reason = {
|
|
||||||
TIMEOUT: 0,
|
|
||||||
EXCEPTION: 1,
|
|
||||||
CONFLICT: 2
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* optional uint64 id = 1;
|
* optional uint64 id = 1;
|
||||||
* @return {number}
|
* @return {number}
|
||||||
|
@ -682,32 +660,17 @@ proto.EvalFailedMessage.prototype.setId = function(value) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* optional Reason reason = 2;
|
* optional string response = 2;
|
||||||
* @return {!proto.EvalFailedMessage.Reason}
|
|
||||||
*/
|
|
||||||
proto.EvalFailedMessage.prototype.getReason = function() {
|
|
||||||
return /** @type {!proto.EvalFailedMessage.Reason} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** @param {!proto.EvalFailedMessage.Reason} value */
|
|
||||||
proto.EvalFailedMessage.prototype.setReason = function(value) {
|
|
||||||
jspb.Message.setProto3EnumField(this, 2, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* optional string message = 3;
|
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
proto.EvalFailedMessage.prototype.getMessage = function() {
|
proto.EvalFailedMessage.prototype.getResponse = function() {
|
||||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** @param {string} value */
|
/** @param {string} value */
|
||||||
proto.EvalFailedMessage.prototype.setMessage = function(value) {
|
proto.EvalFailedMessage.prototype.setResponse = function(value) {
|
||||||
jspb.Message.setProto3StringField(this, 3, value);
|
jspb.Message.setProto3StringField(this, 2, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue