UNPKG

5.37 kBJavaScriptView Raw
1'use strict';
2
3const path = require('path');
4const BbPromise = require('bluebird');
5const os = require('os');
6const chalk = require('chalk');
7const updateNotifier = require('update-notifier');
8const pkg = require('../package.json');
9const CLI = require('./classes/CLI');
10const Config = require('./classes/Config');
11const YamlParser = require('./classes/YamlParser');
12const PluginManager = require('./classes/PluginManager');
13const Utils = require('./classes/Utils');
14const Service = require('./classes/Service');
15const Variables = require('./classes/Variables');
16const ServerlessError = require('./classes/Error').ServerlessError;
17const Version = require('./../package.json').version;
18const isStandaloneExecutable = require('./utils/isStandaloneExecutable');
19const resolveCliInput = require('./utils/resolveCliInput');
20
21const installationMaintananceCommands = new Set(['uninstall', 'upgrade']);
22
23class Serverless {
24 constructor(config) {
25 let configObject = config;
26 configObject = configObject || {};
27
28 this.providers = {};
29
30 this.version = Version;
31
32 this.yamlParser = new YamlParser(this);
33 this.utils = new Utils(this);
34 this.service = new Service(this);
35 this.variables = new Variables(this);
36 this.pluginManager = new PluginManager(this);
37
38 // use the servicePath from the options or try to find it in the CWD
39 this.cliInputArgv = process.argv.slice(2);
40 configObject.servicePath =
41 configObject.servicePath ||
42 this.utils.findServicePath(resolveCliInput(this.cliInputArgv).options.config);
43
44 this.config = new Config(this, configObject);
45
46 this.classes = {};
47 this.classes.CLI = CLI;
48 this.classes.YamlParser = YamlParser;
49 this.classes.Utils = Utils;
50 this.classes.Service = Service;
51 this.classes.Variables = Variables;
52 this.classes.Error = ServerlessError;
53 this.classes.PluginManager = PluginManager;
54
55 this.serverlessDirPath = path.join(os.homedir(), '.serverless');
56 this.isStandaloneExecutable = isStandaloneExecutable;
57 }
58
59 init() {
60 // create an instanceId (can be e.g. used when a predictable random value is needed)
61 this.instanceId = new Date().getTime().toString();
62
63 // create a new CLI instance
64 this.cli = new this.classes.CLI(this, this.cliInputArgv);
65
66 // get an array of commands and options that should be processed
67 this.processedInput = this.cli.processInput();
68
69 // load config file
70 return this.pluginManager
71 .loadConfigFile()
72 .then(() => {
73 // set the options and commands which were processed by the CLI
74 this.pluginManager.setCliOptions(this.processedInput.options);
75 this.pluginManager.setCliCommands(this.processedInput.commands);
76
77 if (!installationMaintananceCommands.has(this.processedInput.commands[0])) {
78 // Check if update is available
79 const notifier = updateNotifier({ pkg });
80 notifier.notify({
81 message:
82 isStandaloneExecutable && notifier.update
83 ? `Update available ${chalk.dim(notifier.update.current)}${chalk.reset(
84 ' → '
85 )}${chalk.green(notifier.update.latest)} \nRun ${chalk.cyan(
86 'serverless upgrade'
87 )} to update`
88 : null,
89 });
90 }
91
92 return this.service.load(this.processedInput.options);
93 })
94 .then(() => {
95 // load all plugins
96 return this.pluginManager.loadAllPlugins(this.service.plugins);
97 })
98 .then(() => {
99 // give the CLI the plugins and commands so that it can print out
100 // information such as options when the user enters --help
101 this.cli.setLoadedPlugins(this.pluginManager.getPlugins());
102 this.cli.setLoadedCommands(this.pluginManager.getCommands());
103 return this.pluginManager.updateAutocompleteCacheFile();
104 });
105 }
106
107 run() {
108 this.utils.logStat(this).catch(() => BbPromise.resolve());
109
110 if (this.cli.displayHelp(this.processedInput)) {
111 return BbPromise.resolve();
112 }
113 this.cli.suppressLogIfPrintCommand(this.processedInput);
114
115 // make sure the command exists before doing anything else
116 this.pluginManager.validateCommand(this.processedInput.commands);
117
118 // populate variables after --help, otherwise help may fail to print
119 // (https://github.com/serverless/serverless/issues/2041)
120 return this.variables.populateService(this.pluginManager.cliOptions).then(() => {
121 // merge arrays after variables have been populated
122 // (https://github.com/serverless/serverless/issues/3511)
123 this.service.mergeArrays();
124
125 // populate function names after variables are loaded in case functions were externalized
126 // (https://github.com/serverless/serverless/issues/2997)
127 this.service.setFunctionNames(this.processedInput.options);
128
129 // validate the service configuration, now that variables are loaded
130 this.service.validate();
131
132 // trigger the plugin lifecycle when there's something which should be processed
133 return this.pluginManager.run(this.processedInput.commands);
134 });
135 }
136
137 setProvider(name, provider) {
138 this.providers[name] = provider;
139 }
140
141 getProvider(name) {
142 return this.providers[name] ? this.providers[name] : false;
143 }
144
145 getVersion() {
146 return this.version;
147 }
148}
149
150module.exports = Serverless;