diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 4b2178b0fad..f22b7c60f6c 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -104,6 +104,11 @@ const vscodeResourceIncludes = [ // Process Explorer 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.html', + // --- Start Positron --- + // Positron Help + 'out-build/vs/workbench/contrib/positronHelp/browser/resources/help.html', + // --- End Positron --- + // Tree Sitter highlights 'out-build/vs/editor/common/languages/highlights/*.scm', diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index f918bfba1fa..c4512cd2cbc 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -57,11 +57,6 @@ const vscodeWebResourceIncludes = [ // Webview 'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}', - // --- Start Positron --- - // Positron Help - 'out-build/vs/workbench/contrib/positronHelp/browser/resources/help.html', - // --- End Positron --- - // Tree Sitter highlights 'out-build/vs/editor/common/languages/highlights/*.scm', diff --git a/build/lib/extensions.js b/build/lib/extensions.js index f61140a8c6b..a2602610175 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -108,8 +108,23 @@ function fromLocalWebpack(extensionPath, webpackConfigFileName, disableMangle) { // local extensions so we can use the vsce.PackageManager.None config to ignore dependencies list // as a temporary workaround. // --- Start Positron --- + // As noted above in the TODO, the upstream strategy is currently to ignore + // external dependencies, and some built-in extensions (e.g. git) do not + // package correctly with the Npm strategy. However, several Positron + // extensions have npm dependencies that need to be packaged. This list is + // used to determine which extensions should be packaged with the Npm + // strategy. + const extensionsWithNpmDeps = [ + 'positron-proxy', + 'positron-duckdb' + ]; + // If the extension has npm dependencies, use the Npm package manager + // dependency strategy. + const packageManger = extensionsWithNpmDeps.includes(packageJsonConfig.name) ? + vsce.PackageManager.Npm : + vsce.PackageManager.None; // Replace vsce.listFiles with listExtensionFiles to queue the work - listExtensionFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.None, packagedDependencies }).then(fileNames => { + listExtensionFiles({ cwd: extensionPath, packageManager: packageManger, packagedDependencies }).then(fileNames => { const files = fileNames .map(fileName => path.join(extensionPath, fileName)) .map(filePath => new File({ @@ -358,10 +373,27 @@ function packageLocalExtensionsStream(forWeb, disableMangle) { .filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true))); - const localExtensionsStream = minifyExtensionResources(es.merge(...localExtensionsDescriptions.map(extension => { - return fromLocal(extension.path, forWeb, disableMangle) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }))); + // --- Start Positron --- + // Process the local extensions serially to avoid running out of file + // descriptors (EMFILE) when building. + const localExtensionsStream = es.through(); + const queue = [...localExtensionsDescriptions]; + function processNext() { + if (queue.length === 0) { + localExtensionsStream.end(); + return; + } + const extension = queue.shift(); + if (!extension) { + return; + } + const stream = fromLocal(extension.path, forWeb, disableMangle) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)) + .pipe(es.through(undefined, processNext)); + stream.pipe(localExtensionsStream, { end: false }); + } + processNext(); + // --- End Positron --- let result; if (forWeb) { result = localExtensionsStream; diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index f8c7344a981..508928335b9 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -112,8 +112,26 @@ function fromLocalWebpack(extensionPath: string, webpackConfigFileName: string, // as a temporary workaround. // --- Start Positron --- + + // As noted above in the TODO, the upstream strategy is currently to ignore + // external dependencies, and some built-in extensions (e.g. git) do not + // package correctly with the Npm strategy. However, several Positron + // extensions have npm dependencies that need to be packaged. This list is + // used to determine which extensions should be packaged with the Npm + // strategy. + const extensionsWithNpmDeps = [ + 'positron-proxy', + 'positron-duckdb' + ]; + + // If the extension has npm dependencies, use the Npm package manager + // dependency strategy. + const packageManger = extensionsWithNpmDeps.includes(packageJsonConfig.name) ? + vsce.PackageManager.Npm : + vsce.PackageManager.None; + // Replace vsce.listFiles with listExtensionFiles to queue the work - listExtensionFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.None, packagedDependencies }).then(fileNames => { + listExtensionFiles({ cwd: extensionPath, packageManager: packageManger, packagedDependencies }).then(fileNames => { const files = fileNames .map(fileName => path.join(extensionPath, fileName)) .map(filePath => new File({ @@ -409,14 +427,34 @@ export function packageLocalExtensionsStream(forWeb: boolean, disableMangle: boo .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true)) ); - const localExtensionsStream = minifyExtensionResources( - es.merge( - ...localExtensionsDescriptions.map(extension => { - return fromLocal(extension.path, forWeb, disableMangle) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }) - ) - ); + + // --- Start Positron --- + + // Process the local extensions serially to avoid running out of file + // descriptors (EMFILE) when building. + + const localExtensionsStream = es.through(); + const queue = [...localExtensionsDescriptions]; + + function processNext() { + if (queue.length === 0) { + localExtensionsStream.end(); + return; + } + + const extension = queue.shift(); + if (!extension) { + return; + } + const stream = fromLocal(extension.path, forWeb, disableMangle) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)) + .pipe(es.through(undefined, processNext)); + + stream.pipe(localExtensionsStream, { end: false }); + } + + processNext(); + // --- End Positron --- let result: Stream; if (forWeb) { diff --git a/src/vs/workbench/contrib/positronHelp/browser/positronHelpService.ts b/src/vs/workbench/contrib/positronHelp/browser/positronHelpService.ts index 45839783e81..4bed5b23821 100644 --- a/src/vs/workbench/contrib/positronHelp/browser/positronHelpService.ts +++ b/src/vs/workbench/contrib/positronHelp/browser/positronHelpService.ts @@ -197,7 +197,14 @@ class PositronHelpService extends Disposable implements IPositronHelpService { // Load the help HTML file. this._fileService.readFile(FileAccess.asFileUri(HELP_HTML_FILE_PATH)) - .then(fileContent => this._helpHTML = fileContent.value.toString()); + .then(fileContent => { + // Set the help HTML to the file's contents. + this._helpHTML = fileContent.value.toString(); + }).catch(error => { + // Set the help HTML to an error message. This will be + // displayed in the Help pane. + this._helpHTML = `

Error Loading Help

Cannot read ${HELP_HTML_FILE_PATH}:

${error}`; + }); // Register onDidColorThemeChange handler. this._register(this._themeService.onDidColorThemeChange(async _colorTheme => {