chore(fs): sort methods
This commit is contained in:
parent
b60678e79f
commit
055d1e81da
@ -51,198 +51,62 @@ export default class RemoteHandlerAbstract {
|
||||
this[kPrefix] = ''
|
||||
}
|
||||
|
||||
get prefix() {
|
||||
// Public members
|
||||
|
||||
get prefix(): string {
|
||||
return this[kPrefix]
|
||||
}
|
||||
|
||||
set prefix(prefix) {
|
||||
set prefix(prefix: string) {
|
||||
prefix = normalizePath(prefix)
|
||||
this[kPrefix] = prefix === '/' ? '' : prefix
|
||||
}
|
||||
|
||||
[kResolve](path) {
|
||||
return this[kPrefix] + normalizePath(path)
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the handler to sync the state of the effective remote with its' metadata
|
||||
*/
|
||||
async sync(): Promise<mixed> {
|
||||
return this._sync()
|
||||
async closeFile(fd: FileDescriptor): Promise<void> {
|
||||
await timeout.call(this._closeFile(fd.fd), this._timeout)
|
||||
}
|
||||
|
||||
async _sync(): Promise<mixed> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resources possibly dedicated to put the remote at work, when it is no more needed
|
||||
*/
|
||||
async forget(): Promise<void> {
|
||||
await this._forget()
|
||||
}
|
||||
|
||||
async _forget(): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async test(): Promise<Object> {
|
||||
const testFileName = this[kResolve](`${Date.now()}.test`)
|
||||
const data = await fromCallback(cb => randomBytes(1024 * 1024, cb))
|
||||
let step = 'write'
|
||||
try {
|
||||
await this._outputFile(testFileName, data, { flags: 'wx' })
|
||||
step = 'read'
|
||||
const read = await this._readFile(testFileName, { flags: 'r' })
|
||||
if (!data.equals(read)) {
|
||||
throw new Error('output and input did not match')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
step,
|
||||
file: testFileName,
|
||||
error: error.message || String(error),
|
||||
}
|
||||
} finally {
|
||||
ignoreErrors.call(this._unlink(testFileName))
|
||||
}
|
||||
}
|
||||
|
||||
async outputFile(
|
||||
file: string,
|
||||
data: Data,
|
||||
{ flags = 'wx' }: { flags?: string } = {}
|
||||
): Promise<void> {
|
||||
return this._outputFile(this[kResolve](file), data, { flags })
|
||||
}
|
||||
|
||||
async _outputFile(file: string, data: Data, options?: Object): Promise<void> {
|
||||
const stream = await this._createOutputStream(file, options)
|
||||
const promise = fromCallback(cb => finished(stream, cb))
|
||||
stream.end(data)
|
||||
return promise
|
||||
}
|
||||
|
||||
async read(
|
||||
async createOutputStream(
|
||||
file: File,
|
||||
buffer: Buffer,
|
||||
position?: number
|
||||
): Promise<{| bytesRead: number, buffer: Buffer |}> {
|
||||
return this._read(
|
||||
typeof file === 'string' ? this[kResolve](file) : file,
|
||||
buffer,
|
||||
position
|
||||
{ checksum = false, ...options }: Object = {}
|
||||
): Promise<LaxWritable> {
|
||||
if (typeof file === 'string') {
|
||||
file = this[kResolve](file)
|
||||
}
|
||||
const path = typeof file === 'string' ? file : file.path
|
||||
const streamP = timeout.call(
|
||||
this._createOutputStream(file, {
|
||||
flags: 'wx',
|
||||
...options,
|
||||
}),
|
||||
this._timeout
|
||||
)
|
||||
}
|
||||
|
||||
_read(
|
||||
file: File,
|
||||
buffer: Buffer,
|
||||
position?: number
|
||||
): Promise<{| bytesRead: number, buffer: Buffer |}> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async readFile(
|
||||
file: string,
|
||||
{ flags = 'r' }: { flags?: string } = {}
|
||||
): Promise<Buffer> {
|
||||
return this._readFile(this[kResolve](file), { flags })
|
||||
}
|
||||
|
||||
_readFile(file: string, options?: Object): Promise<Buffer> {
|
||||
return this._createReadStream(file, options).then(getStream.buffer)
|
||||
}
|
||||
|
||||
async rename(
|
||||
oldPath: string,
|
||||
newPath: string,
|
||||
{ checksum = false }: Object = {}
|
||||
) {
|
||||
oldPath = this[kResolve](oldPath)
|
||||
newPath = this[kResolve](newPath)
|
||||
|
||||
let p = timeout.call(this._rename(oldPath, newPath), this._timeout)
|
||||
if (checksum) {
|
||||
p = Promise.all([
|
||||
p,
|
||||
this._rename(checksumFile(oldPath), checksumFile(newPath)),
|
||||
])
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
async _rename(oldPath: string, newPath: string) {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async rmdir(
|
||||
dir: string,
|
||||
{ recursive = false }: { recursive?: boolean } = {}
|
||||
) {
|
||||
dir = this[kResolve](dir)
|
||||
await (recursive ? this._rmtree(dir) : this._rmdir(dir))
|
||||
}
|
||||
|
||||
async _rmdir(dir: string) {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _rmtree(dir: string) {
|
||||
try {
|
||||
return await this._rmdir(dir)
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOTEMPTY') {
|
||||
throw error
|
||||
}
|
||||
if (!checksum) {
|
||||
return streamP
|
||||
}
|
||||
|
||||
const files = await this._list(dir)
|
||||
await asyncMap(files, file =>
|
||||
this._unlink(`${dir}/${file}`).catch(error => {
|
||||
if (error.code === 'EISDIR') {
|
||||
return this._rmtree(`${dir}/${file}`)
|
||||
}
|
||||
throw error
|
||||
})
|
||||
)
|
||||
return this._rmtree(dir)
|
||||
}
|
||||
|
||||
async list(
|
||||
dir: string = '.',
|
||||
{
|
||||
filter,
|
||||
prependDir = false,
|
||||
}: { filter?: (name: string) => boolean, prependDir?: boolean } = {}
|
||||
): Promise<string[]> {
|
||||
const virtualDir = normalizePath(dir)
|
||||
dir = this[kResolve](dir)
|
||||
|
||||
let entries = await timeout.call(this._list(dir), this._timeout)
|
||||
if (filter !== undefined) {
|
||||
entries = entries.filter(filter)
|
||||
const checksumStream = createChecksumStream()
|
||||
const forwardError = error => {
|
||||
checksumStream.emit('error', error)
|
||||
}
|
||||
|
||||
if (prependDir) {
|
||||
entries.forEach((entry, i) => {
|
||||
entries[i] = virtualDir + '/' + entry
|
||||
})
|
||||
}
|
||||
const stream = await streamP
|
||||
stream.on('error', forwardError)
|
||||
checksumStream.pipe(stream)
|
||||
|
||||
return entries
|
||||
}
|
||||
// $FlowFixMe
|
||||
checksumStream.checksumWritten = checksumStream.checksum
|
||||
.then(value =>
|
||||
this._outputFile(checksumFile(path), value, { flags: 'wx' })
|
||||
)
|
||||
.catch(forwardError)
|
||||
|
||||
async _list(dir: string): Promise<string[]> {
|
||||
throw new Error('Not implemented')
|
||||
return checksumStream
|
||||
}
|
||||
|
||||
createReadStream(
|
||||
@ -306,8 +170,41 @@ export default class RemoteHandlerAbstract {
|
||||
)
|
||||
}
|
||||
|
||||
async _createReadStream(file: File, options?: Object): Promise<LaxReadable> {
|
||||
throw new Error('Not implemented')
|
||||
// Free the resources possibly dedicated to put the remote at work, when it
|
||||
// is no more needed
|
||||
async forget(): Promise<void> {
|
||||
await this._forget()
|
||||
}
|
||||
|
||||
async getSize(file: File): Promise<number> {
|
||||
return timeout.call(
|
||||
this._getSize(typeof file === 'string' ? this[kResolve](file) : file),
|
||||
this._timeout
|
||||
)
|
||||
}
|
||||
|
||||
async list(
|
||||
dir: string = '.',
|
||||
{
|
||||
filter,
|
||||
prependDir = false,
|
||||
}: { filter?: (name: string) => boolean, prependDir?: boolean } = {}
|
||||
): Promise<string[]> {
|
||||
const virtualDir = normalizePath(dir)
|
||||
dir = this[kResolve](dir)
|
||||
|
||||
let entries = await timeout.call(this._list(dir), this._timeout)
|
||||
if (filter !== undefined) {
|
||||
entries = entries.filter(filter)
|
||||
}
|
||||
|
||||
if (prependDir) {
|
||||
entries.forEach((entry, i) => {
|
||||
entries[i] = virtualDir + '/' + entry
|
||||
})
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
async openFile(path: string, flags?: string): Promise<FileDescriptor> {
|
||||
@ -319,16 +216,31 @@ export default class RemoteHandlerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
async _openFile(path: string, flags?: string): Promise<mixed> {
|
||||
throw new Error('Not implemented')
|
||||
async outputFile(
|
||||
file: string,
|
||||
data: Data,
|
||||
{ flags = 'wx' }: { flags?: string } = {}
|
||||
): Promise<void> {
|
||||
return this._outputFile(this[kResolve](file), data, { flags })
|
||||
}
|
||||
|
||||
async closeFile(fd: FileDescriptor): Promise<void> {
|
||||
await timeout.call(this._closeFile(fd.fd), this._timeout)
|
||||
async read(
|
||||
file: File,
|
||||
buffer: Buffer,
|
||||
position?: number
|
||||
): Promise<{| bytesRead: number, buffer: Buffer |}> {
|
||||
return this._read(
|
||||
typeof file === 'string' ? this[kResolve](file) : file,
|
||||
buffer,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
async _closeFile(fd: mixed): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
async readFile(
|
||||
file: string,
|
||||
{ flags = 'r' }: { flags?: string } = {}
|
||||
): Promise<Buffer> {
|
||||
return this._readFile(this[kResolve](file), { flags })
|
||||
}
|
||||
|
||||
async refreshChecksum(path: string): Promise<void> {
|
||||
@ -343,50 +255,62 @@ export default class RemoteHandlerAbstract {
|
||||
})
|
||||
}
|
||||
|
||||
async createOutputStream(
|
||||
file: File,
|
||||
{ checksum = false, ...options }: Object = {}
|
||||
): Promise<LaxWritable> {
|
||||
if (typeof file === 'string') {
|
||||
file = this[kResolve](file)
|
||||
async rename(
|
||||
oldPath: string,
|
||||
newPath: string,
|
||||
{ checksum = false }: Object = {}
|
||||
) {
|
||||
oldPath = this[kResolve](oldPath)
|
||||
newPath = this[kResolve](newPath)
|
||||
|
||||
let p = timeout.call(this._rename(oldPath, newPath), this._timeout)
|
||||
if (checksum) {
|
||||
p = Promise.all([
|
||||
p,
|
||||
this._rename(checksumFile(oldPath), checksumFile(newPath)),
|
||||
])
|
||||
}
|
||||
const path = typeof file === 'string' ? file : file.path
|
||||
const streamP = timeout.call(
|
||||
this._createOutputStream(file, {
|
||||
flags: 'wx',
|
||||
...options,
|
||||
}),
|
||||
this._timeout
|
||||
)
|
||||
|
||||
if (!checksum) {
|
||||
return streamP
|
||||
}
|
||||
|
||||
const checksumStream = createChecksumStream()
|
||||
const forwardError = error => {
|
||||
checksumStream.emit('error', error)
|
||||
}
|
||||
|
||||
const stream = await streamP
|
||||
stream.on('error', forwardError)
|
||||
checksumStream.pipe(stream)
|
||||
|
||||
// $FlowFixMe
|
||||
checksumStream.checksumWritten = checksumStream.checksum
|
||||
.then(value =>
|
||||
this._outputFile(checksumFile(path), value, { flags: 'wx' })
|
||||
)
|
||||
.catch(forwardError)
|
||||
|
||||
return checksumStream
|
||||
return p
|
||||
}
|
||||
|
||||
async _createOutputStream(
|
||||
file: File,
|
||||
options?: Object
|
||||
): Promise<LaxWritable> {
|
||||
throw new Error('Not implemented')
|
||||
async rmdir(
|
||||
dir: string,
|
||||
{ recursive = false }: { recursive?: boolean } = {}
|
||||
) {
|
||||
dir = this[kResolve](dir)
|
||||
await (recursive ? this._rmtree(dir) : this._rmdir(dir))
|
||||
}
|
||||
|
||||
// Asks the handler to sync the state of the effective remote with its'
|
||||
// metadata
|
||||
async sync(): Promise<mixed> {
|
||||
return this._sync()
|
||||
}
|
||||
|
||||
async test(): Promise<Object> {
|
||||
const testFileName = this[kResolve](`${Date.now()}.test`)
|
||||
const data = await fromCallback(cb => randomBytes(1024 * 1024, cb))
|
||||
let step = 'write'
|
||||
try {
|
||||
await this._outputFile(testFileName, data, { flags: 'wx' })
|
||||
step = 'read'
|
||||
const read = await this._readFile(testFileName, { flags: 'r' })
|
||||
if (!data.equals(read)) {
|
||||
throw new Error('output and input did not match')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
step,
|
||||
file: testFileName,
|
||||
error: error.message || String(error),
|
||||
}
|
||||
} finally {
|
||||
ignoreErrors.call(this._unlink(testFileName))
|
||||
}
|
||||
}
|
||||
|
||||
async unlink(file: string, { checksum = true }: Object = {}): Promise<void> {
|
||||
@ -399,18 +323,98 @@ export default class RemoteHandlerAbstract {
|
||||
await timeout.call(this._unlink(file), this._timeout)
|
||||
}
|
||||
|
||||
async _unlink(file: string): Promise<void> {
|
||||
// Methods that can be implemented by inheriting classes
|
||||
|
||||
async _closeFile(fd: mixed): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async getSize(file: File): Promise<number> {
|
||||
return timeout.call(
|
||||
this._getSize(typeof file === 'string' ? this[kResolve](file) : file),
|
||||
this._timeout
|
||||
)
|
||||
async _createOutputStream(
|
||||
file: File,
|
||||
options?: Object
|
||||
): Promise<LaxWritable> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _createReadStream(file: File, options?: Object): Promise<LaxReadable> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _forget(): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _getSize(file: File): Promise<number> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _list(dir: string): Promise<string[]> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _openFile(path: string, flags?: string): Promise<mixed> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _outputFile(file: string, data: Data, options?: Object): Promise<void> {
|
||||
const stream = await this._createOutputStream(file, options)
|
||||
const promise = fromCallback(cb => finished(stream, cb))
|
||||
stream.end(data)
|
||||
return promise
|
||||
}
|
||||
|
||||
_read(
|
||||
file: File,
|
||||
buffer: Buffer,
|
||||
position?: number
|
||||
): Promise<{| bytesRead: number, buffer: Buffer |}> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
_readFile(file: string, options?: Object): Promise<Buffer> {
|
||||
return this._createReadStream(file, options).then(getStream.buffer)
|
||||
}
|
||||
|
||||
async _rename(oldPath: string, newPath: string) {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _rmdir(dir: string) {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _rmtree(dir: string) {
|
||||
try {
|
||||
return await this._rmdir(dir)
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOTEMPTY') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const files = await this._list(dir)
|
||||
await asyncMap(files, file =>
|
||||
this._unlink(`${dir}/${file}`).catch(error => {
|
||||
if (error.code === 'EISDIR') {
|
||||
return this._rmtree(`${dir}/${file}`)
|
||||
}
|
||||
throw error
|
||||
})
|
||||
)
|
||||
return this._rmtree(dir)
|
||||
}
|
||||
|
||||
async _sync(): Promise<mixed> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _unlink(file: string): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
// Private members
|
||||
|
||||
[kResolve](path: string): string {
|
||||
return this[kPrefix] + normalizePath(path)
|
||||
}
|
||||
}
|
||||
|
@ -16,54 +16,6 @@ class TestHandler extends AbstractHandler {
|
||||
}
|
||||
}
|
||||
|
||||
describe('rename()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
rename: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.rename('oldPath', 'newPath')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('list()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
list: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.list()
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('createReadStream()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
createReadStream: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.createReadStream('file')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('openFile()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
openFile: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.openFile('path')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('closeFile()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
@ -88,13 +40,13 @@ describe('createOutputStream()', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('unlink()', () => {
|
||||
describe('createReadStream()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
unlink: () => new Promise(() => {}),
|
||||
createReadStream: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.unlink('')
|
||||
const promise = testHandler.createReadStream('file')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
@ -111,3 +63,51 @@ describe('getSize()', () => {
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('list()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
list: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.list()
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('openFile()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
openFile: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.openFile('path')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('rename()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
rename: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.rename('oldPath', 'newPath')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('unlink()', () => {
|
||||
it(`throws in case of timeout`, async () => {
|
||||
const testHandler = new TestHandler({
|
||||
unlink: () => new Promise(() => {}),
|
||||
})
|
||||
|
||||
const promise = testHandler.unlink('')
|
||||
jest.advanceTimersByTime(TIMEOUT)
|
||||
await expect(promise).rejects.toThrowError(TimeoutError)
|
||||
})
|
||||
})
|
||||
|
@ -65,11 +65,28 @@ handlers.forEach(url => {
|
||||
handler.prefix = prefix
|
||||
})
|
||||
|
||||
describe('#test()', () => {
|
||||
it('tests the remote appears to be working', async () => {
|
||||
expect(await handler.test()).toEqual({
|
||||
success: true,
|
||||
})
|
||||
describe('#createReadStream()', () => {
|
||||
it(`should return a stream`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
const buffer = await getStream.buffer(
|
||||
await handler.createReadStream('file')
|
||||
)
|
||||
|
||||
await expect(buffer).toEqual(TEST_DATA)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getSize()', () => {
|
||||
it(`should return the correct size`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
expect(await handler.getSize('file')).toEqual(TEST_DATA.length)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#list()', () => {
|
||||
it(`should list the content of folder`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
await expect(await handler.list('.')).toEqual(['file'])
|
||||
})
|
||||
})
|
||||
|
||||
@ -98,30 +115,6 @@ handlers.forEach(url => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#list()', () => {
|
||||
it(`should list the content of folder`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
await expect(await handler.list('.')).toEqual(['file'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('#createReadStream()', () => {
|
||||
it(`should return a stream`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
const buffer = await getStream.buffer(
|
||||
await handler.createReadStream('file')
|
||||
)
|
||||
|
||||
await expect(buffer).toEqual(TEST_DATA)
|
||||
})
|
||||
})
|
||||
describe('#getSize()', () => {
|
||||
it(`should return the correct size`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
expect(await handler.getSize('file')).toEqual(TEST_DATA.length)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#rename()', () => {
|
||||
it(`should rename the file`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
@ -132,15 +125,6 @@ handlers.forEach(url => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#unlink()', () => {
|
||||
it(`should remove the file`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
await handler.unlink('file')
|
||||
|
||||
await expect(await handler.list('.')).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('#rmdir()', () => {
|
||||
it(`should remove folder resursively`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
@ -157,5 +141,22 @@ handlers.forEach(url => {
|
||||
await expect(error.code).toEqual('ENOTEMPTY')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#test()', () => {
|
||||
it('tests the remote appears to be working', async () => {
|
||||
expect(await handler.test()).toEqual({
|
||||
success: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#unlink()', () => {
|
||||
it(`should remove the file`, async () => {
|
||||
await handler.outputFile('file', TEST_DATA)
|
||||
await handler.unlink('file')
|
||||
|
||||
await expect(await handler.list('.')).toEqual([])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -17,18 +17,52 @@ export default class LocalHandler extends RemoteHandlerAbstract {
|
||||
return this._getRealPath() + file
|
||||
}
|
||||
|
||||
async _sync() {
|
||||
const path = this._getRealPath()
|
||||
await fs.ensureDir(path)
|
||||
await fs.access(path, fs.R_OK | fs.W_OK)
|
||||
async _closeFile(fd) {
|
||||
return fs.close(fd)
|
||||
}
|
||||
|
||||
return this._remote
|
||||
async _createOutputStream(file, options) {
|
||||
if (typeof file === 'string') {
|
||||
const path = this._getFilePath(file)
|
||||
await fs.ensureDir(dirname(path))
|
||||
return fs.createWriteStream(path, options)
|
||||
}
|
||||
return fs.createWriteStream('', {
|
||||
autoClose: false,
|
||||
...options,
|
||||
fd: file.fd,
|
||||
})
|
||||
}
|
||||
|
||||
async _createReadStream(file, options) {
|
||||
return typeof file === 'string'
|
||||
? fs.createReadStream(this._getFilePath(file), options)
|
||||
: fs.createReadStream('', {
|
||||
autoClose: false,
|
||||
...options,
|
||||
fd: file.fd,
|
||||
})
|
||||
}
|
||||
|
||||
async _forget() {
|
||||
return noop()
|
||||
}
|
||||
|
||||
async _getSize(file) {
|
||||
const stats = await fs.stat(
|
||||
this._getFilePath(typeof file === 'string' ? file : file.path)
|
||||
)
|
||||
return stats.size
|
||||
}
|
||||
|
||||
async _list(dir = '.') {
|
||||
return fs.readdir(this._getFilePath(dir))
|
||||
}
|
||||
|
||||
async _openFile(path, flags) {
|
||||
return fs.open(this._getFilePath(path), flags)
|
||||
}
|
||||
|
||||
async _outputFile(file, data, { flags }) {
|
||||
const path = this._getFilePath(file)
|
||||
await fs.ensureDir(dirname(path))
|
||||
@ -61,31 +95,16 @@ export default class LocalHandler extends RemoteHandlerAbstract {
|
||||
return fs.rename(this._getFilePath(oldPath), this._getFilePath(newPath))
|
||||
}
|
||||
|
||||
async _list(dir = '.') {
|
||||
return fs.readdir(this._getFilePath(dir))
|
||||
async _rmdir(dir) {
|
||||
return fs.rmdir(this._getFilePath(dir))
|
||||
}
|
||||
|
||||
async _createReadStream(file, options) {
|
||||
return typeof file === 'string'
|
||||
? fs.createReadStream(this._getFilePath(file), options)
|
||||
: fs.createReadStream('', {
|
||||
autoClose: false,
|
||||
...options,
|
||||
fd: file.fd,
|
||||
})
|
||||
}
|
||||
async _sync() {
|
||||
const path = this._getRealPath()
|
||||
await fs.ensureDir(path)
|
||||
await fs.access(path, fs.R_OK | fs.W_OK)
|
||||
|
||||
async _createOutputStream(file, options) {
|
||||
if (typeof file === 'string') {
|
||||
const path = this._getFilePath(file)
|
||||
await fs.ensureDir(dirname(path))
|
||||
return fs.createWriteStream(path, options)
|
||||
}
|
||||
return fs.createWriteStream('', {
|
||||
autoClose: false,
|
||||
...options,
|
||||
fd: file.fd,
|
||||
})
|
||||
return this._remote
|
||||
}
|
||||
|
||||
async _unlink(file) {
|
||||
@ -96,23 +115,4 @@ export default class LocalHandler extends RemoteHandlerAbstract {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _getSize(file) {
|
||||
const stats = await fs.stat(
|
||||
this._getFilePath(typeof file === 'string' ? file : file.path)
|
||||
)
|
||||
return stats.size
|
||||
}
|
||||
|
||||
async _openFile(path, flags) {
|
||||
return fs.open(this._getFilePath(path), flags)
|
||||
}
|
||||
|
||||
async _closeFile(fd) {
|
||||
return fs.close(fd)
|
||||
}
|
||||
|
||||
async _rmdir(dir) {
|
||||
return fs.rmdir(this._getFilePath(dir))
|
||||
}
|
||||
}
|
||||
|
@ -60,20 +60,6 @@ export default class NfsHandler extends LocalHandler {
|
||||
})
|
||||
}
|
||||
|
||||
async _sync() {
|
||||
await this._mount()
|
||||
|
||||
return this._remote
|
||||
}
|
||||
|
||||
async _forget() {
|
||||
try {
|
||||
await this._umount(this._remote)
|
||||
} catch (_) {
|
||||
// We have to go on...
|
||||
}
|
||||
}
|
||||
|
||||
async _umount() {
|
||||
await execa('umount', ['--force', this._getRealPath()], {
|
||||
env: {
|
||||
@ -89,4 +75,18 @@ export default class NfsHandler extends LocalHandler {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _forget() {
|
||||
try {
|
||||
await this._umount(this._remote)
|
||||
} catch (_) {
|
||||
// We have to go on...
|
||||
}
|
||||
}
|
||||
|
||||
async _sync() {
|
||||
await this._mount()
|
||||
|
||||
return this._remote
|
||||
}
|
||||
}
|
||||
|
@ -62,11 +62,93 @@ export default class SmbHandler extends RemoteHandlerAbstract {
|
||||
return parts.join('\\')
|
||||
}
|
||||
|
||||
async _sync() {
|
||||
// Check access (smb2 does not expose connect in public so far...)
|
||||
await this.list()
|
||||
async _closeFile({ client, file }) {
|
||||
try {
|
||||
await client.close(file).catch(normalizeError)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
return this._remote
|
||||
async _createOutputStream(file, options = {}) {
|
||||
if (typeof file !== 'string') {
|
||||
file = file.path
|
||||
}
|
||||
const path = this._getFilePath(file)
|
||||
|
||||
const client = this._getClient()
|
||||
try {
|
||||
const dir = this._dirname(path)
|
||||
if (dir) {
|
||||
await client.ensureDir(dir)
|
||||
}
|
||||
|
||||
// FIXME ensure that options are properly handled by @marsaud/smb2
|
||||
const stream = await client.createWriteStream(path, options)
|
||||
|
||||
finished(stream, () => client.disconnect())
|
||||
|
||||
return stream
|
||||
} catch (err) {
|
||||
client.disconnect()
|
||||
throw normalizeError(err)
|
||||
}
|
||||
}
|
||||
|
||||
async _createReadStream(file, options = {}) {
|
||||
if (typeof file !== 'string') {
|
||||
file = file.path
|
||||
}
|
||||
|
||||
const client = this._getClient()
|
||||
try {
|
||||
// FIXME ensure that options are properly handled by @marsaud/smb2
|
||||
const stream = await client.createReadStream(
|
||||
this._getFilePath(file),
|
||||
options
|
||||
)
|
||||
|
||||
finished(stream, () => client.disconnect())
|
||||
|
||||
return stream
|
||||
} catch (error) {
|
||||
client.disconnect()
|
||||
|
||||
throw normalizeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
async _getSize(file) {
|
||||
const client = await this._getClient()
|
||||
try {
|
||||
return await client.getSize(
|
||||
this._getFilePath(typeof file === 'string' ? file : file.path)
|
||||
)
|
||||
} catch (error) {
|
||||
throw normalizeError(error)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
async _list(dir = '.') {
|
||||
const client = this._getClient()
|
||||
try {
|
||||
return await client.readdir(this._getFilePath(dir))
|
||||
} catch (error) {
|
||||
throw normalizeError(error, true)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add flags
|
||||
async _openFile(path) {
|
||||
const client = this._getClient()
|
||||
return {
|
||||
client,
|
||||
file: await client.open(this._getFilePath(path)).catch(normalizeError),
|
||||
}
|
||||
}
|
||||
|
||||
async _outputFile(file, data, options = {}) {
|
||||
@ -143,63 +225,11 @@ export default class SmbHandler extends RemoteHandlerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
async _list(dir = '.') {
|
||||
const client = this._getClient()
|
||||
try {
|
||||
return await client.readdir(this._getFilePath(dir))
|
||||
} catch (error) {
|
||||
throw normalizeError(error, true)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
async _sync() {
|
||||
// Check access (smb2 does not expose connect in public so far...)
|
||||
await this.list()
|
||||
|
||||
async _createReadStream(file, options = {}) {
|
||||
if (typeof file !== 'string') {
|
||||
file = file.path
|
||||
}
|
||||
|
||||
const client = this._getClient()
|
||||
try {
|
||||
// FIXME ensure that options are properly handled by @marsaud/smb2
|
||||
const stream = await client.createReadStream(
|
||||
this._getFilePath(file),
|
||||
options
|
||||
)
|
||||
|
||||
finished(stream, () => client.disconnect())
|
||||
|
||||
return stream
|
||||
} catch (error) {
|
||||
client.disconnect()
|
||||
|
||||
throw normalizeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
async _createOutputStream(file, options = {}) {
|
||||
if (typeof file !== 'string') {
|
||||
file = file.path
|
||||
}
|
||||
const path = this._getFilePath(file)
|
||||
|
||||
const client = this._getClient()
|
||||
try {
|
||||
const dir = this._dirname(path)
|
||||
if (dir) {
|
||||
await client.ensureDir(dir)
|
||||
}
|
||||
|
||||
// FIXME ensure that options are properly handled by @marsaud/smb2
|
||||
const stream = await client.createWriteStream(path, options)
|
||||
|
||||
finished(stream, () => client.disconnect())
|
||||
|
||||
return stream
|
||||
} catch (err) {
|
||||
client.disconnect()
|
||||
throw normalizeError(err)
|
||||
}
|
||||
return this._remote
|
||||
}
|
||||
|
||||
async _unlink(file) {
|
||||
@ -212,34 +242,4 @@ export default class SmbHandler extends RemoteHandlerAbstract {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
async _getSize(file) {
|
||||
const client = await this._getClient()
|
||||
try {
|
||||
return await client.getSize(
|
||||
this._getFilePath(typeof file === 'string' ? file : file.path)
|
||||
)
|
||||
} catch (error) {
|
||||
throw normalizeError(error)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add flags
|
||||
async _openFile(path) {
|
||||
const client = this._getClient()
|
||||
return {
|
||||
client,
|
||||
file: await client.open(this._getFilePath(path)).catch(normalizeError),
|
||||
}
|
||||
}
|
||||
|
||||
async _closeFile({ client, file }) {
|
||||
try {
|
||||
await client.close(file).catch(normalizeError)
|
||||
} finally {
|
||||
client.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user