roku-debug 0.23.7 → 0.23.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +7 -2
- package/audit-ci.jsonc +15 -0
- package/dist/adapters/DebugProtocolAdapter.d.ts +29 -8
- package/dist/adapters/DebugProtocolAdapter.js +97 -35
- package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
- package/dist/adapters/TelnetAdapter.d.ts +2 -0
- package/dist/adapters/TelnetAdapter.js +7 -0
- package/dist/adapters/TelnetAdapter.js.map +1 -1
- package/dist/debugProtocol/client/DebugProtocolClient.d.ts +12 -19
- package/dist/debugProtocol/client/DebugProtocolClient.js +16 -36
- package/dist/debugProtocol/client/DebugProtocolClient.js.map +1 -1
- package/dist/debugProtocol/client/ProtocolCapabilities.d.ts +56 -0
- package/dist/debugProtocol/client/ProtocolCapabilities.js +106 -0
- package/dist/debugProtocol/client/ProtocolCapabilities.js.map +1 -0
- package/dist/debugSession/BrightScriptDebugSession.d.ts +16 -2
- package/dist/debugSession/BrightScriptDebugSession.js +220 -150
- package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
- package/dist/managers/ProjectManager.d.ts +17 -0
- package/dist/managers/ProjectManager.js +42 -5
- package/dist/managers/ProjectManager.js.map +1 -1
- package/package.json +17 -14
|
@@ -64,6 +64,7 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
64
64
|
*/
|
|
65
65
|
this.COMPILE_ERROR_THREAD_ID = 7777;
|
|
66
66
|
this.exceptionBreakpoints = [];
|
|
67
|
+
this.publishTimeout = 60000;
|
|
67
68
|
this.pendingSendLogPromise = Promise.resolve();
|
|
68
69
|
this.debounceSendInvalidatedEvent = (0, debounce_1.debounce)((threadId, frameId) => {
|
|
69
70
|
this.sendInvalidatedEvent(threadId, frameId);
|
|
@@ -273,13 +274,16 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
273
274
|
response.body.supportsRestartRequest = true;
|
|
274
275
|
// make VS Code to use 'evaluate' when hovering over source
|
|
275
276
|
response.body.supportsEvaluateForHovers = true;
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
response.
|
|
282
|
-
//the list
|
|
277
|
+
//NOTE: `supportsConditionalBreakpoints` and `supportsHitConditionalBreakpoints` are
|
|
278
|
+
//sent later in the post-connect CapabilitiesEvent once we know which adapter is in use
|
|
279
|
+
//(telnet always supports them via stop-statement rewrites; debug protocol requires v3.1.0+).
|
|
280
|
+
//VS Code reads these caps per-render in the BREAKPOINTS view, so CapabilitiesEvent updates
|
|
281
|
+
//take effect immediately - unlike `exceptionBreakpointFilters` / `breakpointModes` which
|
|
282
|
+
//must be in the initialize response.
|
|
283
|
+
//surface the filter list here so VS Code's BREAKPOINTS panel renders the checkboxes - the
|
|
284
|
+
//panel only reads this list from the initialize response, not from later CapabilitiesEvents.
|
|
285
|
+
//The `supportsExceptionFilterOptions` / `supportsExceptionOptions` booleans are deferred and
|
|
286
|
+
//sent via CapabilitiesEvent once we know the connected device's protocol version.
|
|
283
287
|
response.body.exceptionBreakpointFilters = [{
|
|
284
288
|
filter: 'caught',
|
|
285
289
|
supportsCondition: true,
|
|
@@ -295,10 +299,6 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
295
299
|
description: 'Breaks only on errors that are not handled.',
|
|
296
300
|
default: true
|
|
297
301
|
}];
|
|
298
|
-
// This debug adapter supports breakpoints that break execution after a specified number of hits
|
|
299
|
-
response.body.supportsHitConditionalBreakpoints = true;
|
|
300
|
-
// This debug adapter supports log points by interpreting the 'logMessage' attribute of the SourceBreakpoint
|
|
301
|
-
response.body.supportsLogPoints = true;
|
|
302
302
|
response.body.supportsCompletionsRequest = true;
|
|
303
303
|
response.body.completionTriggerCharacters = ['.', '(', '{', ',', ' '];
|
|
304
304
|
this.sendResponse(response);
|
|
@@ -306,10 +306,6 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
306
306
|
logging_1.debugServerLogOutputEventTransport.setWriter((message) => {
|
|
307
307
|
this.sendEvent(new Events_1.DebugServerLogOutputEvent(message.logger.formatMessage(message, false)));
|
|
308
308
|
});
|
|
309
|
-
// since this debug adapter can accept configuration requests like 'setBreakpoint' at any time,
|
|
310
|
-
// we request them early by sending an 'initializeRequest' to the frontend.
|
|
311
|
-
// The frontend will end the configuration sequence by calling 'configurationDone' request.
|
|
312
|
-
this.sendEvent(new debugadapter_1.InitializedEvent());
|
|
313
309
|
this.logger.log('initializeRequest finished');
|
|
314
310
|
}
|
|
315
311
|
async setExceptionBreakPointsRequest(response, args) {
|
|
@@ -329,11 +325,14 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
329
325
|
}));
|
|
330
326
|
}
|
|
331
327
|
this.exceptionBreakpoints = filterOptions;
|
|
332
|
-
//
|
|
333
|
-
|
|
328
|
+
//wait until the adapter object exists, but don't wait for the device to come online —
|
|
329
|
+
//VS Code will not send configurationDone (and we cannot launch the channel) until we
|
|
330
|
+
//respond to this request.
|
|
331
|
+
await this.rokuAdapterDeferred.promise;
|
|
334
332
|
if (this.rokuAdapter.supportsExceptionBreakpoints) {
|
|
333
|
+
//the adapter queues these filters internally if the debug protocol client hasn't
|
|
334
|
+
//connected yet, and replays them once it does
|
|
335
335
|
await this.rokuAdapter.setExceptionBreakpoints(filterOptions);
|
|
336
|
-
//if success
|
|
337
336
|
response.body.breakpoints = [
|
|
338
337
|
{ verified: true },
|
|
339
338
|
{ verified: true }
|
|
@@ -433,57 +432,57 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
433
432
|
return config;
|
|
434
433
|
}
|
|
435
434
|
async launchRequest(response, config) {
|
|
436
|
-
var _a, _b, _c, _d, _e, _f;
|
|
435
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
437
436
|
const logEnd = this.logger.timeStart('log', '[launchRequest] launch');
|
|
438
|
-
this.resetSessionState();
|
|
439
|
-
//send the response right away so the UI immediately shows the debugger toolbar
|
|
440
|
-
this.sendResponse(response);
|
|
441
|
-
this.launchConfiguration = this.normalizeLaunchConfig(config);
|
|
442
|
-
this.setupProcessErrorHandlers();
|
|
443
|
-
//prebake some threads for our ProjectManager to use later on (1 for the main project, and 1 for every complib)
|
|
444
|
-
BscProjectWorkerPool_1.bscProjectWorkerPool.preload(1 + ((_c = (_b = (_a = this.launchConfiguration) === null || _a === void 0 ? void 0 : _a.componentLibraries) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0));
|
|
445
|
-
//set the logLevel provided by the launch config
|
|
446
|
-
if (this.launchConfiguration.logLevel) {
|
|
447
|
-
logging_1.logger.logLevel = this.launchConfiguration.logLevel;
|
|
448
|
-
}
|
|
449
|
-
//do a DNS lookup for the host to fix issues with roku rejecting ECP
|
|
450
|
-
try {
|
|
451
|
-
this.launchConfiguration.host = await util_1.util.dnsLookup(this.launchConfiguration.host);
|
|
452
|
-
}
|
|
453
|
-
catch (e) {
|
|
454
|
-
return this.shutdown(`Could not resolve ip address for host '${this.launchConfiguration.host}'`);
|
|
455
|
-
}
|
|
456
|
-
// fetches the device info and parses the xml data to JSON object
|
|
457
437
|
try {
|
|
458
|
-
this.
|
|
459
|
-
|
|
460
|
-
|
|
438
|
+
this.resetSessionState();
|
|
439
|
+
this.launchConfiguration = this.normalizeLaunchConfig(config);
|
|
440
|
+
this.setupProcessErrorHandlers();
|
|
441
|
+
//prebake some threads for our ProjectManager to use later on (1 for the main project, and 1 for every complib)
|
|
442
|
+
BscProjectWorkerPool_1.bscProjectWorkerPool.preload(1 + ((_c = (_b = (_a = this.launchConfiguration) === null || _a === void 0 ? void 0 : _a.componentLibraries) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0));
|
|
443
|
+
//set the logLevel provided by the launch config
|
|
444
|
+
if (this.launchConfiguration.logLevel) {
|
|
445
|
+
logging_1.logger.logLevel = this.launchConfiguration.logLevel;
|
|
446
|
+
}
|
|
447
|
+
this.sendLaunchProgress('start', 'Finding device on network');
|
|
448
|
+
//do a DNS lookup for the host to fix issues with roku rejecting ECP
|
|
449
|
+
try {
|
|
450
|
+
this.launchConfiguration.host = await util_1.util.dnsLookup(this.launchConfiguration.host);
|
|
461
451
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (e instanceof roku_deploy_1.EcpNetworkAccessModeDisabledError) {
|
|
465
|
-
return this.shutdown(`ECP access is disabled on this Roku. Please change it to 'permissive' or 'enabled' and try again. (device: ${this.launchConfiguration.host})`);
|
|
452
|
+
catch (e) {
|
|
453
|
+
return this.shutdown(`Could not resolve ip address for host '${this.launchConfiguration.host}'`);
|
|
466
454
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
455
|
+
// fetches the device info and parses the xml data to JSON object
|
|
456
|
+
try {
|
|
457
|
+
this.deviceInfo = await roku_deploy_1.rokuDeploy.getDeviceInfo({ host: this.launchConfiguration.host, remotePort: this.launchConfiguration.remotePort, enhance: true, timeout: 4000 });
|
|
458
|
+
if (this.deviceInfo.ecpSettingMode === 'limited') {
|
|
459
|
+
return await this.shutdown(`ECP access is limited on this Roku. Please change it to 'permissive' or 'enabled' and try again. (device: ${this.launchConfiguration.host})`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch (e) {
|
|
463
|
+
if (e instanceof roku_deploy_1.EcpNetworkAccessModeDisabledError) {
|
|
464
|
+
return this.shutdown(`ECP access is disabled on this Roku. Please change it to 'permissive' or 'enabled' and try again. (device: ${this.launchConfiguration.host})`);
|
|
465
|
+
}
|
|
466
|
+
return this.shutdown(`Unable to connect to roku at '${this.launchConfiguration.host}'. Verify the IP address is correct and that the device is powered on and connected to same network as this computer.`);
|
|
467
|
+
}
|
|
468
|
+
if (this.deviceInfo && !this.deviceInfo.developerEnabled) {
|
|
469
|
+
return await this.shutdown(`Developer mode is not enabled for host '${this.launchConfiguration.host}'.`);
|
|
470
|
+
}
|
|
471
|
+
await this.initializeProfiling();
|
|
472
|
+
// everything is ready, send the response to the launch request so the UI can update and configuration can begin
|
|
473
|
+
this.sendResponse(response);
|
|
474
|
+
//initialize all file logging (rokuDevice, debugger, etc)
|
|
475
|
+
this.fileLoggingManager.activate((_d = this.launchConfiguration) === null || _d === void 0 ? void 0 : _d.fileLogging, this.cwd);
|
|
476
|
+
this.projectManager.launchConfiguration = this.launchConfiguration;
|
|
477
|
+
this.breakpointManager.launchConfiguration = this.launchConfiguration;
|
|
478
|
+
this.sendEvent(new Events_1.LaunchStartEvent(this.launchConfiguration));
|
|
479
|
+
this.logger.log('[launchRequest] Packaging and deploying to roku');
|
|
481
480
|
const packageEnd = this.logger.timeStart('log', 'Packaging');
|
|
482
|
-
this.sendLaunchProgress('
|
|
481
|
+
this.sendLaunchProgress('update', `Packaging Project${((_g = (_f = (_e = this.launchConfiguration) === null || _e === void 0 ? void 0 : _e.componentLibraries) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0) > 0 ? 's' : ''}`);
|
|
483
482
|
//build the main project and all component libraries at the same time
|
|
484
483
|
await Promise.all([
|
|
485
484
|
this.prepareMainProject(),
|
|
486
|
-
this.
|
|
485
|
+
this.prepareComponentLibraries(this.launchConfiguration.componentLibraries)
|
|
487
486
|
]);
|
|
488
487
|
//all of the projects have been successfully staged.
|
|
489
488
|
this.stagingDefered.tryResolve();
|
|
@@ -503,10 +502,51 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
503
502
|
catch (e) {
|
|
504
503
|
this.logger.error('Failed to initialize rendezvous tracking', e);
|
|
505
504
|
}
|
|
505
|
+
this.sendLaunchProgress('update', 'Connecting to debug server');
|
|
506
506
|
const connectAdapterEnd = this.logger.timeStart('log', 'Connect adapter');
|
|
507
507
|
this.createRokuAdapter(this.rendezvousTracker);
|
|
508
508
|
await this.connectRokuAdapter();
|
|
509
509
|
connectAdapterEnd();
|
|
510
|
+
// Capabilities that depend on the adapter or device version. The exception-breakpoint
|
|
511
|
+
// FILTER LIST was surfaced in initializeRequest (VS Code only reads it from there).
|
|
512
|
+
// Everything below is read per-action in VS Code, so a CapabilitiesEvent update takes
|
|
513
|
+
// effect dynamically.
|
|
514
|
+
const supportsExceptionBreakpoints = this.rokuAdapter.supportsExceptionBreakpoints;
|
|
515
|
+
this.sendEvent(new debugadapter_1.CapabilitiesEvent({
|
|
516
|
+
supportsLogPoints: !this.enableDebugProtocol,
|
|
517
|
+
supportsExceptionFilterOptions: supportsExceptionBreakpoints,
|
|
518
|
+
supportsExceptionOptions: supportsExceptionBreakpoints,
|
|
519
|
+
supportsConditionalBreakpoints: this.rokuAdapter.supportsConditionalBreakpoints,
|
|
520
|
+
supportsHitConditionalBreakpoints: this.rokuAdapter.supportsHitConditionalBreakpoints
|
|
521
|
+
}));
|
|
522
|
+
this.sendLaunchProgress('update', 'Configuring breakpoints');
|
|
523
|
+
util_1.util.log('Done initializing');
|
|
524
|
+
// notify VS Code that the adapter is ready to receive configuration (breakpoints, etc.)
|
|
525
|
+
// VS Code will respond with setBreakpoints, setExceptionBreakpoints, then configurationDone
|
|
526
|
+
this.sendEvent(new debugadapter_1.InitializedEvent());
|
|
527
|
+
}
|
|
528
|
+
catch (e) {
|
|
529
|
+
//if the message is anything other than compile errors, we want to display the error
|
|
530
|
+
if (!(e instanceof roku_deploy_1.CompileError)) {
|
|
531
|
+
util_1.util.log('Encountered an issue during the launch process');
|
|
532
|
+
util_1.util.log(e === null || e === void 0 ? void 0 : e.stack);
|
|
533
|
+
//send any compile errors to the client
|
|
534
|
+
await ((_h = this.rokuAdapter) === null || _h === void 0 ? void 0 : _h.sendErrors());
|
|
535
|
+
const message = (e instanceof Exceptions_1.SocketConnectionInUseError) ? e.message : ((_j = e === null || e === void 0 ? void 0 : e.stack) !== null && _j !== void 0 ? _j : e);
|
|
536
|
+
await this.shutdown(message, true);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
this.sendLaunchProgress('end', 'Aborted (compile error)');
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
logEnd();
|
|
543
|
+
}
|
|
544
|
+
async configurationDoneRequest(response, args) {
|
|
545
|
+
var _a, _b;
|
|
546
|
+
this.logger.log('configurationDoneRequest');
|
|
547
|
+
super.configurationDoneRequest(response, args);
|
|
548
|
+
let error;
|
|
549
|
+
try {
|
|
510
550
|
await this.runAutomaticSceneGraphCommands(this.launchConfiguration.autoRunSgDebugCommands);
|
|
511
551
|
//press the home button to ensure we're at the home screen
|
|
512
552
|
await this.rokuDeploy.pressHomeButton(this.launchConfiguration.host, this.launchConfiguration.remotePort);
|
|
@@ -563,7 +603,7 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
563
603
|
}
|
|
564
604
|
else {
|
|
565
605
|
const message = 'App exit detected; but launchConfiguration.stopDebuggerOnAppExit is set to false, so keeping debug session running.';
|
|
566
|
-
this.logger.log('[
|
|
606
|
+
this.logger.log('[configurationDoneRequest]', message);
|
|
567
607
|
this.sendEvent(new Events_1.LogOutputEvent(message));
|
|
568
608
|
this.rokuAdapter.once('connected').then(async () => {
|
|
569
609
|
await this.rokuAdapter.setExceptionBreakpoints(this.exceptionBreakpoints);
|
|
@@ -572,6 +612,12 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
572
612
|
});
|
|
573
613
|
//profiling supports connecting to the socket BEFORE a channel is published, so go ahead and connect now
|
|
574
614
|
await this.tryProfilingConnectOnStart();
|
|
615
|
+
//all setBreakpoints requests have arrived by this point (configurationDone is the DAP signal
|
|
616
|
+
//that the client has finished sending configuration). Inject the STOPs and seal zips now.
|
|
617
|
+
await Promise.all([
|
|
618
|
+
this.packageMainProject(),
|
|
619
|
+
this.packageAndHostComponentLibraries(this.launchConfiguration.componentLibraries, this.launchConfiguration.componentLibrariesPort)
|
|
620
|
+
]);
|
|
575
621
|
this.sendLaunchProgress('update', 'Uploading to Roku');
|
|
576
622
|
await this.publish();
|
|
577
623
|
//hack for certain roku devices that lock up when this event is emitted (no idea why!).
|
|
@@ -621,15 +667,14 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
621
667
|
util_1.util.log('Encountered an issue during the publish process');
|
|
622
668
|
util_1.util.log(e === null || e === void 0 ? void 0 : e.stack);
|
|
623
669
|
//send any compile errors to the client
|
|
624
|
-
await ((
|
|
625
|
-
const message = (e instanceof Exceptions_1.SocketConnectionInUseError) ? e.message : ((
|
|
670
|
+
await ((_a = this.rokuAdapter) === null || _a === void 0 ? void 0 : _a.sendErrors());
|
|
671
|
+
const message = (e instanceof Exceptions_1.SocketConnectionInUseError) ? e.message : ((_b = e === null || e === void 0 ? void 0 : e.stack) !== null && _b !== void 0 ? _b : e);
|
|
626
672
|
await this.shutdown(message, true);
|
|
627
673
|
}
|
|
628
674
|
else {
|
|
629
675
|
this.sendLaunchProgress('end', 'Aborted (compile error)');
|
|
630
676
|
}
|
|
631
677
|
}
|
|
632
|
-
logEnd();
|
|
633
678
|
}
|
|
634
679
|
/**
|
|
635
680
|
* Activate all required functionality for profiling
|
|
@@ -830,7 +875,7 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
830
875
|
let didTimeOut = false;
|
|
831
876
|
await Promise.race([
|
|
832
877
|
isConnected,
|
|
833
|
-
util_1.util.sleep(
|
|
878
|
+
util_1.util.sleep(this.publishTimeout).then(() => {
|
|
834
879
|
didTimeOut = true;
|
|
835
880
|
})
|
|
836
881
|
]);
|
|
@@ -1021,7 +1066,6 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
1021
1066
|
* Stage, insert breakpoints, and package the main project
|
|
1022
1067
|
*/
|
|
1023
1068
|
async prepareMainProject() {
|
|
1024
|
-
var _a;
|
|
1025
1069
|
//add the main project
|
|
1026
1070
|
this.projectManager.mainProject = new ProjectManager_1.Project({
|
|
1027
1071
|
rootDir: this.launchConfiguration.rootDir,
|
|
@@ -1041,6 +1085,14 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
1041
1085
|
await this.projectManager.mainProject.stage();
|
|
1042
1086
|
//add the entry breakpoint if stopOnEntry is true
|
|
1043
1087
|
await this.handleEntryBreakpoint();
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Inject breakpoint STOP statements into the staged main project and create the zip package.
|
|
1091
|
+
* Runs after the DAP `InitializedEvent` so client-side `setBreakpoints` requests have landed
|
|
1092
|
+
* before any STOPs are written to the staged .brs files (telnet path) and before the zip is sealed.
|
|
1093
|
+
*/
|
|
1094
|
+
async packageMainProject() {
|
|
1095
|
+
var _a;
|
|
1044
1096
|
//add breakpoint lines to source files and then publish
|
|
1045
1097
|
util_1.util.log('Adding stop statements for active breakpoints');
|
|
1046
1098
|
//write the `stop` statements to every file that has breakpoints (do for telnet, skip for debug protocol)
|
|
@@ -1112,91 +1164,102 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
1112
1164
|
/**
|
|
1113
1165
|
* Stores the path to the staging folder for each component library
|
|
1114
1166
|
*/
|
|
1115
|
-
async
|
|
1116
|
-
if (componentLibraries
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1167
|
+
async prepareComponentLibraries(componentLibraries) {
|
|
1168
|
+
if (!componentLibraries || componentLibraries.length === 0) {
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
let componentLibrariesOutDir = (0, FileUtils_1.standardizePath) `${this.launchConfiguration.outDir}/component-libraries`;
|
|
1172
|
+
//make sure this folder exists (and is empty)
|
|
1173
|
+
await fsExtra.ensureDir(componentLibrariesOutDir);
|
|
1174
|
+
await fsExtra.emptyDir(componentLibrariesOutDir);
|
|
1175
|
+
//create a ComponentLibraryProject for each component library
|
|
1176
|
+
for (let libraryIndex = 0; libraryIndex < componentLibraries.length; libraryIndex++) {
|
|
1177
|
+
let componentLibrary = componentLibraries[libraryIndex];
|
|
1178
|
+
this.projectManager.componentLibraryProjects.push(new ProjectManager_1.ComponentLibraryProject({
|
|
1179
|
+
rootDir: componentLibrary.rootDir,
|
|
1180
|
+
files: componentLibrary.files,
|
|
1181
|
+
outDir: componentLibrariesOutDir,
|
|
1182
|
+
outFile: componentLibrary.outFile,
|
|
1183
|
+
sourceDirs: componentLibrary.sourceDirs,
|
|
1184
|
+
bsConst: componentLibrary.bsConst,
|
|
1185
|
+
install: componentLibrary.install,
|
|
1186
|
+
injectRaleTrackerTask: componentLibrary.injectRaleTrackerTask,
|
|
1187
|
+
raleTrackerTaskFileLocation: componentLibrary.raleTrackerTaskFileLocation,
|
|
1188
|
+
libraryIndex: libraryIndex,
|
|
1189
|
+
enhanceREPLCompletions: this.launchConfiguration.enhanceREPLCompletions
|
|
1190
|
+
}));
|
|
1191
|
+
}
|
|
1192
|
+
//stage all of the libraries in parallel
|
|
1193
|
+
await Promise.all(this.projectManager.componentLibraryProjects.map(compLibProject => compLibProject.stage()));
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Inject breakpoint STOPs into the staged complibs, seal their zips, install installable ones,
|
|
1197
|
+
* and start static file hosting. Runs in `configurationDoneRequest` (after `InitializedEvent`)
|
|
1198
|
+
* so client-side `setBreakpoints` requests have landed before the staged .brs files are written
|
|
1199
|
+
* and the zips are sealed.
|
|
1200
|
+
*/
|
|
1201
|
+
async packageAndHostComponentLibraries(componentLibraries, port) {
|
|
1202
|
+
if (!componentLibraries || componentLibraries.length === 0) {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
const componentLibrariesOutDir = (0, FileUtils_1.standardizePath) `${this.launchConfiguration.outDir}/component-libraries`;
|
|
1206
|
+
// Add breakpoint lines to the staging files and before publishing
|
|
1207
|
+
util_1.util.log('Adding stop statements for active breakpoints in Component Libraries');
|
|
1208
|
+
//write STOPs (telnet only), postfix, and zip each complib in parallel — each targets distinct files
|
|
1209
|
+
const packagePromises = this.projectManager.componentLibraryProjects.map(async (compLibProject) => {
|
|
1210
|
+
if (!this.enableDebugProtocol) {
|
|
1211
|
+
await this.breakpointManager.writeBreakpointsForProject(compLibProject);
|
|
1137
1212
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
await compLibProject.postfixFiles();
|
|
1148
|
-
await compLibProject.zipPackage({ retainStagingFolder: true });
|
|
1213
|
+
await compLibProject.postfixFiles();
|
|
1214
|
+
await compLibProject.zipPackage({ retainStagingFolder: true });
|
|
1215
|
+
});
|
|
1216
|
+
const needToDeleteComplibs = this.projectManager.componentLibraryProjects.some(x => x.install);
|
|
1217
|
+
if (needToDeleteComplibs) {
|
|
1218
|
+
await roku_deploy_1.rokuDeploy.deleteAllComponentLibraries({
|
|
1219
|
+
host: this.launchConfiguration.host,
|
|
1220
|
+
password: this.launchConfiguration.password,
|
|
1221
|
+
username: this.launchConfiguration.username || 'rokudev'
|
|
1149
1222
|
});
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1223
|
+
}
|
|
1224
|
+
for (let i = 0; i < this.projectManager.componentLibraryProjects.length; i++) {
|
|
1225
|
+
const compLibProject = this.projectManager.componentLibraryProjects[i];
|
|
1226
|
+
if (compLibProject.install === true) {
|
|
1227
|
+
//wait for this complib to finish being packaged
|
|
1228
|
+
await packagePromises[i];
|
|
1229
|
+
if (componentLibraries[i].packageTask) {
|
|
1230
|
+
await this.sendCustomRequest('executeTask', { task: componentLibraries[i].packageTask });
|
|
1231
|
+
}
|
|
1232
|
+
const options = {
|
|
1153
1233
|
host: this.launchConfiguration.host,
|
|
1154
1234
|
password: this.launchConfiguration.password,
|
|
1155
|
-
username: this.launchConfiguration.username || 'rokudev'
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
outDir: compLibProject.outDir,
|
|
1173
|
-
outFile: compLibProject.outFile,
|
|
1174
|
-
appType: 'dcl',
|
|
1175
|
-
packageUploadOverrides: componentLibraries[i].packageUploadOverrides || {}
|
|
1176
|
-
};
|
|
1177
|
-
if (componentLibraries[i].packagePath) {
|
|
1178
|
-
options.outDir = path.dirname(componentLibraries[i].packagePath);
|
|
1179
|
-
options.outFile = path.basename(componentLibraries[i].packagePath);
|
|
1180
|
-
}
|
|
1181
|
-
try {
|
|
1182
|
-
await roku_deploy_1.rokuDeploy.publish(options);
|
|
1183
|
-
}
|
|
1184
|
-
catch (error) {
|
|
1185
|
-
this.logger.error(`Error installing component library ${i}`, error);
|
|
1186
|
-
}
|
|
1235
|
+
username: this.launchConfiguration.username || 'rokudev',
|
|
1236
|
+
logLevel: logging_1.LogLevelPriority[this.logger.logLevel],
|
|
1237
|
+
failOnCompileError: true,
|
|
1238
|
+
outDir: compLibProject.outDir,
|
|
1239
|
+
outFile: compLibProject.outFile,
|
|
1240
|
+
appType: 'dcl',
|
|
1241
|
+
packageUploadOverrides: componentLibraries[i].packageUploadOverrides || {}
|
|
1242
|
+
};
|
|
1243
|
+
if (componentLibraries[i].packagePath) {
|
|
1244
|
+
options.outDir = path.dirname(componentLibraries[i].packagePath);
|
|
1245
|
+
options.outFile = path.basename(componentLibraries[i].packagePath);
|
|
1246
|
+
}
|
|
1247
|
+
try {
|
|
1248
|
+
await roku_deploy_1.rokuDeploy.publish(options);
|
|
1249
|
+
}
|
|
1250
|
+
catch (error) {
|
|
1251
|
+
this.logger.error(`Error installing component library ${i}`, error);
|
|
1187
1252
|
}
|
|
1188
1253
|
}
|
|
1189
|
-
let hostingPromise;
|
|
1190
|
-
// prepare static file hosting
|
|
1191
|
-
hostingPromise = this.componentLibraryServer.startStaticFileHosting(componentLibrariesOutDir, port, (message) => {
|
|
1192
|
-
util_1.util.log(message);
|
|
1193
|
-
});
|
|
1194
|
-
//wait for all component libaries to finish building, and the file hosting to start up (if enabled)
|
|
1195
|
-
await Promise.all([
|
|
1196
|
-
...compLibPromises,
|
|
1197
|
-
hostingPromise
|
|
1198
|
-
]);
|
|
1199
1254
|
}
|
|
1255
|
+
const hostingPromise = this.componentLibraryServer.startStaticFileHosting(componentLibrariesOutDir, port, (message) => {
|
|
1256
|
+
util_1.util.log(message);
|
|
1257
|
+
});
|
|
1258
|
+
//wait for all complib packaging to finish and the file hosting to start
|
|
1259
|
+
await Promise.all([
|
|
1260
|
+
...packagePromises,
|
|
1261
|
+
hostingPromise
|
|
1262
|
+
]);
|
|
1200
1263
|
}
|
|
1201
1264
|
sourceRequest(response, args) {
|
|
1202
1265
|
this.logger.log('sourceRequest');
|
|
@@ -1207,9 +1270,6 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
1207
1270
|
};
|
|
1208
1271
|
super.sourceRequest(response, args);
|
|
1209
1272
|
}
|
|
1210
|
-
configurationDoneRequest(response, args) {
|
|
1211
|
-
this.logger.log('configurationDoneRequest');
|
|
1212
|
-
}
|
|
1213
1273
|
/**
|
|
1214
1274
|
* Called every time a breakpoint is created, modified, or deleted, for each file. This receives the entire list of breakpoints every time.
|
|
1215
1275
|
*/
|
|
@@ -2141,9 +2201,19 @@ class BrightScriptDebugSession extends debugadapter_1.LoggingDebugSession {
|
|
|
2141
2201
|
* @param args
|
|
2142
2202
|
*/
|
|
2143
2203
|
async disconnectRequest(response, args, request) {
|
|
2144
|
-
//return to the home screen
|
|
2204
|
+
//return to the home screen — best effort. The device may already be powered off or unreachable
|
|
2205
|
+
//at disconnect time; without a guard pressHomeButton rejects (EHOSTDOWN / ECONNREFUSED / etc)
|
|
2206
|
+
//and because @vscode/debugadapter dispatches this method without awaiting the returned Promise,
|
|
2207
|
+
//that rejection escapes as an unhandledRejection and crashes the DAP process.
|
|
2208
|
+
//See https://github.com/rokucommunity/vscode-brightscript-language/issues/807
|
|
2209
|
+
// https://github.com/rokucommunity/roku-debug/issues/332
|
|
2145
2210
|
if (!this.enableDebugProtocol) {
|
|
2146
|
-
|
|
2211
|
+
try {
|
|
2212
|
+
await this.rokuDeploy.pressHomeButton(this.launchConfiguration.host, this.launchConfiguration.remotePort);
|
|
2213
|
+
}
|
|
2214
|
+
catch (e) {
|
|
2215
|
+
this.logger.warn('Failed to press home button during disconnect; device may be unreachable', e);
|
|
2216
|
+
}
|
|
2147
2217
|
}
|
|
2148
2218
|
this.sendResponse(response);
|
|
2149
2219
|
await this.shutdown();
|