Use temporary folder for plugin creation to be able to clean up easy

This commit is contained in:
Marcus Eide
2020-03-05 14:56:46 +01:00
parent 61f14d1baf
commit 9c1d95740c
2 changed files with 99 additions and 78 deletions
+33 -12
View File
@@ -5,29 +5,32 @@ import del from 'del';
import {
createFileFromTemplate,
createFromTemplateDir,
createPluginFolder,
createTemporaryPluginFolder,
movePlugin,
} from './createPlugin';
describe('createPlugin', () => {
describe('createPluginFolder', () => {
it('should create a plugin directory in the correct place', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
it('should create a temporary plugin directory in the correct place', () => {
const id = 'testPlugin';
const tempDir = path.join(os.tmpdir(), id);
try {
const pluginFolder = createPluginFolder(tempDir, 'foo');
expect(fs.existsSync(pluginFolder)).toBe(true);
expect(pluginFolder).toMatch(/packages\/plugins\/foo/);
createTemporaryPluginFolder(tempDir);
expect(fs.existsSync(tempDir)).toBe(true);
expect(tempDir).toMatch(id);
} finally {
del.sync(tempDir, { force: true });
}
});
it('should not create a plugin directory if it already exists', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
it('should not create a temporary plugin directory if it already exists', () => {
const id = 'testPlugin';
const tempDir = path.join(os.tmpdir(), id);
try {
const pluginFolder = createPluginFolder(tempDir, 'foo');
expect(fs.existsSync(pluginFolder)).toBe(true);
expect(() => createPluginFolder(tempDir, 'foo')).toThrowError(
/A plugin with the same name already exists/,
createTemporaryPluginFolder(tempDir);
expect(fs.existsSync(tempDir)).toBe(true);
expect(() => createTemporaryPluginFolder(tempDir)).toThrowError(
/Failed to create temporary plugin directory/,
);
} finally {
del.sync(tempDir, { force: true });
@@ -83,4 +86,22 @@ describe('createPlugin', () => {
}
});
});
describe('movePlugin', () => {
it('should move the temporary plugin directory to its final place', () => {
const id = 'testPlugin';
const tempDir = path.join(os.tmpdir(), id);
const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
const pluginFolder = path.join(rootDir, 'packages', 'plugins', id);
try {
createTemporaryPluginFolder(tempDir);
movePlugin(tempDir, rootDir, id);
expect(fs.existsSync(pluginFolder)).toBe(true);
expect(pluginFolder).toMatch(`/packages\/plugins\/${id}`);
} finally {
del.sync(tempDir, { force: true });
del.sync(rootDir, { force: true });
}
});
});
});
+66 -66
View File
@@ -8,42 +8,42 @@ import { promisify } from 'util';
import { exec } from 'child_process';
import { resolve as resolvePath } from 'path';
import { realpathSync, existsSync } from 'fs';
import os from 'os';
const MARKER_SUCCESS = chalk.green(`\n`);
const MARKER_FAILURE = chalk.red(`\n`);
export const createPluginFolder = (rootDir: string, id: string): string => {
const checkExists = (rootDir: string, id: string) => {
console.log();
console.log(chalk.green(' Creating the plugin directory:'));
console.log(chalk.green(' Checking if the plugin already exists:'));
const destination = path.join(rootDir, 'packages', 'plugins', id);
if (fs.existsSync(destination)) {
console.log(
chalk.red(
` failed:\t ✗ ${chalk.cyan(destination.replace(`${rootDir}/`, ''))}`,
),
);
console.log(chalk.red(` plugin ID\t${chalk.cyan(id)} already exists ✗`));
throw new Error(
`A plugin with the same name already exists: ${chalk.cyan(
destination.replace(`${rootDir}/`, ''),
)}\nPlease try again with a different Plugin ID`,
)}\nPlease try again with a different plugin ID`,
);
}
console.log(chalk.green(` plugin ID\t${chalk.cyan(id)} is available ✓`));
};
export const createTemporaryPluginFolder = (tempDir: string) => {
console.log();
console.log(chalk.green(' Creating a temporary plugin directory:'));
process.stdout.write(
chalk.green(
` creating\t${chalk.cyan(destination.replace(`${rootDir}/`, ''))}`,
),
chalk.green(` creating\t${chalk.cyan('temporary')} directory`),
);
try {
fs.mkdirSync(destination, { recursive: true });
process.stdout.write(chalk.green(' ✓\n'));
return destination;
fs.mkdirSync(tempDir);
process.stdout.write(chalk.green(MARKER_SUCCESS));
} catch (e) {
process.stdout.write(chalk.red(`\n`));
process.stdout.write(chalk.red(MARKER_FAILURE));
throw new Error(
`Failed to create plugin directory: ${destination}: ${e.message}`,
`Failed to create temporary plugin directory: ${e.message}`,
);
}
};
@@ -129,7 +129,7 @@ export const addPluginDependencyToApp = (
'utf-8',
);
} catch (e) {
process.stdout.write(chalk.red(`\n`));
process.stdout.write(chalk.red(MARKER_FAILURE));
throw new Error(
`Failed to add plugin as dependency in app: ${packageFile}: ${e.message}`,
);
@@ -164,7 +164,7 @@ export const addPluginToApp = (rootDir: string, pluginName: string) => {
try {
addExportStatement(pluginsFile, pluginExport);
} catch (e) {
process.stdout.write(chalk.red(`\n`));
process.stdout.write(chalk.red(MARKER_FAILURE));
throw new Error(
`Failed to import plugin in app: ${pluginsFile}: ${e.message}`,
);
@@ -183,14 +183,13 @@ export const createFromTemplateDir = async (
let files = [];
process.stdout.write(chalk.green(` reading\t`));
try {
files = await recursive(templateFolder);
process.stdout.write(
chalk.green(`${chalk.cyan(`${files.length} files`)}\n`),
console.log(
chalk.green(` reading\t${chalk.cyan(`${files.length} files`)}`),
);
} catch (e) {
console.log(chalk.red(` ✗ 0 files\n`));
console.log(chalk.red(` reading\t${chalk.cyan('0')} files`));
throw new Error(`Failed to read files in template directory: ${e.message}`);
}
@@ -228,42 +227,24 @@ export const createFromTemplateDir = async (
});
};
const cleanUp = async (rootDir: string, id: string) => {
const destination = path.join(rootDir, 'packages', 'plugins', id);
const questions: Question[] = [
{
type: 'confirm',
name: 'cleanup',
message: chalk.yellow(
`It seems that something went wrong when creating the plugin 🤔\nDo you want to remove the following directory and all the files in it:\n${chalk.cyan(
destination,
)}`,
),
},
];
const answers: Answers = await inquirer.prompt(questions);
if (answers.cleanup) {
const cleanUp = (tempDir: string, id: string) => {
console.log(
chalk.green(
`It seems that something went wrong when creating the plugin 🤔 `,
),
);
console.log(
chalk.green('We are going to clean up, and then you can try again.'),
);
process.stdout.write(chalk.green(` Cleaning up ${chalk.cyan(id)}`));
try {
fs.rmdirSync(tempDir, { recursive: true });
process.stdout.write(chalk.green(MARKER_SUCCESS));
console.log();
console.log(chalk.green(`🧹 Cleaning up...`));
} catch (e) {
process.stdout.write(chalk.red(MARKER_FAILURE));
console.log();
console.log(chalk.green(` Removing plugin:`));
process.stdout.write(
chalk.green(
` deleting\t${chalk.cyan(destination.replace(`${rootDir}/`, ''))}`,
),
);
try {
// Not using recursion here, so only empty directories can be removed
fs.rmdirSync(destination);
process.stdout.write(MARKER_SUCCESS);
console.log();
} catch (e) {
process.stdout.write(MARKER_FAILURE);
console.log();
console.log(chalk.red(`Failed to cleanup: ${e.message}`));
}
console.log(chalk.red(`Failed to cleanup: ${e.message}`));
}
};
@@ -289,6 +270,24 @@ const buildPlugin = async (pluginFolder: string) => {
}
};
export const movePlugin = (tempDir: string, rootDir: string, id: string) => {
console.log();
console.log(chalk.green(` Finalizing the plugin:`));
const destination = path.join(rootDir, 'packages', 'plugins', id);
process.stdout.write(
chalk.green(` moving\t${chalk.cyan(id)} to final location`),
);
try {
fs.moveSync(tempDir, destination);
process.stdout.write(chalk.green(MARKER_SUCCESS));
} catch (e) {
process.stdout.write(chalk.red(MARKER_FAILURE));
throw new Error(`Failed to move plugin: ${e.message}`);
}
};
const createPlugin = async (): Promise<any> => {
const questions: Question[] = [
{
@@ -305,14 +304,17 @@ const createPlugin = async (): Promise<any> => {
const appPackage = resolvePath(rootDir, 'packages', 'app');
const cliPackage = resolvePath(__dirname, '..', '..');
const templateFolder = resolvePath(cliPackage, 'templates', 'default-plugin');
const tempDir = path.join(os.tmpdir(), answers.id);
console.log();
console.log(chalk.green('Creating the plugin...'));
try {
console.log();
console.log(chalk.green('🧩 Creating the plugin...'));
const destinationFolder = createPluginFolder(rootDir, answers.id);
await createFromTemplateDir(templateFolder, destinationFolder, answers);
await buildPlugin(destinationFolder);
checkExists(rootDir, answers.id);
createTemporaryPluginFolder(tempDir);
await createFromTemplateDir(templateFolder, tempDir, answers);
await buildPlugin(tempDir);
movePlugin(tempDir, rootDir, answers.id);
if (existsSync(appPackage)) {
addPluginDependencyToApp(rootDir, answers.id);
@@ -328,16 +330,14 @@ const createPlugin = async (): Promise<any> => {
),
);
console.log();
return destinationFolder;
} catch (e) {
console.log();
console.log(`${chalk.red(e.message)}`);
console.log();
cleanUp(tempDir, answers.id);
console.log();
console.log(`🔥 ${chalk.red('Failed to create plugin!')}`);
console.log();
await cleanUp(rootDir, answers.id);
}
};