Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
44ed24d5
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
44ed24d5
编写于
3月 20, 2019
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
files2 - implement resolving
上级
cd10c5bd
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
385 addition
and
94 deletion
+385
-94
src/vs/platform/files/common/files.ts
src/vs/platform/files/common/files.ts
+9
-4
src/vs/workbench/services/files/node/fileService.ts
src/vs/workbench/services/files/node/fileService.ts
+9
-9
src/vs/workbench/services/files/test/electron-browser/fileService.test.ts
.../services/files/test/electron-browser/fileService.test.ts
+0
-28
src/vs/workbench/services/files2/common/fileService2.ts
src/vs/workbench/services/files2/common/fileService2.ts
+138
-12
src/vs/workbench/services/files2/node/diskFileSystemProvider.ts
.../workbench/services/files2/node/diskFileSystemProvider.ts
+18
-3
src/vs/workbench/services/files2/test/node/diskFileService.test.ts
...rkbench/services/files2/test/node/diskFileService.test.ts
+211
-38
未找到文件。
src/vs/platform/files/common/files.ts
浏览文件 @
44ed24d5
...
@@ -701,7 +701,16 @@ export interface IUpdateContentOptions {
...
@@ -701,7 +701,16 @@ export interface IUpdateContentOptions {
}
}
export
interface
IResolveFileOptions
{
export
interface
IResolveFileOptions
{
/**
* Automatically continue resolving children of a directory until the provided resources
* are found.
*/
resolveTo
?:
URI
[];
resolveTo
?:
URI
[];
/**
* Automatically continue resolving children of a directory if the number of children is 1.
*/
resolveSingleChildDescendants
?:
boolean
;
resolveSingleChildDescendants
?:
boolean
;
}
}
...
@@ -1034,10 +1043,6 @@ export interface ILegacyFileService {
...
@@ -1034,10 +1043,6 @@ export interface ILegacyFileService {
onFileChanges
:
Event
<
FileChangesEvent
>
;
onFileChanges
:
Event
<
FileChangesEvent
>
;
onAfterOperation
:
Event
<
FileOperationEvent
>
;
onAfterOperation
:
Event
<
FileOperationEvent
>
;
resolveFile
(
resource
:
URI
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
;
resolveFiles
(
toResolve
:
{
resource
:
URI
,
options
?:
IResolveFileOptions
}[]):
Promise
<
IResolveFileResult
[]
>
;
resolveContent
(
resource
:
URI
,
options
?:
IResolveContentOptions
):
Promise
<
IContent
>
;
resolveContent
(
resource
:
URI
,
options
?:
IResolveContentOptions
):
Promise
<
IContent
>
;
resolveStreamContent
(
resource
:
URI
,
options
?:
IResolveContentOptions
):
Promise
<
IStreamContent
>
;
resolveStreamContent
(
resource
:
URI
,
options
?:
IResolveContentOptions
):
Promise
<
IStreamContent
>
;
...
...
src/vs/workbench/services/files/node/fileService.ts
浏览文件 @
44ed24d5
...
@@ -217,15 +217,6 @@ export class FileService extends Disposable implements ILegacyFileService {
...
@@ -217,15 +217,6 @@ export class FileService extends Disposable implements ILegacyFileService {
return
resource
.
scheme
===
Schemas
.
file
;
return
resource
.
scheme
===
Schemas
.
file
;
}
}
resolveFile
(
resource
:
uri
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
{
return
this
.
resolve
(
resource
,
options
);
}
resolveFiles
(
toResolve
:
{
resource
:
uri
,
options
?:
IResolveFileOptions
}[]):
Promise
<
IResolveFileResult
[]
>
{
return
Promise
.
all
(
toResolve
.
map
(
resourceAndOptions
=>
this
.
resolve
(
resourceAndOptions
.
resource
,
resourceAndOptions
.
options
)
.
then
(
stat
=>
({
stat
,
success
:
true
}),
error
=>
({
stat
:
undefined
,
success
:
false
}))));
}
resolveContent
(
resource
:
uri
,
options
?:
IResolveContentOptions
):
Promise
<
IContent
>
{
resolveContent
(
resource
:
uri
,
options
?:
IResolveContentOptions
):
Promise
<
IContent
>
{
return
this
.
resolveStreamContent
(
resource
,
options
).
then
(
streamContent
=>
{
return
this
.
resolveStreamContent
(
resource
,
options
).
then
(
streamContent
=>
{
return
new
Promise
<
IContent
>
((
resolve
,
reject
)
=>
{
return
new
Promise
<
IContent
>
((
resolve
,
reject
)
=>
{
...
@@ -1092,6 +1083,15 @@ export class FileService extends Disposable implements ILegacyFileService {
...
@@ -1092,6 +1083,15 @@ export class FileService extends Disposable implements ILegacyFileService {
// Tests only
// Tests only
resolveFile
(
resource
:
uri
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
{
return
this
.
resolve
(
resource
,
options
);
}
resolveFiles
(
toResolve
:
{
resource
:
uri
,
options
?:
IResolveFileOptions
}[]):
Promise
<
IResolveFileResult
[]
>
{
return
Promise
.
all
(
toResolve
.
map
(
resourceAndOptions
=>
this
.
resolve
(
resourceAndOptions
.
resource
,
resourceAndOptions
.
options
)
.
then
(
stat
=>
({
stat
,
success
:
true
}),
error
=>
({
stat
:
undefined
,
success
:
false
}))));
}
createFolder
(
resource
:
uri
):
Promise
<
IFileStat
>
{
createFolder
(
resource
:
uri
):
Promise
<
IFileStat
>
{
// 1.) Create folder
// 1.) Create folder
...
...
src/vs/workbench/services/files/test/electron-browser/fileService.test.ts
浏览文件 @
44ed24d5
...
@@ -13,7 +13,6 @@ import { URI as uri } from 'vs/base/common/uri';
...
@@ -13,7 +13,6 @@ import { URI as uri } from 'vs/base/common/uri';
import
*
as
uuid
from
'
vs/base/common/uuid
'
;
import
*
as
uuid
from
'
vs/base/common/uuid
'
;
import
*
as
pfs
from
'
vs/base/node/pfs
'
;
import
*
as
pfs
from
'
vs/base/node/pfs
'
;
import
*
as
encodingLib
from
'
vs/base/node/encoding
'
;
import
*
as
encodingLib
from
'
vs/base/node/encoding
'
;
import
*
as
utils
from
'
vs/workbench/services/files/test/electron-browser/utils
'
;
import
{
TestEnvironmentService
,
TestContextService
,
TestTextResourceConfigurationService
,
TestLifecycleService
,
TestStorageService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
TestEnvironmentService
,
TestContextService
,
TestTextResourceConfigurationService
,
TestLifecycleService
,
TestStorageService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
getRandomTestPath
}
from
'
vs/base/test/node/testUtils
'
;
import
{
getRandomTestPath
}
from
'
vs/base/test/node/testUtils
'
;
import
{
TestNotificationService
}
from
'
vs/platform/notification/test/common/testNotificationService
'
;
import
{
TestNotificationService
}
from
'
vs/platform/notification/test/common/testNotificationService
'
;
...
@@ -456,33 +455,6 @@ suite('FileService', () => {
...
@@ -456,33 +455,6 @@ suite('FileService', () => {
});
});
});
});
test
(
'
resolveFile
'
,
()
=>
{
return
service
.
resolveFile
(
uri
.
file
(
testDir
),
{
resolveTo
:
[
uri
.
file
(
path
.
join
(
testDir
,
'
deep
'
))]
}).
then
(
r
=>
{
assert
.
equal
(
r
.
children
!
.
length
,
8
);
const
deep
=
utils
.
getByName
(
r
,
'
deep
'
)
!
;
assert
.
equal
(
deep
.
children
!
.
length
,
4
);
});
});
test
(
'
resolveFiles
'
,
()
=>
{
return
service
.
resolveFiles
([
{
resource
:
uri
.
file
(
testDir
),
options
:
{
resolveTo
:
[
uri
.
file
(
path
.
join
(
testDir
,
'
deep
'
))]
}
},
{
resource
:
uri
.
file
(
path
.
join
(
testDir
,
'
deep
'
))
}
]).
then
(
res
=>
{
const
r1
=
res
[
0
].
stat
!
;
assert
.
equal
(
r1
.
children
!
.
length
,
8
);
const
deep
=
utils
.
getByName
(
r1
,
'
deep
'
)
!
;
assert
.
equal
(
deep
.
children
!
.
length
,
4
);
const
r2
=
res
[
1
].
stat
!
;
assert
.
equal
(
r2
.
children
!
.
length
,
4
);
assert
.
equal
(
r2
.
name
,
'
deep
'
);
});
});
test
(
'
updateContent
'
,
()
=>
{
test
(
'
updateContent
'
,
()
=>
{
const
resource
=
uri
.
file
(
path
.
join
(
testDir
,
'
small.txt
'
));
const
resource
=
uri
.
file
(
path
.
join
(
testDir
,
'
small.txt
'
));
...
...
src/vs/workbench/services/files2/common/fileService2.ts
浏览文件 @
44ed24d5
...
@@ -4,13 +4,17 @@
...
@@ -4,13 +4,17 @@
*--------------------------------------------------------------------------------------------*/
*--------------------------------------------------------------------------------------------*/
import
{
Disposable
,
IDisposable
,
toDisposable
,
combinedDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
Disposable
,
IDisposable
,
toDisposable
,
combinedDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IFileService
,
IResolveFileOptions
,
IResourceEncodings
,
FileChangesEvent
,
FileOperationEvent
,
IFileSystemProviderRegistrationEvent
,
IFileSystemProvider
,
IFileStat
,
IResolveFileResult
,
IResolveContentOptions
,
IContent
,
IStreamContent
,
ITextSnapshot
,
IUpdateContentOptions
,
ICreateFileOptions
,
IFileSystemProviderActivationEvent
,
FileOperationError
,
FileOperationResult
,
FileOperation
,
FileSystemProviderCapabilities
,
FileType
,
toFileSystemProviderErrorCode
,
FileSystemProviderErrorCode
}
from
'
vs/platform/files/common/files
'
;
import
{
IFileService
,
IResolveFileOptions
,
IResourceEncodings
,
FileChangesEvent
,
FileOperationEvent
,
IFileSystemProviderRegistrationEvent
,
IFileSystemProvider
,
IFileStat
,
IResolveFileResult
,
IResolveContentOptions
,
IContent
,
IStreamContent
,
ITextSnapshot
,
IUpdateContentOptions
,
ICreateFileOptions
,
IFileSystemProviderActivationEvent
,
FileOperationError
,
FileOperationResult
,
FileOperation
,
FileSystemProviderCapabilities
,
FileType
,
toFileSystemProviderErrorCode
,
FileSystemProviderErrorCode
,
IStat
}
from
'
vs/platform/files/common/files
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
ServiceIdentifier
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ServiceIdentifier
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
registerSingleton
}
from
'
vs/platform/instantiation/common/extensions
'
;
import
{
isAbsolutePath
,
dirname
,
basename
,
joinPath
,
isEqual
}
from
'
vs/base/common/resources
'
;
import
{
isAbsolutePath
,
dirname
,
basename
,
joinPath
,
isEqual
}
from
'
vs/base/common/resources
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
TernarySearchTree
}
from
'
vs/base/common/map
'
;
import
{
isNonEmptyArray
}
from
'
vs/base/common/arrays
'
;
import
{
getBaseLabel
}
from
'
vs/base/common/labels
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
export
class
FileService2
extends
Disposable
implements
IFileService
{
export
class
FileService2
extends
Disposable
implements
IFileService
{
...
@@ -29,6 +33,10 @@ export class FileService2 extends Disposable implements IFileService {
...
@@ -29,6 +33,10 @@ export class FileService2 extends Disposable implements IFileService {
_serviceBrand
:
ServiceIdentifier
<
any
>
;
_serviceBrand
:
ServiceIdentifier
<
any
>
;
constructor
(@
ILogService
private
logService
:
ILogService
)
{
super
();
}
//#region File System Provider
//#region File System Provider
private
_onDidChangeFileSystemProviderRegistrations
:
Emitter
<
IFileSystemProviderRegistrationEvent
>
=
this
.
_register
(
new
Emitter
<
IFileSystemProviderRegistrationEvent
>
());
private
_onDidChangeFileSystemProviderRegistrations
:
Emitter
<
IFileSystemProviderRegistrationEvent
>
=
this
.
_register
(
new
Emitter
<
IFileSystemProviderRegistrationEvent
>
());
...
@@ -69,7 +77,7 @@ export class FileService2 extends Disposable implements IFileService {
...
@@ -69,7 +77,7 @@ export class FileService2 extends Disposable implements IFileService {
]);
]);
}
}
activateProvider
(
scheme
:
string
):
Promise
<
void
>
{
a
sync
a
ctivateProvider
(
scheme
:
string
):
Promise
<
void
>
{
// Emit an event that we are about to activate a provider with the given scheme.
// Emit an event that we are about to activate a provider with the given scheme.
// Listeners can participate in the activation by registering a provider for it.
// Listeners can participate in the activation by registering a provider for it.
...
@@ -89,7 +97,7 @@ export class FileService2 extends Disposable implements IFileService {
...
@@ -89,7 +97,7 @@ export class FileService2 extends Disposable implements IFileService {
// If the provider is not yet there, make sure to join on the listeners assuming
// If the provider is not yet there, make sure to join on the listeners assuming
// that it takes a bit longer to register the file system provider.
// that it takes a bit longer to register the file system provider.
return
Promise
.
all
(
joiners
).
then
(()
=>
undefined
);
await
Promise
.
all
(
joiners
);
}
}
canHandleResource
(
resource
:
URI
):
boolean
{
canHandleResource
(
resource
:
URI
):
boolean
{
...
@@ -129,16 +137,134 @@ export class FileService2 extends Disposable implements IFileService {
...
@@ -129,16 +137,134 @@ export class FileService2 extends Disposable implements IFileService {
//#region File Metadata Resolving
//#region File Metadata Resolving
resolveFile
(
resource
:
URI
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
{
async
resolveFile
(
resource
:
URI
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
{
return
this
.
_impl
.
resolveFile
(
resource
,
options
);
try
{
return
await
this
.
doResolveFile
(
resource
,
options
);
}
catch
(
error
)
{
// Specially handle file not found case as file operation result
if
(
toFileSystemProviderErrorCode
(
error
)
===
FileSystemProviderErrorCode
.
FileNotFound
)
{
throw
new
FileOperationError
(
localize
(
'
fileNotFoundError
'
,
"
File not found ({0})
"
,
resource
.
toString
(
true
)),
FileOperationResult
.
FILE_NOT_FOUND
);
}
// Bubble up any other error as is
throw
error
;
}
}
private
async
doResolveFile
(
resource
:
URI
,
options
?:
IResolveFileOptions
):
Promise
<
IFileStat
>
{
const
provider
=
await
this
.
withProvider
(
resource
);
// leverage a trie to check for recursive resolving
const
to
=
options
&&
options
.
resolveTo
;
const
trie
=
TernarySearchTree
.
forPaths
<
true
>
();
trie
.
set
(
resource
.
toString
(),
true
);
if
(
isNonEmptyArray
(
to
))
{
to
.
forEach
(
uri
=>
trie
.
set
(
uri
.
toString
(),
true
));
}
const
stat
=
await
provider
.
stat
(
resource
);
return
await
this
.
toFileStat
(
provider
,
resource
,
stat
,
async
stat
=>
{
// check for recursive resolving
if
(
Boolean
(
trie
.
findSuperstr
(
stat
.
resource
.
toString
())
||
trie
.
get
(
stat
.
resource
.
toString
())))
{
return
true
;
}
// check for resolving single child folders
if
(
stat
.
isDirectory
&&
options
&&
options
.
resolveSingleChildDescendants
)
{
try
{
return
(
await
provider
.
readdir
(
resource
)).
length
===
1
;
}
catch
(
error
)
{
return
false
;
}
}
return
false
;
});
}
private
async
toFileStat
(
provider
:
IFileSystemProvider
,
resource
:
URI
,
stat
:
IStat
,
recurse
:
(
stat
:
IFileStat
)
=>
Promise
<
boolean
>
):
Promise
<
IFileStat
>
{
// convert to file stat
const
fileStat
:
IFileStat
=
{
resource
,
name
:
getBaseLabel
(
resource
),
isDirectory
:
(
stat
.
type
&
FileType
.
Directory
)
!==
0
,
isSymbolicLink
:
(
stat
.
type
&
FileType
.
SymbolicLink
)
!==
0
,
isReadonly
:
!!
(
provider
.
capabilities
&
FileSystemProviderCapabilities
.
Readonly
),
mtime
:
stat
.
mtime
,
size
:
stat
.
size
,
etag
:
stat
.
mtime
.
toString
(
29
)
+
stat
.
size
.
toString
(
31
),
};
// check to recurse for directories
if
(
fileStat
.
isDirectory
&&
await
recurse
(
fileStat
))
{
try
{
const
entries
=
await
provider
.
readdir
(
resource
);
fileStat
.
children
=
await
Promise
.
all
(
entries
.
map
(
async
entry
=>
{
const
childResource
=
joinPath
(
resource
,
entry
[
0
]);
const
childStat
=
await
provider
.
stat
(
childResource
);
return
this
.
toFileStat
(
provider
,
childResource
,
childStat
,
recurse
);
}));
}
catch
(
error
)
{
this
.
logService
.
trace
(
error
);
fileStat
.
children
=
[];
// gracefully handle errors, we may not have permissions to read
}
}
resolveFiles
(
toResolve
:
{
resource
:
URI
;
options
?:
IResolveFileOptions
;
}[]):
Promise
<
IResolveFileResult
[]
>
{
return
fileStat
;
return
this
.
_impl
.
resolveFiles
(
toResolve
);
}
}
existsFile
(
resource
:
URI
):
Promise
<
boolean
>
{
return
Promise
.
resolve
(
fileStat
);
return
this
.
resolveFile
(
resource
).
then
(
_
=>
true
,
error
=>
false
);
}
async
resolveFiles
(
toResolve
:
{
resource
:
URI
;
options
?:
IResolveFileOptions
;
}[]):
Promise
<
IResolveFileResult
[]
>
{
// soft-groupBy, keep order, don't rearrange/merge groups
const
groups
:
Array
<
typeof
toResolve
>
=
[];
let
group
:
typeof
toResolve
|
undefined
;
for
(
const
request
of
toResolve
)
{
if
(
!
group
||
group
[
0
].
resource
.
scheme
!==
request
.
resource
.
scheme
)
{
group
=
[];
groups
.
push
(
group
);
}
group
.
push
(
request
);
}
// resolve files
const
result
:
IResolveFileResult
[]
=
[];
for
(
const
group
of
groups
)
{
for
(
const
groupEntry
of
group
)
{
try
{
const
stat
=
await
this
.
doResolveFile
(
groupEntry
.
resource
,
groupEntry
.
options
);
result
.
push
({
stat
,
success
:
true
});
}
catch
(
error
)
{
this
.
logService
.
trace
(
error
);
result
.
push
({
stat
:
undefined
,
success
:
false
});
}
}
}
return
result
;
}
async
existsFile
(
resource
:
URI
):
Promise
<
boolean
>
{
try
{
await
this
.
resolveFile
(
resource
);
return
true
;
}
catch
(
error
)
{
return
false
;
}
}
}
//#endregion
//#endregion
...
@@ -200,11 +326,11 @@ export class FileService2 extends Disposable implements IFileService {
...
@@ -200,11 +326,11 @@ export class FileService2 extends Disposable implements IFileService {
}
}
break
;
// we have hit a directory that exists -> good
break
;
// we have hit a directory that exists -> good
}
catch
(
e
)
{
}
catch
(
e
rror
)
{
// Bubble up any other error that is not file not found
// Bubble up any other error that is not file not found
if
(
toFileSystemProviderErrorCode
(
e
)
!==
FileSystemProviderErrorCode
.
FileNotFound
)
{
if
(
toFileSystemProviderErrorCode
(
e
rror
)
!==
FileSystemProviderErrorCode
.
FileNotFound
)
{
throw
e
;
throw
e
rror
;
}
}
// Upon error, remember directories that need to be created
// Upon error, remember directories that need to be created
...
...
src/vs/workbench/services/files2/node/diskFileSystemProvider.ts
浏览文件 @
44ed24d5
...
@@ -10,8 +10,9 @@ import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatc
...
@@ -10,8 +10,9 @@ import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatc
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
isLinux
}
from
'
vs/base/common/platform
'
;
import
{
isLinux
}
from
'
vs/base/common/platform
'
;
import
{
statLink
}
from
'
vs/base/node/pfs
'
;
import
{
statLink
,
readdir
}
from
'
vs/base/node/pfs
'
;
import
{
normalize
}
from
'
vs/base/common/path
'
;
import
{
normalize
}
from
'
vs/base/common/path
'
;
import
{
joinPath
}
from
'
vs/base/common/resources
'
;
export
class
DiskFileSystemProvider
extends
Disposable
implements
IFileSystemProvider
{
export
class
DiskFileSystemProvider
extends
Disposable
implements
IFileSystemProvider
{
...
@@ -54,8 +55,22 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
...
@@ -54,8 +55,22 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro
}
}
}
}
readdir
(
resource
:
URI
):
Promise
<
[
string
,
FileType
][]
>
{
async
readdir
(
resource
:
URI
):
Promise
<
[
string
,
FileType
][]
>
{
throw
new
Error
(
'
Method not implemented.
'
);
try
{
const
children
=
await
readdir
(
this
.
toFilePath
(
resource
));
const
result
:
[
string
,
FileType
][]
=
[];
for
(
let
i
=
0
;
i
<
children
.
length
;
i
++
)
{
const
child
=
children
[
i
];
const
stat
=
await
this
.
stat
(
joinPath
(
resource
,
child
));
result
.
push
([
child
,
stat
.
type
]);
}
return
result
;
}
catch
(
error
)
{
throw
this
.
toFileSystemProviderError
(
error
);
}
}
}
//#endregion
//#endregion
...
...
src/vs/workbench/services/files2/test/node/diskFileService.test.ts
浏览文件 @
44ed24d5
...
@@ -10,17 +10,33 @@ import { Schemas } from 'vs/base/common/network';
...
@@ -10,17 +10,33 @@ import { Schemas } from 'vs/base/common/network';
import
{
DiskFileSystemProvider
}
from
'
vs/workbench/services/files2/node/diskFileSystemProvider
'
;
import
{
DiskFileSystemProvider
}
from
'
vs/workbench/services/files2/node/diskFileSystemProvider
'
;
import
{
getRandomTestPath
}
from
'
vs/base/test/node/testUtils
'
;
import
{
getRandomTestPath
}
from
'
vs/base/test/node/testUtils
'
;
import
{
generateUuid
}
from
'
vs/base/common/uuid
'
;
import
{
generateUuid
}
from
'
vs/base/common/uuid
'
;
import
{
join
}
from
'
vs/base/common/path
'
;
import
{
join
,
basename
}
from
'
vs/base/common/path
'
;
import
{
getPathFromAmdModule
}
from
'
vs/base/common/amd
'
;
import
{
getPathFromAmdModule
}
from
'
vs/base/common/amd
'
;
import
{
copy
,
del
}
from
'
vs/base/node/pfs
'
;
import
{
copy
,
del
}
from
'
vs/base/node/pfs
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
existsSync
}
from
'
fs
'
;
import
{
existsSync
}
from
'
fs
'
;
import
{
FileOperation
,
FileOperationEvent
}
from
'
vs/platform/files/common/files
'
;
import
{
FileOperation
,
FileOperationEvent
,
IFileStat
}
from
'
vs/platform/files/common/files
'
;
import
{
FileService
}
from
'
vs/workbench/services/files/node/fileService
'
;
import
{
FileService
}
from
'
vs/workbench/services/files/node/fileService
'
;
import
{
TestContextService
,
TestEnvironmentService
,
TestTextResourceConfigurationService
,
TestLifecycleService
,
TestStorageService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
TestContextService
,
TestEnvironmentService
,
TestTextResourceConfigurationService
,
TestLifecycleService
,
TestStorageService
}
from
'
vs/workbench/test/workbenchTestServices
'
;
import
{
Workspace
,
toWorkspaceFolders
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
Workspace
,
toWorkspaceFolders
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
TestConfigurationService
}
from
'
vs/platform/configuration/test/common/testConfigurationService
'
;
import
{
TestConfigurationService
}
from
'
vs/platform/configuration/test/common/testConfigurationService
'
;
import
{
TestNotificationService
}
from
'
vs/platform/notification/test/common/testNotificationService
'
;
import
{
TestNotificationService
}
from
'
vs/platform/notification/test/common/testNotificationService
'
;
import
{
NullLogService
}
from
'
vs/platform/log/common/log
'
;
import
{
isLinux
}
from
'
vs/base/common/platform
'
;
function
getByName
(
root
:
IFileStat
,
name
:
string
):
IFileStat
|
null
{
if
(
root
.
children
===
undefined
)
{
return
null
;
}
for
(
const
child
of
root
.
children
)
{
if
(
child
.
name
===
name
)
{
return
child
;
}
}
return
null
;
}
suite
(
'
Disk File Service
'
,
()
=>
{
suite
(
'
Disk File Service
'
,
()
=>
{
...
@@ -30,7 +46,7 @@ suite('Disk File Service', () => {
...
@@ -30,7 +46,7 @@ suite('Disk File Service', () => {
let
testDir
:
string
;
let
testDir
:
string
;
setup
(
async
()
=>
{
setup
(
async
()
=>
{
service
=
new
FileService2
();
service
=
new
FileService2
(
new
NullLogService
()
);
service
.
registerProvider
(
Schemas
.
file
,
new
DiskFileSystemProvider
());
service
.
registerProvider
(
Schemas
.
file
,
new
DiskFileSystemProvider
());
const
id
=
generateUuid
();
const
id
=
generateUuid
();
...
@@ -49,60 +65,217 @@ suite('Disk File Service', () => {
...
@@ -49,60 +65,217 @@ suite('Disk File Service', () => {
});
});
test
(
'
createFolder
'
,
async
()
=>
{
test
(
'
createFolder
'
,
async
()
=>
{
let
event
:
FileOperationEvent
;
let
event
:
FileOperationEvent
|
undefined
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
event
=
e
;
event
=
e
;
});
});
return
service
.
resolveFile
(
URI
.
file
(
testDir
)).
then
(
parent
=>
{
const
parent
=
await
service
.
resolveFile
(
URI
.
file
(
testDir
));
const
resource
=
URI
.
file
(
join
(
parent
.
resource
.
fsPath
,
'
newFolder
'
));
const
resource
=
URI
.
file
(
join
(
parent
.
resource
.
fsPath
,
'
newFolder
'
));
return
service
.
createFolder
(
resource
).
then
(
f
=>
{
const
folder
=
await
service
.
createFolder
(
resource
);
assert
.
equal
(
f
.
name
,
'
newFolder
'
);
assert
.
equal
(
existsSync
(
f
.
resource
.
fsPath
),
true
);
assert
.
equal
(
folder
.
name
,
'
newFolder
'
);
assert
.
equal
(
existsSync
(
folder
.
resource
.
fsPath
),
true
);
assert
.
ok
(
event
);
assert
.
ok
(
event
);
assert
.
equal
(
event
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
operation
,
FileOperation
.
CREATE
);
assert
.
equal
(
event
!
.
operation
,
FileOperation
.
CREATE
);
assert
.
equal
(
event
.
target
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
!
.
target
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
target
!
.
isDirectory
,
true
);
assert
.
equal
(
event
!
.
target
!
.
isDirectory
,
true
);
toDispose
.
dispose
();
toDispose
.
dispose
();
});
});
});
});
test
(
'
createFolder: creating multiple folders at once
'
,
function
()
{
test
(
'
createFolder: creating multiple folders at once
'
,
async
function
()
{
let
event
:
FileOperationEvent
;
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
event
=
e
;
event
=
e
;
});
});
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
return
service
.
resolveFile
(
URI
.
file
(
testDir
)).
then
(
parent
=>
{
const
parent
=
await
service
.
resolveFile
(
URI
.
file
(
testDir
));
const
resource
=
URI
.
file
(
join
(
parent
.
resource
.
fsPath
,
...
multiFolderPaths
));
const
resource
=
URI
.
file
(
join
(
parent
.
resource
.
fsPath
,
...
multiFolderPaths
));
return
service
.
createFolder
(
resource
).
then
(
f
=>
{
const
folder
=
await
service
.
createFolder
(
resource
);
const
lastFolderName
=
multiFolderPaths
[
multiFolderPaths
.
length
-
1
];
const
lastFolderName
=
multiFolderPaths
[
multiFolderPaths
.
length
-
1
];
assert
.
equal
(
f
.
name
,
lastFolderName
);
assert
.
equal
(
folder
.
name
,
lastFolderName
);
assert
.
equal
(
existsSync
(
f
.
resource
.
fsPath
),
true
);
assert
.
equal
(
existsSync
(
folder
.
resource
.
fsPath
),
true
);
assert
.
ok
(
event
!
);
assert
.
equal
(
event
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
!
.
operation
,
FileOperation
.
CREATE
);
assert
.
equal
(
event
!
.
target
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
!
.
target
!
.
isDirectory
,
true
);
assert
.
ok
(
event
);
assert
.
equal
(
event
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
operation
,
FileOperation
.
CREATE
);
assert
.
equal
(
event
.
target
!
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
target
!
.
isDirectory
,
true
);
toDispose
.
dispose
();
toDispose
.
dispose
();
});
});
});
});
test
(
'
existsFile
'
,
()
=>
{
test
(
'
existsFile
'
,
async
()
=>
{
return
service
.
existsFile
(
URI
.
file
(
testDir
)).
then
((
exists
)
=>
{
let
exists
=
await
service
.
existsFile
(
URI
.
file
(
testDir
));
assert
.
equal
(
exists
,
true
);
assert
.
equal
(
exists
,
true
);
return
service
.
existsFile
(
URI
.
file
(
testDir
+
'
something
'
)).
then
((
exists
)
=>
{
exists
=
await
service
.
existsFile
(
URI
.
file
(
testDir
+
'
something
'
));
assert
.
equal
(
exists
,
false
);
assert
.
equal
(
exists
,
false
);
});
});
test
(
'
resolveFile
'
,
async
()
=>
{
const
resolved
=
await
service
.
resolveFile
(
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
(
'
resolveFile - directory
'
,
async
()
=>
{
const
testsElements
=
[
'
examples
'
,
'
other
'
,
'
index.html
'
,
'
site.css
'
];
const
result
=
await
service
.
resolveFile
(
URI
.
file
(
getPathFromAmdModule
(
require
,
'
./fixtures/resolver
'
)));
assert
.
ok
(
result
);
assert
.
ok
(
result
.
children
);
assert
.
ok
(
result
.
children
!
.
length
>
0
);
assert
.
ok
(
result
!
.
isDirectory
);
assert
.
equal
(
result
.
children
!
.
length
,
testsElements
.
length
);
assert
.
ok
(
result
.
children
!
.
every
((
entry
)
=>
{
return
testsElements
.
some
((
name
)
=>
{
return
basename
(
entry
.
resource
.
fsPath
)
===
name
;
});
}));
result
.
children
!
.
forEach
((
value
)
=>
{
assert
.
ok
(
basename
(
value
.
resource
.
fsPath
));
if
([
'
examples
'
,
'
other
'
].
indexOf
(
basename
(
value
.
resource
.
fsPath
))
>=
0
)
{
assert
.
ok
(
value
.
isDirectory
);
}
else
if
(
basename
(
value
.
resource
.
fsPath
)
===
'
index.html
'
)
{
assert
.
ok
(
!
value
.
isDirectory
);
assert
.
ok
(
!
value
.
children
);
}
else
if
(
basename
(
value
.
resource
.
fsPath
)
===
'
site.css
'
)
{
assert
.
ok
(
!
value
.
isDirectory
);
assert
.
ok
(
!
value
.
children
);
}
else
{
assert
.
ok
(
!
'
Unexpected value
'
+
basename
(
value
.
resource
.
fsPath
));
}
});
});
test
(
'
resolveFile - directory - resolveTo single directory
'
,
async
()
=>
{
const
resolverFixturesPath
=
getPathFromAmdModule
(
require
,
'
./fixtures/resolver
'
);
const
result
=
await
service
.
resolveFile
(
URI
.
file
(
resolverFixturesPath
),
{
resolveTo
:
[
URI
.
file
(
join
(
resolverFixturesPath
,
'
other/deep
'
))]
});
assert
.
ok
(
result
);
assert
.
ok
(
result
.
children
);
assert
.
ok
(
result
.
children
!
.
length
>
0
);
assert
.
ok
(
result
.
isDirectory
);
const
children
=
result
.
children
!
;
assert
.
equal
(
children
.
length
,
4
);
const
other
=
getByName
(
result
,
'
other
'
);
assert
.
ok
(
other
);
assert
.
ok
(
other
!
.
children
!
.
length
>
0
);
const
deep
=
getByName
(
other
!
,
'
deep
'
);
assert
.
ok
(
deep
);
assert
.
ok
(
deep
!
.
children
!
.
length
>
0
);
assert
.
equal
(
deep
!
.
children
!
.
length
,
4
);
});
test
(
'
resolve directory - resolveTo single directory - mixed casing
'
,
async
()
=>
{
const
resolverFixturesPath
=
getPathFromAmdModule
(
require
,
'
./fixtures/resolver
'
);
const
result
=
await
service
.
resolveFile
(
URI
.
file
(
resolverFixturesPath
),
{
resolveTo
:
[
URI
.
file
(
join
(
resolverFixturesPath
,
'
other/Deep
'
))]
});
assert
.
ok
(
result
);
assert
.
ok
(
result
.
children
);
assert
.
ok
(
result
.
children
!
.
length
>
0
);
assert
.
ok
(
result
.
isDirectory
);
const
children
=
result
.
children
;
assert
.
equal
(
children
!
.
length
,
4
);
const
other
=
getByName
(
result
,
'
other
'
);
assert
.
ok
(
other
);
assert
.
ok
(
other
!
.
children
!
.
length
>
0
);
const
deep
=
getByName
(
other
!
,
'
deep
'
);
if
(
isLinux
)
{
// Linux has case sensitive file system
assert
.
ok
(
deep
);
assert
.
ok
(
!
deep
!
.
children
);
// not resolved because we got instructed to resolve other/Deep with capital D
}
else
{
assert
.
ok
(
deep
);
assert
.
ok
(
deep
!
.
children
!
.
length
>
0
);
assert
.
equal
(
deep
!
.
children
!
.
length
,
4
);
}
});
test
(
'
resolve directory - resolveTo multiple directories
'
,
async
()
=>
{
const
resolverFixturesPath
=
getPathFromAmdModule
(
require
,
'
./fixtures/resolver
'
);
const
result
=
await
service
.
resolveFile
(
URI
.
file
(
resolverFixturesPath
),
{
resolveTo
:
[
URI
.
file
(
join
(
resolverFixturesPath
,
'
other/deep
'
)),
URI
.
file
(
join
(
resolverFixturesPath
,
'
examples
'
))
]
});
});
assert
.
ok
(
result
);
assert
.
ok
(
result
.
children
);
assert
.
ok
(
result
.
children
!
.
length
>
0
);
assert
.
ok
(
result
.
isDirectory
);
const
children
=
result
.
children
!
;
assert
.
equal
(
children
.
length
,
4
);
const
other
=
getByName
(
result
,
'
other
'
);
assert
.
ok
(
other
);
assert
.
ok
(
other
!
.
children
!
.
length
>
0
);
const
deep
=
getByName
(
other
!
,
'
deep
'
);
assert
.
ok
(
deep
);
assert
.
ok
(
deep
!
.
children
!
.
length
>
0
);
assert
.
equal
(
deep
!
.
children
!
.
length
,
4
);
const
examples
=
getByName
(
result
,
'
examples
'
);
assert
.
ok
(
examples
);
assert
.
ok
(
examples
!
.
children
!
.
length
>
0
);
assert
.
equal
(
examples
!
.
children
!
.
length
,
4
);
});
test
(
'
resolve directory - resolveSingleChildFolders
'
,
async
()
=>
{
const
resolverFixturesPath
=
getPathFromAmdModule
(
require
,
'
./fixtures/resolver/other
'
);
const
result
=
await
service
.
resolveFile
(
URI
.
file
(
resolverFixturesPath
),
{
resolveSingleChildDescendants
:
true
});
assert
.
ok
(
result
);
assert
.
ok
(
result
.
children
);
assert
.
ok
(
result
.
children
!
.
length
>
0
);
assert
.
ok
(
result
.
isDirectory
);
const
children
=
result
.
children
!
;
assert
.
equal
(
children
.
length
,
1
);
let
deep
=
getByName
(
result
,
'
deep
'
);
assert
.
ok
(
deep
);
assert
.
ok
(
deep
!
.
children
!
.
length
>
0
);
assert
.
equal
(
deep
!
.
children
!
.
length
,
4
);
});
test
(
'
resolveFiles
'
,
async
()
=>
{
const
res
=
await
service
.
resolveFiles
([
{
resource
:
URI
.
file
(
testDir
),
options
:
{
resolveTo
:
[
URI
.
file
(
join
(
testDir
,
'
deep
'
))]
}
},
{
resource
:
URI
.
file
(
join
(
testDir
,
'
deep
'
))
}
]);
const
r1
=
(
res
[
0
].
stat
!
);
assert
.
equal
(
r1
.
children
!
.
length
,
8
);
const
deep
=
(
getByName
(
r1
,
'
deep
'
)
!
);
assert
.
equal
(
deep
.
children
!
.
length
,
4
);
const
r2
=
(
res
[
1
].
stat
!
);
assert
.
equal
(
r2
.
children
!
.
length
,
4
);
assert
.
equal
(
r2
.
name
,
'
deep
'
);
});
});
});
});
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录