validate path directory, and prevent target from being overwritten
Validation now occurs to ensure that the target path exists and is a directory. Additionally, instead of moving the temporary directory to the target path, files are now recursively copied, and then cleaned up. This was to support app creation in the current directory, without clobbering existing files (for example .git/) Instead of overwriting the target `path` directory while using the move method, Signed-off-by: Colton Padden <colton.padden@fastmail.com>
This commit is contained in:
@@ -24,10 +24,11 @@ import { resolve as resolvePath } from 'path';
|
||||
import { findPaths } from '@backstage/cli-common';
|
||||
import os from 'os';
|
||||
import { Task, templatingTask } from './lib/tasks';
|
||||
import recursive from 'recursive-readdir';
|
||||
|
||||
const exec = promisify(execCb);
|
||||
|
||||
async function checkExists(rootDir: string, name: string) {
|
||||
async function checkAppPathDoesntExist(rootDir: string, name: string) {
|
||||
await Task.forItem('checking', name, async () => {
|
||||
const destination = resolvePath(rootDir, name);
|
||||
|
||||
@@ -40,6 +41,22 @@ async function checkExists(rootDir: string, name: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function checkPathExistsAndIsDirectory(path: string) {
|
||||
await Task.forItem('checking', path, async () => {
|
||||
if (await fs.pathExists(path)) {
|
||||
if (!fs.lstatSync(path).isDirectory()) {
|
||||
throw new Error(
|
||||
'Directory specified with --path argument is a file\nPlease ensure target path is a directory',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
'Directory specified with --path argument does not exist\nPlease try again with a different path',
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function createTemporaryAppFolder(tempDir: string) {
|
||||
await Task.forItem('creating', 'temporary directory', async () => {
|
||||
try {
|
||||
@@ -77,11 +94,18 @@ async function buildApp(appDir: string) {
|
||||
|
||||
async function moveApp(tempDir: string, destination: string, id: string) {
|
||||
await Task.forItem('moving', id, async () => {
|
||||
await fs.move(tempDir, destination, { overwrite: true }).catch(error => {
|
||||
throw new Error(
|
||||
`Failed to move app from ${tempDir} to ${destination}: ${error.message}`,
|
||||
);
|
||||
const tempFiles = await recursive(tempDir).catch(error => {
|
||||
throw new Error(`Failed to read temporary directory: ${error.message}`);
|
||||
});
|
||||
|
||||
for (const tempFile of tempFiles) {
|
||||
const destFile = tempFile.replace(tempDir, destination);
|
||||
await fs.copy(tempFile, destFile).catch(error => {
|
||||
throw new Error(
|
||||
`Failed to move file from ${tempFile} to ${destFile}: ${error.message}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -130,11 +154,13 @@ export default async (cmd: Command): Promise<void> => {
|
||||
Task.log('Creating the app...');
|
||||
|
||||
try {
|
||||
// Directory must not already exist when using consructed path from
|
||||
// `answers.name`
|
||||
if (!cmd.path) {
|
||||
Task.section('Checking if the directory is available');
|
||||
await checkExists(paths.targetDir, answers.name);
|
||||
Task.section('Checking if the directory is available');
|
||||
if (cmd.path) {
|
||||
await checkPathExistsAndIsDirectory(appDir);
|
||||
} else {
|
||||
// Directory must not already exist when using consructed path from
|
||||
// `answers.name`
|
||||
await checkAppPathDoesntExist(paths.targetDir, answers.name);
|
||||
}
|
||||
|
||||
Task.section('Creating a temporary app directory');
|
||||
@@ -146,6 +172,9 @@ export default async (cmd: Command): Promise<void> => {
|
||||
Task.section('Moving to final location');
|
||||
await moveApp(tempDir, appDir, answers.name);
|
||||
|
||||
Task.section('Cleanup');
|
||||
await cleanUp(tempDir);
|
||||
|
||||
if (!cmd.skipInstall) {
|
||||
Task.section('Building the app');
|
||||
await buildApp(appDir);
|
||||
|
||||
Reference in New Issue
Block a user