mirror of
https://github.com/immich-app/immich.git
synced 2025-01-21 00:52:43 -05:00
fix(cli): handle patterns correctly on Windows (#10430)
Modify the handling of patterns in the `crawl` function to correctly convert the current path to a pattern when it contains backslash on Windows, in according to fast-glob's docs.
This commit is contained in:
parent
1200265425
commit
4cb165304b
4 changed files with 53 additions and 6 deletions
32
.github/workflows/test.yml
vendored
32
.github/workflows/test.yml
vendored
|
@ -79,6 +79,38 @@ jobs:
|
||||||
run: npm run test:cov
|
run: npm run test:cov
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
cli-unit-tests-win:
|
||||||
|
name: CLI (Windows)
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./cli
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup typescript-sdk
|
||||||
|
run: npm ci && npm run build
|
||||||
|
working-directory: ./open-api/typescript-sdk
|
||||||
|
|
||||||
|
- name: Install deps
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
# Skip linter & formatter in Windows test.
|
||||||
|
- name: Run tsc
|
||||||
|
run: npm run check
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
- name: Run unit tests & coverage
|
||||||
|
run: npm run test:cov
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
web-unit-tests:
|
web-unit-tests:
|
||||||
name: Web
|
name: Web
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import mockfs from 'mock-fs';
|
import mockfs from 'mock-fs';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
import { CrawlOptions, crawl } from 'src/utils';
|
import { CrawlOptions, crawl } from 'src/utils';
|
||||||
|
|
||||||
interface Test {
|
interface Test {
|
||||||
|
@ -9,6 +10,10 @@ interface Test {
|
||||||
|
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
|
|
||||||
|
const readContent = (path: string) => {
|
||||||
|
return readFileSync(path).toString();
|
||||||
|
};
|
||||||
|
|
||||||
const extensions = [
|
const extensions = [
|
||||||
'.jpg',
|
'.jpg',
|
||||||
'.jpeg',
|
'.jpeg',
|
||||||
|
@ -256,7 +261,8 @@ const tests: Test[] = [
|
||||||
{
|
{
|
||||||
test: 'should support ignoring absolute paths',
|
test: 'should support ignoring absolute paths',
|
||||||
options: {
|
options: {
|
||||||
pathsToCrawl: ['/'],
|
// Currently, fast-glob has some caveat when dealing with `/`.
|
||||||
|
pathsToCrawl: ['/*s'],
|
||||||
recursive: true,
|
recursive: true,
|
||||||
exclusionPattern: '/images/**',
|
exclusionPattern: '/images/**',
|
||||||
},
|
},
|
||||||
|
@ -276,14 +282,16 @@ describe('crawl', () => {
|
||||||
describe('crawl', () => {
|
describe('crawl', () => {
|
||||||
for (const { test, options, files } of tests) {
|
for (const { test, options, files } of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, ''])));
|
// The file contents is the same as the path.
|
||||||
|
mockfs(Object.fromEntries(Object.keys(files).map((file) => [file, file])));
|
||||||
|
|
||||||
const actual = await crawl({ ...options, extensions });
|
const actual = await crawl({ ...options, extensions });
|
||||||
const expected = Object.entries(files)
|
const expected = Object.entries(files)
|
||||||
.filter((entry) => entry[1])
|
.filter((entry) => entry[1])
|
||||||
.map(([file]) => file);
|
.map(([file]) => file);
|
||||||
|
|
||||||
expect(actual.sort()).toEqual(expected.sort());
|
// Compare file's content instead of path since a file can be represent in multiple ways.
|
||||||
|
expect(actual.map((path) => readContent(path)).sort()).toEqual(expected.sort());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { getMyUser, init, isHttpError } from '@immich/sdk';
|
import { getMyUser, init, isHttpError } from '@immich/sdk';
|
||||||
import { glob } from 'fast-glob';
|
import { convertPathToPattern, glob } from 'fast-glob';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { createReadStream } from 'node:fs';
|
import { createReadStream } from 'node:fs';
|
||||||
import { readFile, stat, writeFile } from 'node:fs/promises';
|
import { readFile, stat, writeFile } from 'node:fs/promises';
|
||||||
|
import { platform } from 'node:os';
|
||||||
import { join, resolve } from 'node:path';
|
import { join, resolve } from 'node:path';
|
||||||
import yaml from 'yaml';
|
import yaml from 'yaml';
|
||||||
|
|
||||||
|
@ -106,6 +107,11 @@ export interface CrawlOptions {
|
||||||
exclusionPattern?: string;
|
exclusionPattern?: string;
|
||||||
extensions: string[];
|
extensions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const convertPathToPatternOnWin = (path: string) => {
|
||||||
|
return platform() === 'win32' ? convertPathToPattern(path) : path;
|
||||||
|
};
|
||||||
|
|
||||||
export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
||||||
const { extensions: extensionsWithPeriod, recursive, pathsToCrawl, exclusionPattern, includeHidden } = options;
|
const { extensions: extensionsWithPeriod, recursive, pathsToCrawl, exclusionPattern, includeHidden } = options;
|
||||||
const extensions = extensionsWithPeriod.map((extension) => extension.replace('.', ''));
|
const extensions = extensionsWithPeriod.map((extension) => extension.replace('.', ''));
|
||||||
|
@ -124,11 +130,11 @@ export const crawl = async (options: CrawlOptions): Promise<string[]> => {
|
||||||
if (stats.isFile() || stats.isSymbolicLink()) {
|
if (stats.isFile() || stats.isSymbolicLink()) {
|
||||||
crawledFiles.push(absolutePath);
|
crawledFiles.push(absolutePath);
|
||||||
} else {
|
} else {
|
||||||
patterns.push(absolutePath);
|
patterns.push(convertPathToPatternOnWin(absolutePath));
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.code === 'ENOENT') {
|
if (error.code === 'ENOENT') {
|
||||||
patterns.push(currentPath);
|
patterns.push(convertPathToPatternOnWin(currentPath));
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { defineConfig } from 'vite';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
resolve: { alias: { src: '/src' } },
|
||||||
build: {
|
build: {
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: 'src/index.ts',
|
input: 'src/index.ts',
|
||||||
|
|
Loading…
Add table
Reference in a new issue