Add full cross-platform path support
- Added automatic volume path translation in deployment (deploy.js) - Updated FileBrowser template to use /opt/ instead of hard-coded E:/ - Migrated self-updater.js to use centralized platformPaths module - Updated UI placeholders to use platform-neutral paths (/media/) - All paths now automatically adapt to Windows or Linux at runtime via process.platform detection
This commit is contained in:
@@ -672,8 +672,8 @@ const APP_TEMPLATES = {
|
|||||||
image: "filebrowser/filebrowser:latest",
|
image: "filebrowser/filebrowser:latest",
|
||||||
ports: ["{{PORT}}:80"],
|
ports: ["{{PORT}}:80"],
|
||||||
volumes: [
|
volumes: [
|
||||||
"E:/docker-progs/filebrowser/data:/srv",
|
"/opt/filebrowser/data:/srv",
|
||||||
"E:/docker-progs/filebrowser/database:/database"
|
"/opt/filebrowser/database:/database"
|
||||||
],
|
],
|
||||||
environment: {}
|
environment: {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -106,13 +106,20 @@ module.exports = function(ctx, helpers) {
|
|||||||
throw new Error(`[DC-203] Port conflict detected: ${conflictDetails}. Please choose a different port.`);
|
throw new Error(`[DC-203] Port conflict detected: ${conflictDetails}. Please choose a different port.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate volume paths for cross-platform compatibility
|
||||||
|
const translatedVolumes = (processedTemplate.docker.volumes || []).map(volume => {
|
||||||
|
const [hostPath, ...rest] = volume.split(':');
|
||||||
|
const translatedHost = platformPaths.toDockerMountPath(hostPath);
|
||||||
|
return rest.length > 0 ? `${translatedHost}:${rest.join(':')}` : translatedHost;
|
||||||
|
});
|
||||||
|
|
||||||
const containerConfig = {
|
const containerConfig = {
|
||||||
Image: processedTemplate.docker.image,
|
Image: processedTemplate.docker.image,
|
||||||
name: containerName,
|
name: containerName,
|
||||||
ExposedPorts: {},
|
ExposedPorts: {},
|
||||||
HostConfig: {
|
HostConfig: {
|
||||||
PortBindings: {},
|
PortBindings: {},
|
||||||
Binds: processedTemplate.docker.volumes || [],
|
Binds: translatedVolumes,
|
||||||
RestartPolicy: { Name: 'unless-stopped' },
|
RestartPolicy: { Name: 'unless-stopped' },
|
||||||
LogConfig: DOCKER.LOG_CONFIG
|
LogConfig: DOCKER.LOG_CONFIG
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,18 +16,17 @@ const path = require('path');
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require('child_process');
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
const platformPaths = require('./platform-paths');
|
||||||
const isWindows = process.platform === 'win32';
|
|
||||||
|
|
||||||
const DEFAULTS = {
|
const DEFAULTS = {
|
||||||
CHECK_INTERVAL: 30 * 60 * 1000, // 30 minutes
|
CHECK_INTERVAL: 30 * 60 * 1000, // 30 minutes
|
||||||
UPDATE_URL: 'https://get.dashcaddy.net/release',
|
UPDATE_URL: 'https://get.dashcaddy.net/release',
|
||||||
MIRROR_URL: 'https://get2.dashcaddy.net/release',
|
MIRROR_URL: 'https://get2.dashcaddy.net/release',
|
||||||
UPDATES_DIR: isWindows ? 'C:/caddy/updates' : '/app/updates',
|
UPDATES_DIR: platformPaths.isWindows ? path.join(platformPaths.caddyBase, 'updates') : '/app/updates',
|
||||||
// API_SOURCE_DIR is the HOST path — written to trigger.json for the host-side updater
|
// API_SOURCE_DIR is the HOST path — written to trigger.json for the host-side updater
|
||||||
API_SOURCE_DIR: isWindows ? 'C:/caddy/sites/dashcaddy-api' : '/etc/dashcaddy/sites/dashcaddy-api',
|
API_SOURCE_DIR: path.join(platformPaths.caddySites, 'dashcaddy-api'),
|
||||||
// FRONTEND_DIR is the container path — dashboard is volume-mounted at /app/dashboard
|
// FRONTEND_DIR is the container path — dashboard is volume-mounted at /app/dashboard
|
||||||
FRONTEND_DIR: isWindows ? 'C:/caddy/sites/status' : '/app/dashboard',
|
FRONTEND_DIR: platformPaths.isWindows ? path.join(platformPaths.caddySites, 'status') : '/app/dashboard',
|
||||||
MAX_BACKUPS: 3,
|
MAX_BACKUPS: 3,
|
||||||
HEALTH_TIMEOUT: 60000,
|
HEALTH_TIMEOUT: 60000,
|
||||||
DOWNLOAD_TIMEOUT: 120000,
|
DOWNLOAD_TIMEOUT: 120000,
|
||||||
@@ -44,7 +43,7 @@ class SelfUpdater extends EventEmitter {
|
|||||||
updatesDir: options.updatesDir || DEFAULTS.UPDATES_DIR,
|
updatesDir: options.updatesDir || DEFAULTS.UPDATES_DIR,
|
||||||
// hostUpdatesDir is the HOST path that maps to updatesDir inside the container.
|
// hostUpdatesDir is the HOST path that maps to updatesDir inside the container.
|
||||||
// Used when writing trigger.json so the host-side script can find staging files.
|
// Used when writing trigger.json so the host-side script can find staging files.
|
||||||
hostUpdatesDir: options.hostUpdatesDir || (isWindows ? options.updatesDir || DEFAULTS.UPDATES_DIR : '/opt/dashcaddy/updates'),
|
hostUpdatesDir: options.hostUpdatesDir || (platformPaths.isWindows ? options.updatesDir || DEFAULTS.UPDATES_DIR : '/opt/dashcaddy/updates'),
|
||||||
apiSourceDir: options.apiSourceDir || DEFAULTS.API_SOURCE_DIR,
|
apiSourceDir: options.apiSourceDir || DEFAULTS.API_SOURCE_DIR,
|
||||||
frontendDir: options.frontendDir || DEFAULTS.FRONTEND_DIR,
|
frontendDir: options.frontendDir || DEFAULTS.FRONTEND_DIR,
|
||||||
maxBackups: parseInt(options.maxBackups || DEFAULTS.MAX_BACKUPS, 10),
|
maxBackups: parseInt(options.maxBackups || DEFAULTS.MAX_BACKUPS, 10),
|
||||||
|
|||||||
@@ -104,7 +104,7 @@
|
|||||||
|
|
||||||
<!-- Path input with browse button -->
|
<!-- Path input with browse button -->
|
||||||
<div class="flex-row-gap">
|
<div class="flex-row-gap">
|
||||||
<input type="text" id="deploy-media-path" placeholder="E:/Movies, E:/TVShows"
|
<input type="text" id="deploy-media-path" placeholder="/media/Movies, /media/TVShows"
|
||||||
class="input-flex" style="font-size: 0.95rem;" />
|
class="input-flex" style="font-size: 0.95rem;" />
|
||||||
<button type="button" id="browse-media-btn" style="padding: 10px 16px; background: var(--accent); color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 500; white-space: nowrap;">
|
<button type="button" id="browse-media-btn" style="padding: 10px 16px; background: var(--accent); color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 500; white-space: nowrap;">
|
||||||
📂 Browse
|
📂 Browse
|
||||||
@@ -465,7 +465,7 @@
|
|||||||
if (appTemplate.mediaMount) {
|
if (appTemplate.mediaMount) {
|
||||||
mediaPathSection.style.display = 'block';
|
mediaPathSection.style.display = 'block';
|
||||||
mediaPathInput.value = '';
|
mediaPathInput.value = '';
|
||||||
mediaPathInput.placeholder = 'E:/Movies, E:/TVShows or click Browse';
|
mediaPathInput.placeholder = '/media/Movies, /media/TVShows or click Browse';
|
||||||
|
|
||||||
// Fetch detected mounts from existing media servers
|
// Fetch detected mounts from existing media servers
|
||||||
const detectedMountsContainer = document.getElementById('detected-mounts-container');
|
const detectedMountsContainer = document.getElementById('detected-mounts-container');
|
||||||
|
|||||||
Reference in New Issue
Block a user