Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 43 additions & 10 deletions src/service-override/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,64 @@ import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/envir
import { IProductService } from 'vs/platform/product/common/productService.service'
import type { IWorkbenchConstructionOptions } from 'vs/workbench/browser/web.api'
import { getWorkbenchConstructionOptions, getWorkspaceIdentifier, logsPath } from '../workbench'
import type { URI } from 'vs/base/common/uri'

export interface WorkbenchEnvironmentServiceOverrides {
windowLogsPath?: URI
logFile?: URI
userRoamingDataHome?: URI
argvResource?: URI
cacheHome?: URI
workspaceStorageHome?: URI
localHistoryHome?: URI
stateResource?: URI
}

class InjectedBrowserWorkbenchEnvironmentService
extends BrowserWorkbenchEnvironmentService
implements IBrowserWorkbenchEnvironmentService
{
constructor(
workspaceId: string = getWorkspaceIdentifier().id,
options: IWorkbenchConstructionOptions = getWorkbenchConstructionOptions(),
private overrides: WorkbenchEnvironmentServiceOverrides = {},
@IProductService productService: IProductService
) {
super(workspaceId, logsPath, options, productService)
super(workspaceId, logsPath, getWorkbenchConstructionOptions(), productService)
}
}

/**
* @deprecated Provide construction option via the services `initialize` function `configuration` parameter
*/
function getServiceOverride(options: IWorkbenchConstructionOptions): IEditorOverrideServices
function getServiceOverride(): IEditorOverrideServices
override get windowLogsPath() {
return this.overrides.windowLogsPath ?? super.windowLogsPath
}
override get logFile() {
return this.overrides.logFile ?? super.logFile
}
override get userRoamingDataHome() {
return this.overrides.userRoamingDataHome ?? super.userRoamingDataHome
}
override get argvResource() {
return this.overrides.argvResource ?? super.argvResource
}
override get cacheHome() {
return this.overrides.cacheHome ?? super.cacheHome
}
override get workspaceStorageHome() {
return this.overrides.workspaceStorageHome ?? super.workspaceStorageHome
}
override get localHistoryHome() {
return this.overrides.localHistoryHome ?? super.localHistoryHome
}
override get stateResource() {
return this.overrides.stateResource ?? super.stateResource
}
}

function getServiceOverride(options?: IWorkbenchConstructionOptions): IEditorOverrideServices {
function getServiceOverride(
overrides?: WorkbenchEnvironmentServiceOverrides
): IEditorOverrideServices {
return {
[IEnvironmentService.toString()]: new SyncDescriptor(
InjectedBrowserWorkbenchEnvironmentService,
[undefined, options],
[undefined, overrides],
true
)
}
Expand Down
57 changes: 40 additions & 17 deletions src/service-override/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,8 @@ class OverlayFileSystemProvider
capabilities =
FileSystemProviderCapabilities.FileReadWrite |
FileSystemProviderCapabilities.PathCaseSensitive |
FileSystemProviderCapabilities.FileReadStream
FileSystemProviderCapabilities.FileReadStream |
FileSystemProviderCapabilities.FileAppend

private async readFromDelegates<T>(
caller: (delegate: IFileSystemProviderWithFileReadWriteCapability) => Promise<T>,
Expand All @@ -768,29 +769,36 @@ class OverlayFileSystemProvider
if (this.delegates.length === 0) {
throw createFileSystemProviderError('No delegate', FileSystemProviderErrorCode.Unavailable)
}
let firstError: unknown | undefined
const errors: unknown[] = []
for (const delegate of this.delegates) {
if (token != null && token.isCancellationRequested) {
throw new Error('Cancelled')
}
try {
return await caller(delegate)
} catch (err) {
firstError ??= err
if (
err instanceof FileSystemProviderError &&
[
FileSystemProviderErrorCode.NoPermissions,
FileSystemProviderErrorCode.FileNotFound,
FileSystemProviderErrorCode.Unavailable
].includes(err.code)
) {
continue
errors.push(err)
if (err instanceof FileSystemProviderError) {
if (
[
FileSystemProviderErrorCode.NoPermissions,
FileSystemProviderErrorCode.FileNotFound,
FileSystemProviderErrorCode.Unavailable
].includes(err.code)
) {
continue
}
}
throw err
}
}
throw firstError

const fileSystemErrors = errors?.filter((err) => err instanceof FileSystemProviderError)
const mostRelevantErrors =
fileSystemErrors.find((err) => err.code === FileSystemProviderErrorCode.FileNotFound) ??
fileSystemErrors[0] ??
errors[0]
throw mostRelevantErrors
}

private async writeToDelegates(
Expand Down Expand Up @@ -951,7 +959,7 @@ class OverlayFileSystemProvider
}
}

class DelegateFileSystemProvider implements IFileSystemProvider {
class DelegateFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability {
constructor(
private options: {
delegate: IFileSystemProvider
Expand All @@ -977,17 +985,32 @@ class DelegateFileSystemProvider implements IFileSystemProvider {
? (resource: URI): Promise<Uint8Array> => {
return this.options.delegate.readFile!(this.options.toDelegate(resource))
}
: undefined
: () => {
throw createFileSystemProviderError(
'No delegate',
FileSystemProviderErrorCode.Unavailable
)
}

writeFile =
this.options.delegate.writeFile != null
? (resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void> => {
return this.options.delegate.writeFile!(this.options.toDelegate(resource), content, opts)
}
: undefined
: () => {
throw createFileSystemProviderError(
'No delegate',
FileSystemProviderErrorCode.Unavailable
)
}

watch(resource: URI, opts: IWatchOptions): IDisposable {
return this.options.delegate.watch(this.options.toDelegate(resource), opts)
try {
return this.options.delegate.watch(this.options.toDelegate(resource), opts)
} catch {
// ignore watch error
}
return Disposable.None
}

stat(resource: URI): Promise<IStat> {
Expand Down
Loading