diff --git a/apps/renterd/lib/paths.spec.ts b/apps/renterd/lib/paths.spec.ts index 566a742d5..280bf699b 100644 --- a/apps/renterd/lib/paths.spec.ts +++ b/apps/renterd/lib/paths.spec.ts @@ -1,88 +1,116 @@ import { bucketAndKeyParamsFromPath, buildDirectoryPath, + getDirectorySegmentsFromPath, getParentDirectoryPath, join, } from './paths' -describe('join', () => { - it('a', () => { - expect(join('bucket/dir/', '/path/to/file.txt')).toEqual( - 'bucket/dir/path/to/file.txt' - ) - }) - it('b', () => { - expect(join('bucket/dir/', '')).toEqual('bucket/dir/') - }) - it('b', () => { - expect(join('bucket/dir/', '/')).toEqual('bucket/dir/') +describe('paths', () => { + describe('join', () => { + it('a', () => { + expect(join('bucket/dir/', '/path/to/file.txt')).toEqual( + 'bucket/dir/path/to/file.txt' + ) + }) + it('b', () => { + expect(join('bucket/dir/', '')).toEqual('bucket/dir/') + }) + it('b', () => { + expect(join('bucket/dir/', '/')).toEqual('bucket/dir/') + }) }) -}) -describe('buildDirPath', () => { - it('a', () => { - expect(buildDirectoryPath('bucket/dir/', '/path/to/dir')).toEqual( - 'bucket/dir/path/to/dir/' - ) - }) - it('b', () => { - expect(buildDirectoryPath('bucket/dir/', '')).toEqual('bucket/dir/') - }) - it('c', () => { - expect(buildDirectoryPath('bucket/dir/', '/')).toEqual('bucket/dir/') + describe('buildDirPath', () => { + it('a', () => { + expect(buildDirectoryPath('bucket/dir/', '/path/to/dir')).toEqual( + 'bucket/dir/path/to/dir/' + ) + }) + it('b', () => { + expect(buildDirectoryPath('bucket/dir/', '')).toEqual('bucket/dir/') + }) + it('c', () => { + expect(buildDirectoryPath('bucket/dir/', '/')).toEqual('bucket/dir/') + }) }) -}) -describe('getParentDirectoryPath', () => { - it('a', () => { - expect(getParentDirectoryPath('bucket/dir/')).toEqual('bucket/') - }) - it('b', () => { - expect(getParentDirectoryPath('bucket/dir')).toEqual('bucket/') - }) - it('c', () => { - expect(getParentDirectoryPath('/')).toEqual('/') - }) - it('d', () => { - expect(getParentDirectoryPath('')).toEqual('/') + describe('getParentDirectoryPath', () => { + it('a', () => { + expect(getParentDirectoryPath('bucket/dir/')).toEqual('bucket/') + }) + it('b', () => { + expect(getParentDirectoryPath('bucket/dir')).toEqual('bucket/') + }) + it('c', () => { + expect(getParentDirectoryPath('/')).toEqual('/') + }) + it('d', () => { + expect(getParentDirectoryPath('')).toEqual('/') + }) }) -}) -describe('bucketAndKeyParamsFromPath', () => { - it('works for file', () => { - expect(bucketAndKeyParamsFromPath('bucket/path/to/file.txt')).toEqual({ - bucket: 'bucket', - key: 'path/to/file.txt', + describe('getDirectorySegmentsFromPath', () => { + it('directory path', () => { + expect(getDirectorySegmentsFromPath('bucket/dir/')).toEqual([ + 'bucket', + 'dir', + ]) + }) + it('file path', () => { + expect(getDirectorySegmentsFromPath('bucket/dir/foo')).toEqual([ + 'bucket', + 'dir', + ]) + }) + it('malformed path', () => { + expect(getDirectorySegmentsFromPath('/bucket/dir/foo')).toEqual([ + 'bucket', + 'dir', + ]) + expect(getDirectorySegmentsFromPath('//bucket/dir/foo')).toEqual([ + 'bucket', + 'dir', + ]) }) }) - it('works for file with hash in path', () => { - expect( - bucketAndKeyParamsFromPath('bucket/path#/to#hash/file#hash.txt') - ).toEqual({ - bucket: 'bucket', - key: 'path%23/to%23hash/file%23hash.txt', + describe('bucketAndKeyParamsFromPath', () => { + it('works for file', () => { + expect(bucketAndKeyParamsFromPath('bucket/path/to/file.txt')).toEqual({ + bucket: 'bucket', + key: 'path/to/file.txt', + }) }) - }) - it('works for directory', () => { - expect(bucketAndKeyParamsFromPath('bucket/path/to/directory/')).toEqual({ - bucket: 'bucket', - key: 'path/to/directory/', + it('works for file with hash in path', () => { + expect( + bucketAndKeyParamsFromPath('bucket/path#/to#hash/file#hash.txt') + ).toEqual({ + bucket: 'bucket', + key: 'path%23/to%23hash/file%23hash.txt', + }) }) - }) - it('works for empty', () => { - expect(bucketAndKeyParamsFromPath('bucket')).toEqual({ - bucket: 'bucket', - key: '', + it('works for directory', () => { + expect(bucketAndKeyParamsFromPath('bucket/path/to/directory/')).toEqual({ + bucket: 'bucket', + key: 'path/to/directory/', + }) + }) + + it('works for empty', () => { + expect(bucketAndKeyParamsFromPath('bucket')).toEqual({ + bucket: 'bucket', + key: '', + }) }) - }) - it('works for empty with trailing', () => { - expect(bucketAndKeyParamsFromPath('bucket/')).toEqual({ - bucket: 'bucket', - key: '', + it('works for empty with trailing', () => { + expect(bucketAndKeyParamsFromPath('bucket/')).toEqual({ + bucket: 'bucket', + key: '', + }) }) }) }) diff --git a/apps/renterd/lib/paths.ts b/apps/renterd/lib/paths.ts index ecf0e3b9a..e81e2a792 100644 --- a/apps/renterd/lib/paths.ts +++ b/apps/renterd/lib/paths.ts @@ -1,3 +1,5 @@ +import { trimStart } from '@technically/lodash' + export type FullPathSegments = string[] export type FullPath = string export type KeyPath = string @@ -9,6 +11,7 @@ export function join(a: string, b: string): FullPath { } export function buildDirectoryPath(dirPath: FullPath, name: string): FullPath { + dirPath = trimStart(dirPath, '/') const path = join(dirPath, name) return path.endsWith('/') ? path : path + '/' } @@ -18,6 +21,7 @@ export function getBucketFromPath(path: FullPath): string { } export function getKeyFromPath(path: FullPath): KeyPath { + path = trimStart(path, '/') const segsWithoutBucket = path.split('/').slice(1).join('/') return `/${segsWithoutBucket}` } @@ -37,9 +41,10 @@ export function bucketAndKeyParamsFromPath(path: FullPath): { } } -export function getFilename(filePath: FullPath): string { - const parts = filePath.split('/') - if (filePath.endsWith('/')) { +export function getFilename(path: FullPath): string { + path = trimStart(path, '/') + const parts = path.split('/') + if (path.endsWith('/')) { return `${parts[parts.length - 2]}/` } return parts[parts.length - 1] @@ -50,11 +55,13 @@ export function isDirectory(path: FullPath): boolean { } export function getParentDirectoryPath(path: FullPath): FullPath { + path = trimStart(path, '/') const p = isDirectory(path) ? path.slice(0, -1) : path return p.split('/').slice(0, -1).join('/').concat('/') } export function getDirectorySegmentsFromPath(path: FullPath): FullPathSegments { + path = trimStart(path, '/') if (isDirectory(path)) { return path.slice(0, -1).split('/') } @@ -66,6 +73,7 @@ export function pathSegmentsToPath(segments: FullPathSegments): FullPath { } export function ensureDirectory(path: FullPath): FullPath { + path = trimStart(path, '/') if (isDirectory(path)) { return path }