diff --git a/app/cli.ts b/app/cli.ts index 4ebc4c6ed..43e03a6f1 100644 --- a/app/cli.ts +++ b/app/cli.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import path from 'path'; -import { spawn } from 'child_process'; +import { spawn, exec } from 'child_process'; import { parse, ArgsParseOptions, ArgumentConfig } from 'ts-command-line-args'; import dotEnv from 'dotenv'; import findProcess from 'find-process'; @@ -224,10 +224,19 @@ const commands = { logger.debug('Writing %s to %s', newEnvLine, envFlashFilePath); // Copy the new env over to live location before restarting - const newDotEnvFilePath = path.join(basePath, `.env.${newEnv}`); - const dotEnvFilePath = path.join(basePath, '.env'); - await fs.promises.copyFile(newDotEnvFilePath, dotEnvFilePath); - logger.debug('Copying %s to %s', newDotEnvFilePath, dotEnvFilePath); + const source = path.join(basePath, `.env.${newEnv}`); + const destination = path.join(basePath, '.env'); + logger.debug('Copying %s to %s', source, destination); + await new Promise((resolve, reject) => { + // Use the native cp command to ensure we're outside the virtual file system + exec(`cp "${source}" "${destination}"`, error => { + if (error) { + return reject(error); + } + + resolve(); + }); + }); // If there's a process running restart it const unraidApiPid = await getUnraidApiPid(); diff --git a/test/cli.spec.ts b/test/cli.spec.ts index 3511a6627..f036700e0 100644 --- a/test/cli.spec.ts +++ b/test/cli.spec.ts @@ -1,5 +1,5 @@ import { promisify } from 'util'; -import { join as joinPath } from 'path'; +import { join as joinPath, resolve as resolvePath } from 'path'; import { exec as execWithCallback } from 'child_process'; import { writeFileSync, readFileSync } from 'fs'; import tempy from 'tempy'; @@ -19,6 +19,9 @@ const repeat = async (func: () => void, times = 0) => { return promise; }; +const stagingEnv = readFileSync(resolvePath(__dirname, '..', '.env.staging'), 'utf-8'); +const productionEnv = readFileSync(resolvePath(__dirname, '..', '.env.production'), 'utf-8'); + test.beforeEach(t => { t.context = { paths: { @@ -28,8 +31,8 @@ test.beforeEach(t => { }; writeFileSync(t.context.paths.PATHS_MYSERVERS_ENV, 'env="production"'); - writeFileSync(joinPath(t.context.paths.PATHS_UNRAID_API_BASE, '.env.staging'), 'env="staging"'); - writeFileSync(joinPath(t.context.paths.PATHS_UNRAID_API_BASE, '.env.production'), 'env="production"'); + writeFileSync(joinPath(t.context.paths.PATHS_UNRAID_API_BASE, '.env.staging'), stagingEnv); + writeFileSync(joinPath(t.context.paths.PATHS_UNRAID_API_BASE, '.env.production'), productionEnv); }); test.serial('Loads production when no env is set', async t => { @@ -48,7 +51,7 @@ test.serial('Loads production when no env is set', async t => { t.is(output, 'Current ENV in file: undefined\nNo ENV found, setting env to "production"...\nRun "unraid-api start" to start the API.\n'); // Check the .env was updated on the live server - t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), 'env="production"'); + t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), productionEnv); // Check the env file that's persisted on the boot drive t.is(readFileSync(PATHS_MYSERVERS_ENV, 'utf-8'), 'env="production"'); @@ -71,7 +74,7 @@ test.serial('Loads production when switching from staging', async t => { t.is(output, 'Current ENV in file: staging\nSwitching from "staging" to "production"...\nRun "unraid-api start" to start the API.\n'); // Check the .env was updated on the live server - t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), 'env="production"'); + t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), productionEnv); // Check the env file that's persisted on the boot drive t.is(readFileSync(PATHS_MYSERVERS_ENV, 'utf-8'), 'env="production"'); @@ -94,7 +97,7 @@ test.serial('Loads staging when switching from production', async t => { t.is(output, 'Current ENV in file: production\nSwitching from "production" to "staging"...\nRun "unraid-api start" to start the API.\n'); // Check the .env was updated on the live server - t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), 'env="staging"'); + t.is(readFileSync(joinPath(PATHS_UNRAID_API_BASE, '.env'), 'utf-8'), stagingEnv); // Check the env file that's persisted on the boot drive t.is(readFileSync(PATHS_MYSERVERS_ENV, 'utf-8'), 'env="staging"');