Skip to content

Commit b7b5bd7

Browse files
Use the new API for stat (async-only and not lstat).
1 parent a152544 commit b7b5bd7

File tree

5 files changed

+318
-185
lines changed

5 files changed

+318
-185
lines changed

src/client/common/platform/fileSystem.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ import {
2323

2424
const ENCODING: string = 'utf8';
2525

26+
function convertFileStat(stat: fsextra.Stats): FileStat {
27+
let fileType = FileType.Unknown;
28+
if (stat.isFile()) {
29+
fileType = FileType.File;
30+
} else if (stat.isDirectory()) {
31+
fileType = FileType.Directory;
32+
} else if (stat.isSymbolicLink()) {
33+
fileType = FileType.SymbolicLink;
34+
}
35+
return {
36+
type: fileType,
37+
size: stat.size,
38+
ctime: stat.ctimeMs,
39+
mtime: stat.mtimeMs
40+
};
41+
}
42+
2643
// This is the parts of the vscode.workspace.fs API that we use here.
2744
interface INewAPI {
2845
//copy(source: vscode.Uri, target: vscode.Uri, options?: {overwrite: boolean}): Thenable<void>;
@@ -31,7 +48,7 @@ interface INewAPI {
3148
readDirectory(uri: vscode.Uri): Thenable<[string, FileType][]>;
3249
readFile(uri: vscode.Uri): Thenable<Uint8Array>;
3350
//rename(source: vscode.Uri, target: vscode.Uri, options?: {overwrite: boolean}): Thenable<void>;
34-
//stat(uri: vscode.Uri): Thenable<vscode.FileStat>;
51+
stat(uri: vscode.Uri): Thenable<FileStat>;
3552
//writeFile(uri: vscode.Uri, content: Uint8Array): Thenable<void>;
3653
}
3754

@@ -49,7 +66,6 @@ interface IRawFSExtra {
4966
chmod(filePath: string, mode: string | number): Promise<void>;
5067
//tslint:disable-next-line:no-any
5168
writeFile(path: string, data: any, options: any): Promise<void>;
52-
stat(filename: string): Promise<fsextra.Stats>;
5369
lstat(filename: string): Promise<fsextra.Stats>;
5470
mkdirp(dirname: string): Promise<void>;
5571

@@ -96,6 +112,11 @@ export class RawFileSystem implements IRawFileSystem {
96112
});
97113
}
98114

115+
public async stat(filename: string): Promise<FileStat> {
116+
const uri = vscode.Uri.file(filename);
117+
return this.newapi.stat(uri);
118+
}
119+
99120
public async listdir(dirname: string): Promise<[string, FileType][]> {
100121
const uri = vscode.Uri.file(dirname);
101122
return this.newapi.readDirectory(uri);
@@ -119,12 +140,10 @@ export class RawFileSystem implements IRawFileSystem {
119140
return this.fsExtra.chmod(filename, mode);
120141
}
121142

122-
public async stat(filename: string): Promise<FileStat> {
123-
return this.fsExtra.stat(filename);
124-
}
125-
126143
public async lstat(filename: string): Promise<FileStat> {
127-
return this.fsExtra.lstat(filename);
144+
// At the moment the new VS Code API does not seem to support lstat...
145+
const stat = await this.fsExtra.lstat(filename);
146+
return convertFileStat(stat);
128147
}
129148

130149
public async copyFile(src: string, dest: string): Promise<void> {
@@ -165,7 +184,8 @@ export class RawFileSystem implements IRawFileSystem {
165184
// non-async (fs-extra)
166185

167186
public statSync(filename: string): FileStat {
168-
return this.fsExtra.statSync(filename);
187+
const stat = this.fsExtra.statSync(filename);
188+
return convertFileStat(stat);
169189
}
170190

171191
public readTextSync(filename: string): string {
@@ -262,15 +282,11 @@ export class FileSystemUtils implements IFileSystemUtils {
262282
} catch (err) {
263283
return false;
264284
}
285+
265286
if (fileType === undefined) {
266287
return true;
267-
} else if (fileType === FileType.File) {
268-
return stat.isFile();
269-
} else if (fileType === FileType.Directory) {
270-
return stat.isDirectory();
271-
} else {
272-
return false;
273288
}
289+
return stat.type === fileType;
274290
}
275291
public async fileExists(filename: string): Promise<boolean> {
276292
return this.pathExists(filename, FileType.File);
@@ -320,7 +336,7 @@ export class FileSystemUtils implements IFileSystemUtils {
320336

321337
public async getFileHash(filename: string): Promise<string> {
322338
const stat = await this.raw.lstat(filename);
323-
const data = `${stat.ctimeMs}-${stat.mtimeMs}`;
339+
const data = `${stat.ctime}-${stat.mtime}`;
324340
return this.getHash(data);
325341
}
326342

@@ -367,12 +383,8 @@ export class FileSystem extends FileSystemUtils implements IFileSystem {
367383
//****************************
368384
// aliases
369385

370-
public async stat(filePath: string): Promise<vscode.FileStat> {
371-
// Do not import vscode directly, as this isn't available in the Debugger Context.
372-
// If stat is used in debugger context, it will fail, however theres a separate PR that will resolve this.
373-
// tslint:disable-next-line: no-require-imports
374-
const vsc = require('vscode');
375-
return vsc.workspace.fs.stat(vscode.Uri.file(filePath));
386+
public async stat(filePath: string): Promise<FileStat> {
387+
return this.raw.stat(filePath);
376388
}
377389

378390
public async readFile(filename: string): Promise<string> {

src/client/common/platform/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
'use strict';
55

66
import * as fs from 'fs';
7-
import * as fsextra from 'fs-extra';
87
import { SemVer } from 'semver';
98
import * as vscode from 'vscode';
109
import { Architecture, OSType } from '../utils/platform';
@@ -42,7 +41,7 @@ export type TemporaryDirectory = vscode.Disposable & {
4241
};
4342

4443
export import FileType = vscode.FileType;
45-
export type FileStat = fsextra.Stats;
44+
export type FileStat = vscode.FileStat;
4645
export type WriteStream = fs.WriteStream;
4746

4847
// Later we will drop "IFileSystem", switching usage to
@@ -101,7 +100,7 @@ export interface IFileSystemUtils {
101100
// more aliases (to cause less churn)
102101
export const IFileSystem = Symbol('IFileSystem');
103102
export interface IFileSystem extends IFileSystemUtils {
104-
stat(filePath: string): Promise<vscode.FileStat>;
103+
stat(filePath: string): Promise<FileStat>;
105104
readFile(filename: string): Promise<string>;
106105
writeFile(filename: string, data: {}): Promise<void>;
107106
chmod(filename: string, mode: string): Promise<void>;

src/test/common/platform/filesystem.functional.test.ts

Lines changed: 35 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -218,47 +218,17 @@ suite('Raw FileSystem', () => {
218218
});
219219
});
220220

221-
suite('stat', () => {
222-
test('gets the info for an existing file', async () => {
223-
const filename = await fix.createFile('x/y/z/spam.py', '...');
224-
const expected = await fsextra.stat(filename);
225-
226-
const stat = await filesystem.stat(filename);
227-
228-
expect(stat).to.deep.equal(expected);
229-
});
230-
231-
test('gets the info for an existing directory', async () => {
232-
const dirname = await fix.createDirectory('x/y/z/spam');
233-
const expected = await fsextra.stat(dirname);
234-
235-
const stat = await filesystem.stat(dirname);
236-
237-
expect(stat).to.deep.equal(expected);
238-
});
239-
240-
test('for symlinks, gets the info for the linked file', async () => {
241-
const filename = await fix.createFile('x/y/z/spam.py', '...');
242-
const symlink = await fix.createSymlink('x/y/z/eggs.py', filename);
243-
const expected = await fsextra.stat(filename);
244-
245-
const stat = await filesystem.stat(symlink);
246-
247-
expect(stat).to.deep.equal(expected);
248-
});
249-
250-
test('fails if the file does not exist', async () => {
251-
const promise = filesystem.stat(DOES_NOT_EXIST);
252-
253-
await expect(promise).to.eventually.be.rejected;
254-
});
255-
});
256-
257221
suite('lstat', () => {
258222
test('for symlinks, gives the link info', async () => {
259223
const filename = await fix.createFile('x/y/z/spam.py', '...');
260224
const symlink = await fix.createSymlink('x/y/z/eggs.py', filename);
261-
const expected = await fsextra.lstat(symlink);
225+
const old = await fsextra.lstat(symlink);
226+
const expected = {
227+
type: FileType.SymbolicLink,
228+
size: old.size,
229+
ctime: old.ctimeMs,
230+
mtime: old.mtimeMs
231+
};
262232

263233
const stat = await filesystem.lstat(symlink);
264234

@@ -267,7 +237,13 @@ suite('Raw FileSystem', () => {
267237

268238
test('for normal files, gives the file info', async () => {
269239
const filename = await fix.createFile('x/y/z/spam.py', '...');
270-
const expected = await fsextra.stat(filename);
240+
const old = await fsextra.stat(filename);
241+
const expected = {
242+
type: FileType.File,
243+
size: old.size,
244+
ctime: old.ctimeMs,
245+
mtime: old.mtimeMs
246+
};
271247

272248
const stat = await filesystem.lstat(filename);
273249

@@ -356,7 +332,13 @@ suite('Raw FileSystem', () => {
356332
suite('statSync', () => {
357333
test('gets the info for an existing file', async () => {
358334
const filename = await fix.createFile('x/y/z/spam.py', '...');
359-
const expected = await fsextra.stat(filename);
335+
const old = await fsextra.stat(filename);
336+
const expected = {
337+
type: FileType.File,
338+
size: old.size,
339+
ctime: old.ctimeMs,
340+
mtime: old.mtimeMs
341+
};
360342

361343
const stat = filesystem.statSync(filename);
362344

@@ -365,7 +347,13 @@ suite('Raw FileSystem', () => {
365347

366348
test('gets the info for an existing directory', async () => {
367349
const dirname = await fix.createDirectory('x/y/z/spam');
368-
const expected = await fsextra.stat(dirname);
350+
const old = await fsextra.stat(dirname);
351+
const expected = {
352+
type: FileType.Directory,
353+
size: old.size,
354+
ctime: old.ctimeMs,
355+
mtime: old.mtimeMs
356+
};
369357

370358
const stat = filesystem.statSync(dirname);
371359

@@ -375,7 +363,13 @@ suite('Raw FileSystem', () => {
375363
test('for symlinks, gets the info for the linked file', async () => {
376364
const filename = await fix.createFile('x/y/z/spam.py', '...');
377365
const symlink = await fix.createSymlink('x/y/z/eggs.py', filename);
378-
const expected = await fsextra.stat(filename);
366+
const old = await fsextra.stat(filename);
367+
const expected = {
368+
type: FileType.File,
369+
size: old.size,
370+
ctime: old.ctimeMs,
371+
mtime: old.mtimeMs
372+
};
379373

380374
const stat = filesystem.statSync(symlink);
381375

@@ -632,100 +626,6 @@ suite('FileSystem Utils', () => {
632626
}
633627
});
634628

635-
suite('pathExists', () => {
636-
test('file missing (any})', async () => {
637-
const exists = await utils.pathExists(DOES_NOT_EXIST);
638-
639-
expect(exists).to.equal(false);
640-
});
641-
642-
Object.keys(FileType).forEach(ft => {
643-
test(`file missing (${ft})`, async () => {
644-
//tslint:disable-next-line:no-any
645-
const exists = await utils.pathExists(DOES_NOT_EXIST, ft as any as FileType);
646-
647-
expect(exists).to.equal(false);
648-
});
649-
});
650-
651-
test('any', async () => {
652-
const filename = await fix.createFile('x/y/z/spam.py');
653-
654-
const exists = await utils.pathExists(filename);
655-
656-
expect(exists).to.equal(true);
657-
});
658-
659-
test('want file, got file', async () => {
660-
const filename = await fix.createFile('x/y/z/spam.py');
661-
662-
const exists = await utils.pathExists(filename, FileType.File);
663-
664-
expect(exists).to.equal(true);
665-
});
666-
667-
test('want file, not file', async () => {
668-
const filename = await fix.createDirectory('x/y/z/spam.py');
669-
670-
const exists = await utils.pathExists(filename, FileType.File);
671-
672-
expect(exists).to.equal(false);
673-
});
674-
675-
test('want directory, got directory', async () => {
676-
const dirname = await fix.createDirectory('x/y/z/spam');
677-
678-
const exists = await utils.pathExists(dirname, FileType.Directory);
679-
680-
expect(exists).to.equal(true);
681-
});
682-
683-
test('want directory, not directory', async () => {
684-
const dirname = await fix.createFile('x/y/z/spam');
685-
686-
const exists = await utils.pathExists(dirname, FileType.Directory);
687-
688-
expect(exists).to.equal(false);
689-
});
690-
691-
test('symlink', async () => {
692-
const filename = await fix.createFile('x/y/z/spam.py', '...');
693-
const symlink = await fix.createSymlink('x/y/z/eggs.py', filename);
694-
695-
const exists = await utils.pathExists(symlink, FileType.SymbolicLink);
696-
697-
expect(exists).to.equal(false);
698-
});
699-
700-
test('unknown', async () => {
701-
const sockFile = await fix.createSocket('x/y/z/ipc.sock');
702-
703-
const exists = await utils.pathExists(sockFile, FileType.Unknown);
704-
705-
expect(exists).to.equal(false);
706-
});
707-
});
708-
709-
suite('fileExists', () => {
710-
test('want file, got file', async () => {
711-
const filename = await fix.createFile('x/y/z/spam.py');
712-
713-
const exists = await utils.fileExists(filename);
714-
715-
expect(exists).to.equal(true);
716-
});
717-
});
718-
719-
suite('directoryExists', () => {
720-
test('want directory, got directory', async () => {
721-
const dirname = await fix.createDirectory('x/y/z/spam');
722-
723-
const exists = await utils.directoryExists(dirname);
724-
725-
expect(exists).to.equal(true);
726-
});
727-
});
728-
729629
suite('pathExistsSync', () => {
730630
test('exists', async () => {
731631
const filename = await fix.createFile('x/y/z/spam.py');

0 commit comments

Comments
 (0)