diff --git a/packages/strapi-utils/lib/cli.js b/packages/strapi-utils/lib/cli.js new file mode 100755 index 0000000000..0c9ef59c8a --- /dev/null +++ b/packages/strapi-utils/lib/cli.js @@ -0,0 +1,31 @@ +'use strict'; + +/** + * Module dependencies + */ + +// Node.js core. +const path = require('path'); + +/** + * Check that we're in a valid Strapi project. + * + * @returns {boolean} + */ + +const isStrapiApp = () => { + const pathToPackageJSON = path.resolve(process.cwd(), 'package.json'); + let validPackageJSON = true; + + try { + require(pathToPackageJSON); + } catch (e) { + validPackageJSON = false; + } + + return validPackageJSON; +}; + +module.exports = { + isStrapiApp +}; diff --git a/packages/strapi-utils/lib/index.js b/packages/strapi-utils/lib/index.js index 8b7e16af98..e020a1c534 100755 --- a/packages/strapi-utils/lib/index.js +++ b/packages/strapi-utils/lib/index.js @@ -5,6 +5,7 @@ */ module.exports = { + cli: require('./cli'), commander: require('./commander'), dictionary: require('./dictionary'), finder: require('./finder'), diff --git a/packages/strapi/bin/strapi-generate.js b/packages/strapi/bin/strapi-generate.js index 23b1da94fb..2d89be676a 100755 --- a/packages/strapi/bin/strapi-generate.js +++ b/packages/strapi/bin/strapi-generate.js @@ -13,7 +13,7 @@ const path = require('path'); const generate = require('strapi-generate'); // Logger. -const logger = require('strapi-utils').logger; +const { logger, cli } = require('strapi-utils'); /** * `$ strapi generate` @@ -36,16 +36,7 @@ module.exports = function (id, cliArguments) { // Check that we're in a valid Strapi project. if (scope.generatorType !== 'new' || scope.generatorType !== 'generator' || scope.generatorType !== 'hook') { - const pathToPackageJSON = path.resolve(scope.rootPath, 'package.json'); - let invalidPackageJSON; - - try { - require(pathToPackageJSON); - } catch (e) { - invalidPackageJSON = true; - } - - if (invalidPackageJSON) { + if (!cli.isStrapiApp()) { return logger.error('This command can only be used inside a Strapi project.'); } } diff --git a/packages/strapi/bin/strapi-install.js b/packages/strapi/bin/strapi-install.js new file mode 100755 index 0000000000..a034dc37bb --- /dev/null +++ b/packages/strapi/bin/strapi-install.js @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +'use strict'; + +/** + * Module dependencies + */ + +// Node.js core. +const { exec } = require('child_process'); +const fs = require('fs'); + +// Logger. +const { logger, cli } = require('strapi-utils'); + +/** + * `$ strapi install` + * + * Install a Strapi plugin. + */ + +module.exports = function (plugin, cliArguments) { + // Define variables. + const pluginPrefix = 'strapi-plugin-'; + const pluginId = `${pluginPrefix}${plugin}`; + const pluginPath = `./plugins/${plugin}`; + + // Check that we're in a valid Strapi project. + if (!cli.isStrapiApp()) { + return logger.error('This command can only be used inside a Strapi project.'); + } + + // Check that the plugin is not installed yet. + if (fs.existsSync(pluginPath)) { + logger.error(`It looks like this plugin is already installed. Please check in \`${pluginPath}\`.`); + process.exit(1); + } + + // Progress message. + logger.debug('Installation in progress...'); + + if (cliArguments.dev) { + // Run `npm link` to create a symlink between the node module + // installed globally and the current Strapi application. + exec(`npm link ${pluginId}`, (err) => { + if (err) { + logger.error('It looks like this plugin is not installed globally.'); + process.exit(1); + } + + try { + // Create a symlink between the Strapi application and the node module installed. + fs.symlinkSync(`../node_modules/${pluginId}`, pluginPath, 'dir'); + + // Success. + logger.info('The plugin has been successfully installed.'); + process.exit(0); + } catch (err) { + logger.error('An error occurred during plugin installation.'); + process.exit(1); + } + }); + } else { + // Debug message. + logger.debug('Installing the plugin from npm registry.'); + + // Install the plugin from the npm registry. + exec(`npm install ${pluginId}`, (err) => { + if (err) { + logger.error(`An error occurred during plugin installation. \nPlease make sure this plugin is available on npm: https://www.npmjs.com/package/${pluginId}`); + process.exit(1); + } + + // Debug message. + logger.debug('Plugin successfully installed from npm registry.'); + + try { + // Debug message. + logger.debug(`Moving the \`node_modules/${pluginId}\` folder to the \`./plugins\` folder.`); + + // Move the plugin from the `node_modules` folder to the `./plugins` folder. + fs.renameSync(`./node_modules/${pluginId}`, pluginPath); + + // Success. + logger.info('The plugin has been successfully installed.'); + process.exit(0); + } catch (err) { + logger.error('An error occurred during plugin installation.'); + process.exit(1); + } + }); + } +}; diff --git a/packages/strapi/bin/strapi-start.js b/packages/strapi/bin/strapi-start.js index 2149eb91ef..1576f11f00 100755 --- a/packages/strapi/bin/strapi-start.js +++ b/packages/strapi/bin/strapi-start.js @@ -18,7 +18,7 @@ const forever = require('forever-monitor'); const isLocalStrapiValid = require('../lib/private/isLocalStrapiValid'); // Logger. -const logger = require('strapi-utils').logger; +const { logger, cli } = require('strapi-utils'); /** * `$ strapi start` @@ -28,6 +28,11 @@ const logger = require('strapi-utils').logger; */ module.exports = function() { + // Check that we're in a valid Strapi project. + if (!cli.isStrapiApp()) { + return logger.error('This command can only be used inside a Strapi project.'); + } + try { // Set NODE_ENV if (_.isEmpty(process.env.NODE_ENV)) { diff --git a/packages/strapi/bin/strapi-uninstall.js b/packages/strapi/bin/strapi-uninstall.js new file mode 100755 index 0000000000..88d794ba21 --- /dev/null +++ b/packages/strapi/bin/strapi-uninstall.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +'use strict'; + +/** + * Module dependencies + */ + +// Node.js core. +const { exec } = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const rimraf = require('rimraf'); + +// Logger. +const { logger, cli } = require('strapi-utils'); + +/** + * `$ strapi uninstall` + * + * Uninstall a Strapi plugin. + */ + +module.exports = function (plugin) { + // Define variables. + const pluginPath = `./plugins/${plugin}`; + + // Check that we're in a valid Strapi project. + if (!cli.isStrapiApp()) { + return logger.error('This command can only be used inside a Strapi project.'); + } + + // Check that the plugin is installed. + if (!fs.existsSync(pluginPath)) { + logger.error(`It looks like this plugin is not installed. Please check that \`${pluginPath}\` folder exists.`); + process.exit(1); + } + + // Delete the plugin folder. + rimraf(pluginPath, (err) => { + if (err) { + logger.error('An error occurred during plugin uninstallation.'); + process.exit(1); + } + + // Success. + logger.info('The plugin has been successfully uninstalled.'); + process.exit(0); + }); +}; diff --git a/packages/strapi/bin/strapi.js b/packages/strapi/bin/strapi.js index 362a46fd05..ba26cc9937 100755 --- a/packages/strapi/bin/strapi.js +++ b/packages/strapi/bin/strapi.js @@ -126,6 +126,19 @@ program .description('generate a custom generator') .action(require('./strapi-generate')); +// `$ strapi install` +program + .command('install ') + .option('-d, --dev', 'Development mode') + .description('install a Strapi plugin') + .action(require('./strapi-install')); + +// `$ strapi uninstall` +program + .command('uninstall ') + .description('uninstall a Strapi plugin') + .action(require('./strapi-uninstall')); + // `$ strapi migrate:make` program .command('migrate:make')