mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
files - implement ctime properly as btime (fix #84525)
This commit is contained in:
parent
d5ff86c8ec
commit
5ae52b61cb
|
@ -23,6 +23,8 @@ suite('workspace-fs', () => {
|
|||
assert.equal(typeof stat.mtime, 'number');
|
||||
assert.equal(typeof stat.ctime, 'number');
|
||||
|
||||
assert.ok(stat.mtime > 0);
|
||||
assert.ok(stat.ctime > 0);
|
||||
|
||||
const entries = await vscode.workspace.fs.readDirectory(root);
|
||||
assert.ok(entries.length > 0);
|
||||
|
|
|
@ -209,6 +209,8 @@ export class FileService extends Disposable implements IFileService {
|
|||
});
|
||||
}
|
||||
|
||||
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial<IStat>, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStat>;
|
||||
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, resolveMetadata: true, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStatWithMetadata>;
|
||||
private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial<IStat>, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise<IFileStat> {
|
||||
|
||||
// convert to file stat
|
||||
|
@ -219,6 +221,7 @@ export class FileService extends Disposable implements IFileService {
|
|||
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
|
||||
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
|
||||
mtime: stat.mtime,
|
||||
ctime: stat.ctime,
|
||||
size: stat.size,
|
||||
etag: etag({ mtime: stat.mtime, size: stat.size })
|
||||
};
|
||||
|
|
|
@ -207,8 +207,17 @@ export enum FileType {
|
|||
|
||||
export interface IStat {
|
||||
type: FileType;
|
||||
|
||||
/**
|
||||
* The last modification date represented as millis from unix epoch.
|
||||
*/
|
||||
mtime: number;
|
||||
|
||||
/**
|
||||
* The creation date represented as millis from unix epoch.
|
||||
*/
|
||||
ctime: number;
|
||||
|
||||
size: number;
|
||||
}
|
||||
|
||||
|
@ -583,14 +592,21 @@ interface IBaseStat {
|
|||
size?: number;
|
||||
|
||||
/**
|
||||
* The last modification date represented
|
||||
* as millis from unix epoch.
|
||||
* The last modification date represented as millis from unix epoch.
|
||||
*
|
||||
* The value may or may not be resolved as
|
||||
* it is optional.
|
||||
*/
|
||||
mtime?: number;
|
||||
|
||||
/**
|
||||
* The creation date represented as millis from unix epoch.
|
||||
*
|
||||
* The value may or may not be resolved as
|
||||
* it is optional.
|
||||
*/
|
||||
ctime?: number;
|
||||
|
||||
/**
|
||||
* A unique identifier thet represents the
|
||||
* current state of the file or directory.
|
||||
|
@ -608,6 +624,7 @@ interface IBaseStat {
|
|||
|
||||
export interface IBaseStatWithMetadata extends IBaseStat {
|
||||
mtime: number;
|
||||
ctime: number;
|
||||
etag: string;
|
||||
size: number;
|
||||
}
|
||||
|
@ -635,6 +652,7 @@ export interface IFileStat extends IBaseStat {
|
|||
|
||||
export interface IFileStatWithMetadata extends IFileStat, IBaseStatWithMetadata {
|
||||
mtime: number;
|
||||
ctime: number;
|
||||
etag: string;
|
||||
size: number;
|
||||
children?: IFileStatWithMetadata[];
|
||||
|
@ -703,7 +721,7 @@ export interface IResolveFileOptions {
|
|||
readonly resolveSingleChildDescendants?: boolean;
|
||||
|
||||
/**
|
||||
* Will resolve mtime, size and etag of files if enabled. This can have a negative impact
|
||||
* Will resolve mtime, ctime, size and etag of files if enabled. This can have a negative impact
|
||||
* on performance and thus should only be used when these values are required.
|
||||
*/
|
||||
readonly resolveMetadata?: boolean;
|
||||
|
|
|
@ -80,7 +80,7 @@ export class DiskFileSystemProvider extends Disposable implements
|
|||
|
||||
return {
|
||||
type: this.toType(stat, isSymbolicLink),
|
||||
ctime: stat.ctime.getTime(),
|
||||
ctime: stat.birthtime.getTime(), // intentionally not using ctime here, we want the creation time
|
||||
mtime: stat.mtime.getTime(),
|
||||
size: stat.size
|
||||
};
|
||||
|
|
|
@ -213,23 +213,32 @@ suite('Disk File Service', function () {
|
|||
assert.equal(exists, false);
|
||||
});
|
||||
|
||||
test('resolve', async () => {
|
||||
const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] });
|
||||
assert.equal(resolved.children!.length, 8);
|
||||
test('resolve - file', async () => {
|
||||
const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver/index.html'));
|
||||
const resolved = await service.resolve(resource);
|
||||
|
||||
const deep = (getByName(resolved, 'deep')!);
|
||||
assert.equal(deep.children!.length, 4);
|
||||
assert.equal(resolved.name, 'index.html');
|
||||
assert.equal(resolved.resource.toString(), resource.toString());
|
||||
assert.equal(resolved.children, undefined);
|
||||
assert.ok(resolved.mtime! > 0);
|
||||
assert.ok(resolved.ctime! > 0);
|
||||
assert.ok(resolved.size! > 0);
|
||||
});
|
||||
|
||||
test('resolve - directory', async () => {
|
||||
const testsElements = ['examples', 'other', 'index.html', 'site.css'];
|
||||
|
||||
const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver')));
|
||||
const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver'));
|
||||
const result = await service.resolve(resource);
|
||||
|
||||
assert.ok(result);
|
||||
assert.equal(result.resource.toString(), resource.toString());
|
||||
assert.equal(result.name, 'resolver');
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result!.isDirectory);
|
||||
assert.ok(result.mtime! > 0);
|
||||
assert.ok(result.ctime! > 0);
|
||||
assert.equal(result.children!.length, testsElements.length);
|
||||
|
||||
assert.ok(result.children!.every(entry => {
|
||||
|
@ -242,12 +251,18 @@ suite('Disk File Service', function () {
|
|||
assert.ok(basename(value.resource.fsPath));
|
||||
if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) {
|
||||
assert.ok(value.isDirectory);
|
||||
assert.equal(value.mtime, undefined);
|
||||
assert.equal(value.ctime, undefined);
|
||||
} else if (basename(value.resource.fsPath) === 'index.html') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
assert.equal(value.mtime, undefined);
|
||||
assert.equal(value.ctime, undefined);
|
||||
} else if (basename(value.resource.fsPath) === 'site.css') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
assert.equal(value.mtime, undefined);
|
||||
assert.equal(value.ctime, undefined);
|
||||
} else {
|
||||
assert.ok(!'Unexpected value ' + basename(value.resource.fsPath));
|
||||
}
|
||||
|
@ -260,9 +275,12 @@ suite('Disk File Service', function () {
|
|||
const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver')), { resolveMetadata: true });
|
||||
|
||||
assert.ok(result);
|
||||
assert.equal(result.name, 'resolver');
|
||||
assert.ok(result.children);
|
||||
assert.ok(result.children!.length > 0);
|
||||
assert.ok(result!.isDirectory);
|
||||
assert.ok(result.mtime! > 0);
|
||||
assert.ok(result.ctime! > 0);
|
||||
assert.equal(result.children!.length, testsElements.length);
|
||||
|
||||
assert.ok(result.children!.every(entry => {
|
||||
|
@ -277,18 +295,32 @@ suite('Disk File Service', function () {
|
|||
assert.ok(basename(value.resource.fsPath));
|
||||
if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) {
|
||||
assert.ok(value.isDirectory);
|
||||
assert.ok(value.mtime! > 0);
|
||||
assert.ok(value.ctime! > 0);
|
||||
} else if (basename(value.resource.fsPath) === 'index.html') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
assert.ok(value.mtime! > 0);
|
||||
assert.ok(value.ctime! > 0);
|
||||
} else if (basename(value.resource.fsPath) === 'site.css') {
|
||||
assert.ok(!value.isDirectory);
|
||||
assert.ok(!value.children);
|
||||
assert.ok(value.mtime! > 0);
|
||||
assert.ok(value.ctime! > 0);
|
||||
} else {
|
||||
assert.ok(!'Unexpected value ' + basename(value.resource.fsPath));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('resolve - directory with resolveTo', async () => {
|
||||
const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] });
|
||||
assert.equal(resolved.children!.length, 8);
|
||||
|
||||
const deep = (getByName(resolved, 'deep')!);
|
||||
assert.equal(deep.children!.length, 4);
|
||||
});
|
||||
|
||||
test('resolve - directory - resolveTo single directory', async () => {
|
||||
const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver');
|
||||
const result = await service.resolve(URI.file(resolverFixturesPath), { resolveTo: [URI.file(join(resolverFixturesPath, 'other/deep'))] });
|
||||
|
|
|
@ -52,7 +52,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
|||
$stat(uri: UriComponents): Promise<IStat> {
|
||||
return this._fileService.resolve(URI.revive(uri), { resolveMetadata: true }).then(stat => {
|
||||
return {
|
||||
ctime: 0,
|
||||
ctime: stat.ctime,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
type: MainThreadFileSystem._getFileType(stat)
|
||||
|
|
|
@ -32,6 +32,7 @@ import { Schemas } from 'vs/base/common/network';
|
|||
|
||||
export interface IBackupMetaData {
|
||||
mtime: number;
|
||||
ctime: number;
|
||||
size: number;
|
||||
etag: string;
|
||||
orphaned: boolean;
|
||||
|
@ -224,6 +225,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
if (isEqual(target, this.resource) && this.lastResolvedFileStat) {
|
||||
meta = {
|
||||
mtime: this.lastResolvedFileStat.mtime,
|
||||
ctime: this.lastResolvedFileStat.ctime,
|
||||
size: this.lastResolvedFileStat.size,
|
||||
etag: this.lastResolvedFileStat.etag,
|
||||
orphaned: this.inOrphanMode
|
||||
|
@ -313,6 +315,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
resource: this.resource,
|
||||
name: basename(this.resource),
|
||||
mtime: resolvedBackup.meta ? resolvedBackup.meta.mtime : Date.now(),
|
||||
ctime: resolvedBackup.meta ? resolvedBackup.meta.ctime : Date.now(),
|
||||
size: resolvedBackup.meta ? resolvedBackup.meta.size : 0,
|
||||
etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown!
|
||||
value: resolvedBackup.value,
|
||||
|
@ -397,6 +400,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
resource: this.resource,
|
||||
name: content.name,
|
||||
mtime: content.mtime,
|
||||
ctime: content.ctime,
|
||||
size: content.size,
|
||||
etag: content.etag,
|
||||
isDirectory: false,
|
||||
|
|
|
@ -262,6 +262,7 @@ export class TestTextFileService extends NativeTextFileService {
|
|||
resource: content.resource,
|
||||
name: content.name,
|
||||
mtime: content.mtime,
|
||||
ctime: content.ctime,
|
||||
etag: content.etag,
|
||||
encoding: 'utf8',
|
||||
value: await createTextBufferFactoryFromStream(content.value),
|
||||
|
@ -996,6 +997,7 @@ export class TestFileService implements IFileService {
|
|||
etag: 'index.txt',
|
||||
encoding: 'utf8',
|
||||
mtime: Date.now(),
|
||||
ctime: Date.now(),
|
||||
name: resources.basename(resource),
|
||||
size: 1
|
||||
});
|
||||
|
@ -1022,6 +1024,7 @@ export class TestFileService implements IFileService {
|
|||
etag: 'index.txt',
|
||||
encoding: 'utf8',
|
||||
mtime: Date.now(),
|
||||
ctime: Date.now(),
|
||||
size: 1,
|
||||
name: resources.basename(resource)
|
||||
});
|
||||
|
@ -1033,6 +1036,7 @@ export class TestFileService implements IFileService {
|
|||
etag: 'index.txt',
|
||||
encoding: 'utf8',
|
||||
mtime: Date.now(),
|
||||
ctime: Date.now(),
|
||||
size: 42,
|
||||
isDirectory: false,
|
||||
name: resources.basename(resource)
|
||||
|
|
Loading…
Reference in a new issue