mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
chore: install kepubify into Docker image at build time
- download correct arch binary from projectx-tools during image build - use system binary at /usr/local/bin/kepubify when available, fall back to runtime download for local dev
This commit is contained in:
+12
-1
@@ -40,8 +40,19 @@ RUN mkdir -p /deploy/migrations && cp -r /app/server/src/db/migrations/. /deploy
|
|||||||
FROM ${NODE_IMAGE} AS runtime
|
FROM ${NODE_IMAGE} AS runtime
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
ARG TARGETARCH
|
||||||
RUN apk upgrade --no-cache && \
|
RUN apk upgrade --no-cache && \
|
||||||
apk add --no-cache poppler-utils su-exec && \
|
apk add --no-cache poppler-utils su-exec curl && \
|
||||||
|
case "$TARGETARCH" in \
|
||||||
|
amd64) KEPUBIFY_BIN="kepubify-linux-64bit" ;; \
|
||||||
|
arm64) KEPUBIFY_BIN="kepubify-linux-arm64" ;; \
|
||||||
|
arm) KEPUBIFY_BIN="kepubify-linux-arm" ;; \
|
||||||
|
386) KEPUBIFY_BIN="kepubify-linux-32bit" ;; \
|
||||||
|
esac && \
|
||||||
|
curl -fsSL "https://github.com/neonsolstice/projectx-tools/raw/main/kepubify/${KEPUBIFY_BIN}" \
|
||||||
|
-o /usr/local/bin/kepubify && \
|
||||||
|
chmod +x /usr/local/bin/kepubify && \
|
||||||
|
apk del curl && \
|
||||||
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
|
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|||||||
@@ -48,8 +48,19 @@ describe('KepubifyBinaryService', () => {
|
|||||||
expect(() => (service as any).detectBinaryName()).toThrow('Unsupported platform');
|
expect(() => (service as any).detectBinaryName()).toThrow('Unsupported platform');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('caches computed binary path after first resolution', async () => {
|
it('returns system binary path when kepubify is already installed', async () => {
|
||||||
const service = new KepubifyBinaryService(config as never);
|
const service = new KepubifyBinaryService(config as never);
|
||||||
|
statMock.mockResolvedValue({} as never);
|
||||||
|
|
||||||
|
await expect(service.getBinaryPath()).resolves.toBe('/usr/local/bin/kepubify');
|
||||||
|
await expect(service.getBinaryPath()).resolves.toBe('/usr/local/bin/kepubify');
|
||||||
|
|
||||||
|
expect(statMock).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('caches computed binary path after first resolution when system binary absent', async () => {
|
||||||
|
const service = new KepubifyBinaryService(config as never);
|
||||||
|
statMock.mockRejectedValue(new Error('missing'));
|
||||||
const detectSpy = vi.spyOn(service as any, 'detectBinaryName').mockReturnValue('kepubify-linux-64bit');
|
const detectSpy = vi.spyOn(service as any, 'detectBinaryName').mockReturnValue('kepubify-linux-64bit');
|
||||||
const ensureSpy = vi.spyOn(service as any, 'ensureBinary').mockResolvedValue(undefined);
|
const ensureSpy = vi.spyOn(service as any, 'ensureBinary').mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { join } from 'path';
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
const KEPUBIFY_BASE_URL = 'https://github.com/booklore-app/booklore-tools/raw/main/kepubify/';
|
const KEPUBIFY_BASE_URL = 'https://github.com/neonsolstice/projectx-tools/raw/main/kepubify/';
|
||||||
|
const SYSTEM_BINARY_PATH = '/usr/local/bin/kepubify';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class KepubifyBinaryService {
|
export class KepubifyBinaryService {
|
||||||
@@ -18,6 +19,12 @@ export class KepubifyBinaryService {
|
|||||||
|
|
||||||
async getBinaryPath(): Promise<string> {
|
async getBinaryPath(): Promise<string> {
|
||||||
if (this.cachedBinaryPath) return this.cachedBinaryPath;
|
if (this.cachedBinaryPath) return this.cachedBinaryPath;
|
||||||
|
|
||||||
|
if (await this.exists(SYSTEM_BINARY_PATH)) {
|
||||||
|
this.cachedBinaryPath = SYSTEM_BINARY_PATH;
|
||||||
|
return SYSTEM_BINARY_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
const binaryName = this.detectBinaryName();
|
const binaryName = this.detectBinaryName();
|
||||||
const toolsDir = join(this.appDataPath, '.tools', 'kepubify');
|
const toolsDir = join(this.appDataPath, '.tools', 'kepubify');
|
||||||
const binaryPath = join(toolsDir, binaryName);
|
const binaryPath = join(toolsDir, binaryName);
|
||||||
@@ -26,6 +33,15 @@ export class KepubifyBinaryService {
|
|||||||
return binaryPath;
|
return binaryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async exists(path: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await stat(path);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private detectBinaryName(): string {
|
private detectBinaryName(): string {
|
||||||
const platform = process.platform;
|
const platform = process.platform;
|
||||||
const arch = process.arch;
|
const arch = process.arch;
|
||||||
|
|||||||
Reference in New Issue
Block a user