mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 01:25:36 -05:00
Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 (#15681)
* Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 * Fixes and cleanup * Distro * Fix hygiene yarn * delete no yarn lock changes file * Fix hygiene * Fix layer check * Fix CI * Skip lib checks * Remove tests deleted in vs code * Fix tests * Distro * Fix tests and add removed extension point * Skip failing notebook tests for now * Disable broken tests and cleanup build folder * Update yarn.lock and fix smoke tests * Bump sqlite * fix contributed actions and file spacing * Fix user data path * Update yarn.locks Co-authored-by: ADS Merger <karlb@microsoft.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
import { open, close, read, write, fdatasync, Stats, promises } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { IDisposable, Disposable, toDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files';
|
||||
import { FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, IFileSystemProviderWithFileFolderCopyCapability, isFileOpenForWriteOptions } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
@@ -30,7 +30,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
export interface IWatcherOptions {
|
||||
pollingInterval?: number;
|
||||
usePolling: boolean;
|
||||
usePolling: boolean | string[];
|
||||
}
|
||||
|
||||
export interface IDiskFileSystemProviderOptions {
|
||||
@@ -64,7 +64,8 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
FileSystemProviderCapabilities.FileReadWrite |
|
||||
FileSystemProviderCapabilities.FileOpenReadWriteClose |
|
||||
FileSystemProviderCapabilities.FileReadStream |
|
||||
FileSystemProviderCapabilities.FileFolderCopy;
|
||||
FileSystemProviderCapabilities.FileFolderCopy |
|
||||
FileSystemProviderCapabilities.FileWriteUnlock;
|
||||
|
||||
if (isLinux) {
|
||||
this._capabilities |= FileSystemProviderCapabilities.PathCaseSensitive;
|
||||
@@ -188,12 +189,12 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
}
|
||||
|
||||
// Open
|
||||
handle = await this.open(resource, { create: true });
|
||||
handle = await this.open(resource, { create: true, unlock: opts.unlock });
|
||||
|
||||
// Write content at once
|
||||
await this.write(handle, 0, content, 0, content.byteLength);
|
||||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
throw await this.toFileSystemProviderWriteError(resource, error);
|
||||
} finally {
|
||||
if (typeof handle === 'number') {
|
||||
await this.close(handle);
|
||||
@@ -203,15 +204,28 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
|
||||
private readonly mapHandleToPos: Map<number, number> = new Map();
|
||||
|
||||
private readonly writeHandles: Set<number> = new Set();
|
||||
private readonly writeHandles = new Map<number, URI>();
|
||||
private canFlush: boolean = true;
|
||||
|
||||
async open(resource: URI, opts: FileOpenOptions): Promise<number> {
|
||||
try {
|
||||
const filePath = this.toFilePath(resource);
|
||||
|
||||
// Determine wether to unlock the file (write only)
|
||||
if (isFileOpenForWriteOptions(opts) && opts.unlock) {
|
||||
try {
|
||||
const { stat } = await SymlinkSupport.stat(filePath);
|
||||
if (!(stat.mode & 0o200 /* File mode indicating writable by owner */)) {
|
||||
await promises.chmod(filePath, stat.mode | 0o200);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.trace(error); // ignore any errors here and try to just write
|
||||
}
|
||||
}
|
||||
|
||||
// Determine file flags for opening (read vs write)
|
||||
let flags: string | undefined = undefined;
|
||||
if (opts.create) {
|
||||
if (isFileOpenForWriteOptions(opts)) {
|
||||
if (isWindows) {
|
||||
try {
|
||||
// On Windows and if the file exists, we use a different strategy of saving the file
|
||||
@@ -252,13 +266,17 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
this.mapHandleToPos.set(handle, 0);
|
||||
|
||||
// remember that this handle was used for writing
|
||||
if (opts.create) {
|
||||
this.writeHandles.add(handle);
|
||||
if (isFileOpenForWriteOptions(opts)) {
|
||||
this.writeHandles.set(handle, resource);
|
||||
}
|
||||
|
||||
return handle;
|
||||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
if (isFileOpenForWriteOptions(opts)) {
|
||||
throw await this.toFileSystemProviderWriteError(resource, error);
|
||||
} else {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +406,7 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
|
||||
return bytesWritten;
|
||||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
throw await this.toFileSystemProviderWriteError(this.writeHandles.get(fd), error);
|
||||
} finally {
|
||||
this.updatePos(fd, normalizedPos, bytesWritten);
|
||||
}
|
||||
@@ -690,9 +708,29 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
return createFileSystemProviderError(error, code);
|
||||
}
|
||||
|
||||
private async toFileSystemProviderWriteError(resource: URI | undefined, error: NodeJS.ErrnoException): Promise<FileSystemProviderError> {
|
||||
let fileSystemProviderWriteError = this.toFileSystemProviderError(error);
|
||||
|
||||
// If the write error signals permission issues, we try
|
||||
// to read the file's mode to see if the file is write
|
||||
// locked.
|
||||
if (resource && fileSystemProviderWriteError.code === FileSystemProviderErrorCode.NoPermissions) {
|
||||
try {
|
||||
const { stat } = await SymlinkSupport.stat(this.toFilePath(resource));
|
||||
if (!(stat.mode & 0o200 /* File mode indicating writable by owner */)) {
|
||||
fileSystemProviderWriteError = createFileSystemProviderError(error, FileSystemProviderErrorCode.FileWriteLocked);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.trace(error); // ignore - return original error
|
||||
}
|
||||
}
|
||||
|
||||
return fileSystemProviderWriteError;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
dispose(this.recursiveWatcher);
|
||||
|
||||
@@ -124,7 +124,7 @@ export class FileWatcher extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.isDisposed = true;
|
||||
|
||||
super.dispose();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nsfw from 'vscode-nsfw';
|
||||
import * as nsfw from 'nsfw';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
@@ -61,9 +61,7 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
|
||||
});
|
||||
|
||||
// Logging
|
||||
if (this.verboseLogging) {
|
||||
this.log(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
|
||||
}
|
||||
this.debug(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
|
||||
|
||||
// Stop watching some roots
|
||||
rootsToStopWatching.forEach(root => {
|
||||
@@ -133,9 +131,7 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.verboseLogging) {
|
||||
this.log(`Start watching with nsfw: ${request.path}`);
|
||||
}
|
||||
this.debug(`Start watching with nsfw: ${request.path}`);
|
||||
|
||||
nsfw(request.path, events => {
|
||||
for (const e of events) {
|
||||
@@ -249,4 +245,8 @@ export class NsfwWatcherService extends Disposable implements IWatcherService {
|
||||
private error(message: string) {
|
||||
this._onDidLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message });
|
||||
}
|
||||
|
||||
private debug(message: string) {
|
||||
this._onDidLogMessage.fire({ type: 'debug', message: `[File Watcher (nsfw)] ` + message });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher';
|
||||
suite('NSFW Watcher Service', async () => {
|
||||
|
||||
// Load `nsfwWatcherService` within the suite to prevent all tests
|
||||
// from failing to start if `vscode-nsfw` was not properly installed
|
||||
// from failing to start if `nsfw` was not properly installed
|
||||
const { NsfwWatcherService } = await import('vs/platform/files/node/watcher/nsfw/nsfwWatcherService');
|
||||
|
||||
class TestNsfwWatcherService extends NsfwWatcherService {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import { Server } from 'vs/base/parts/ipc/node/ipc.cp';
|
||||
import { NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/nsfwWatcherService';
|
||||
import { createChannelReceiver } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
|
||||
const server = new Server('watcher');
|
||||
const service = new NsfwWatcherService();
|
||||
server.registerChannel('watcher', createChannelReceiver(service));
|
||||
server.registerChannel('watcher', ProxyChannel.fromService(service));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createChannelSender, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ProxyChannel, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Client } from 'vs/base/parts/ipc/node/ipc.cp';
|
||||
import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -61,7 +61,7 @@ export class FileWatcher extends Disposable {
|
||||
}));
|
||||
|
||||
// Initialize watcher
|
||||
this.service = createChannelSender<IWatcherService>(getNextTickChannel(client.getChannel('watcher')));
|
||||
this.service = ProxyChannel.toService<IWatcherService>(getNextTickChannel(client.getChannel('watcher')));
|
||||
|
||||
this.service.setVerboseLogging(this.verboseLogging);
|
||||
|
||||
@@ -91,7 +91,7 @@ export class FileWatcher extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.isDisposed = true;
|
||||
|
||||
super.dispose();
|
||||
|
||||
@@ -49,7 +49,7 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
|
||||
get wacherCount() { return this._watcherCount; }
|
||||
|
||||
private pollingInterval?: number;
|
||||
private usePolling?: boolean;
|
||||
private usePolling?: boolean | string[];
|
||||
private verboseLogging: boolean | undefined;
|
||||
|
||||
private spamCheckStartTime: number | undefined;
|
||||
@@ -101,7 +101,11 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
|
||||
|
||||
private watch(basePath: string, requests: IWatcherRequest[]): IWatcher {
|
||||
const pollingInterval = this.pollingInterval || 5000;
|
||||
const usePolling = this.usePolling;
|
||||
let usePolling = this.usePolling; // boolean or a list of path patterns
|
||||
if (Array.isArray(usePolling)) {
|
||||
// switch to polling if one of the paths matches with a watched path
|
||||
usePolling = usePolling.some(pattern => requests.some(r => glob.match(pattern, r.path)));
|
||||
}
|
||||
|
||||
const watcherOpts: chokidar.WatchOptions = {
|
||||
ignoreInitial: true,
|
||||
@@ -142,9 +146,7 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
|
||||
this.warn(`Watcher basePath does not match version on disk and was corrected (original: ${basePath}, real: ${realBasePath})`);
|
||||
}
|
||||
|
||||
if (this.verboseLogging) {
|
||||
this.log(`Start watching with chokidar: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);
|
||||
}
|
||||
this.debug(`Start watching with chokidar: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);
|
||||
|
||||
let chokidarWatcher: chokidar.FSWatcher | null = chokidar.watch(realBasePath, watcherOpts);
|
||||
this._watcherCount++;
|
||||
@@ -297,6 +299,10 @@ export class ChokidarWatcherService extends Disposable implements IWatcherServic
|
||||
this._onDidLogMessage.fire({ type: 'trace', message: `[File Watcher (chokidar)] ` + message });
|
||||
}
|
||||
|
||||
private debug(message: string) {
|
||||
this._onDidLogMessage.fire({ type: 'debug', message: `[File Watcher (chokidar)] ` + message });
|
||||
}
|
||||
|
||||
private warn(message: string) {
|
||||
this._onDidLogMessage.fire({ type: 'warn', message: `[File Watcher (chokidar)] ` + message });
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface IWatcherRequest {
|
||||
|
||||
export interface IWatcherOptions {
|
||||
pollingInterval?: number;
|
||||
usePolling?: boolean;
|
||||
usePolling?: boolean | string[]; // boolean or a set of glob patterns matching folders that need polling
|
||||
verboseLogging?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import { Server } from 'vs/base/parts/ipc/node/ipc.cp';
|
||||
import { ChokidarWatcherService } from 'vs/platform/files/node/watcher/unix/chokidarWatcherService';
|
||||
import { createChannelReceiver } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
|
||||
const server = new Server('watcher');
|
||||
const service = new ChokidarWatcherService();
|
||||
server.registerChannel('watcher', createChannelReceiver(service));
|
||||
server.registerChannel('watcher', ProxyChannel.fromService(service));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createChannelSender, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ProxyChannel, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Client } from 'vs/base/parts/ipc/node/ipc.cp';
|
||||
import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -62,7 +62,7 @@ export class FileWatcher extends Disposable {
|
||||
}));
|
||||
|
||||
// Initialize watcher
|
||||
this.service = createChannelSender<IWatcherService>(getNextTickChannel(client.getChannel('watcher')));
|
||||
this.service = ProxyChannel.toService<IWatcherService>(getNextTickChannel(client.getChannel('watcher')));
|
||||
this.service.init({ ...this.watcherOptions, verboseLogging: this.verboseLogging });
|
||||
|
||||
this._register(this.service.onDidChangeFile(e => !this.isDisposed && this.onDidFilesChange(e)));
|
||||
@@ -92,7 +92,7 @@ export class FileWatcher extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.isDisposed = true;
|
||||
|
||||
super.dispose();
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface IDiskFileChange {
|
||||
}
|
||||
|
||||
export interface ILogMessage {
|
||||
type: 'trace' | 'warn' | 'error';
|
||||
type: 'trace' | 'warn' | 'error' | 'info' | 'debug';
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user