Skip to content

Commit

Permalink
fix(server): Allow commas and braces in import paths (immich-app#13259)
Browse files Browse the repository at this point in the history
fix commas and braces in paths
  • Loading branch information
etnoy authored and Yosi Taguri committed Oct 16, 2024
1 parent 60ed15c commit dd5642d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
56 changes: 56 additions & 0 deletions e2e/src/api/specs/library.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,62 @@ describe('/libraries', () => {
expect(assets.items.find((asset) => asset.originalPath.includes('directoryB'))).toBeDefined();
});

it('should scan multiple import paths with commas', async () => {
// https://github.com/immich-app/immich/issues/10699
const library = await utils.createLibrary(admin.accessToken, {
ownerId: admin.userId,
importPaths: [`${testAssetDirInternal}/temp/folder, a`, `${testAssetDirInternal}/temp/folder, b`],
});

utils.createImageFile(`${testAssetDir}/temp/folder, a/assetA.png`);
utils.createImageFile(`${testAssetDir}/temp/folder, b/assetB.png`);

const { status } = await request(app)
.post(`/libraries/${library.id}/scan`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send();
expect(status).toBe(204);

await utils.waitForQueueFinish(admin.accessToken, 'library');

const { assets } = await utils.metadataSearch(admin.accessToken, { libraryId: library.id });

expect(assets.count).toBe(2);
expect(assets.items.find((asset) => asset.originalPath.includes('folder, a'))).toBeDefined();
expect(assets.items.find((asset) => asset.originalPath.includes('folder, b'))).toBeDefined();

utils.removeImageFile(`${testAssetDir}/temp/folder, a/assetA.png`);
utils.removeImageFile(`${testAssetDir}/temp/folder, b/assetB.png`);
});

it('should scan multiple import paths with braces', async () => {
// https://github.com/immich-app/immich/issues/10699
const library = await utils.createLibrary(admin.accessToken, {
ownerId: admin.userId,
importPaths: [`${testAssetDirInternal}/temp/folder{ a`, `${testAssetDirInternal}/temp/folder} b`],
});

utils.createImageFile(`${testAssetDir}/temp/folder{ a/assetA.png`);
utils.createImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);

const { status } = await request(app)
.post(`/libraries/${library.id}/scan`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send();
expect(status).toBe(204);

await utils.waitForQueueFinish(admin.accessToken, 'library');

const { assets } = await utils.metadataSearch(admin.accessToken, { libraryId: library.id });

expect(assets.count).toBe(2);
expect(assets.items.find((asset) => asset.originalPath.includes('folder{ a'))).toBeDefined();
expect(assets.items.find((asset) => asset.originalPath.includes('folder} b'))).toBeDefined();

utils.removeImageFile(`${testAssetDir}/temp/folder{ a/assetA.png`);
utils.removeImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);
});

it('should reimport a modified file', async () => {
const library = await utils.createLibrary(admin.accessToken, {
ownerId: admin.userId,
Expand Down
15 changes: 9 additions & 6 deletions server/src/repositories/storage.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ export class StorageRepository implements IStorageRepository {
return Promise.resolve([]);
}

return glob(this.asGlob(pathsToCrawl), {
const globbedPaths = pathsToCrawl.map((path) => this.asGlob(path));

return glob(globbedPaths, {
absolute: true,
caseSensitiveMatch: false,
onlyFiles: true,
Expand All @@ -172,7 +174,9 @@ export class StorageRepository implements IStorageRepository {
return emptyGenerator();
}

const stream = globStream(this.asGlob(pathsToCrawl), {
const globbedPaths = pathsToCrawl.map((path) => this.asGlob(path));

const stream = globStream(globbedPaths, {
absolute: true,
caseSensitiveMatch: false,
onlyFiles: true,
Expand Down Expand Up @@ -206,10 +210,9 @@ export class StorageRepository implements IStorageRepository {
return () => watcher.close();
}

private asGlob(pathsToCrawl: string[]): string {
const escapedPaths = pathsToCrawl.map((path) => escapePath(path));
const base = escapedPaths.length === 1 ? escapedPaths[0] : `{${escapedPaths.join(',')}}`;
private asGlob(pathToCrawl: string): string {
const escapedPath = escapePath(pathToCrawl);
const extensions = `*{${mimeTypes.getSupportedFileExtensions().join(',')}}`;
return `${base}/**/${extensions}`;
return `${escapedPath}/**/${extensions}`;
}
}

0 comments on commit dd5642d

Please sign in to comment.