UNPKG

7.99 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5const tree_sync_1 = __importDefault(require("tree-sync"));
6const child_process_1 = __importDefault(require("child_process"));
7const fs_1 = __importDefault(require("fs"));
8const path_1 = __importDefault(require("path"));
9const cli_1 = __importDefault(require("./errors/cli"));
10const index_1 = __importDefault(require("./index"));
11const messages_1 = __importDefault(require("./messages"));
12const WatchDetector = require('watch-detector');
13const UI = require('console-ui');
14function getBuilder(options) {
15 const brocfile = index_1.default.loadBrocfile(options);
16 return new index_1.default.Builder(brocfile(buildBrocfileOptions(options)));
17}
18function getWatcher(options) {
19 return options.watch ? index_1.default.Watcher : require('./dummy-watcher');
20}
21function buildWatcherOptions(options, ui) {
22 if (!options) {
23 options = {};
24 }
25 const detector = new WatchDetector({
26 ui,
27 childProcess: child_process_1.default,
28 fs: fs_1.default,
29 watchmanSupportsPlatform: /^win/.test(process.platform),
30 root: process.cwd(),
31 });
32 const watchPreference = detector.findBestWatcherOption({
33 watcher: options.watcher,
34 });
35 const watcher = watchPreference.watcher;
36 return {
37 saneOptions: {
38 poll: watcher === 'polling',
39 watchman: watcher === 'watchman',
40 node: watcher === 'node' || !watcher,
41 },
42 };
43}
44function buildBrocfileOptions(options) {
45 return {
46 env: options.environment,
47 };
48}
49function guardOutputDir(outputDir) {
50 if (isParentDirectory(outputDir)) {
51 throw new cli_1.default(`build directory can not be the current or direct parent directory: ${outputDir}`);
52 }
53}
54function isParentDirectory(outputPath) {
55 if (!fs_1.default.existsSync(outputPath)) {
56 return false;
57 }
58 outputPath = fs_1.default.realpathSync(outputPath);
59 const rootPath = process.cwd();
60 const rootPathParents = [rootPath];
61 let dir = path_1.default.dirname(rootPath);
62 rootPathParents.push(dir);
63 while (dir !== path_1.default.dirname(dir)) {
64 dir = path_1.default.dirname(dir);
65 rootPathParents.push(dir);
66 }
67 return rootPathParents.indexOf(outputPath) !== -1;
68}
69module.exports = function broccoliCLI(args, ui = new UI()) {
70 // always require a fresh commander, as it keeps state at module scope
71 delete require.cache[require.resolve('commander')];
72 const program = require('commander');
73 let actionPromise;
74 program.version(require('../package.json').version).usage('<command> [options] [<args ...>]');
75 program
76 .command('serve')
77 .alias('s')
78 .description('start a broccoli server')
79 .option('--port <port>', 'the port to bind to [4200]', 4200)
80 .option('--host <host>', 'the host to bind to [localhost]', 'localhost')
81 .option('--ssl', 'serve via HTTPS', false)
82 .option('--ssl-key <path>', 'path to SSL key file [ssl/server.key]', 'ssl/server.key')
83 .option('--ssl-cert <path>', 'path to SSL cert file [ssl/server.crt]', 'ssl/server.crt')
84 .option('--brocfile-path <path>', 'the path to brocfile')
85 .option('--output-path <path>', 'the path to target output folder')
86 .option('--cwd <path>', 'the path to working folder')
87 .option('--no-watch', 'turn off the watcher')
88 .option('--watcher <watcher>', 'select sane watcher mode')
89 .option('-e, --environment <environment>', 'build environment [development]', 'development')
90 .option('--prod', 'alias for --environment=production')
91 .option('--dev', 'alias for --environment=development')
92 .action((options) => {
93 if (options.prod) {
94 options.environment = 'production';
95 }
96 else if (options.dev) {
97 options.environment = 'development';
98 }
99 const builder = getBuilder(options);
100 const Watcher = getWatcher(options);
101 const outputDir = options.outputPath;
102 const watcher = new Watcher(builder, builder.watchedSourceNodeWrappers, buildWatcherOptions(options, ui));
103 if (outputDir) {
104 try {
105 guardOutputDir(outputDir);
106 }
107 catch (e) {
108 if (e instanceof cli_1.default) {
109 ui.writeError(e.message);
110 return process.exit(1);
111 }
112 throw e;
113 }
114 const outputTree = new tree_sync_1.default(builder.outputPath, outputDir);
115 watcher.on('buildSuccess', () => outputTree.sync());
116 }
117 actionPromise = index_1.default.server.serve(watcher, options.host, parseInt(options.port, 10), undefined, undefined, ui, options.ssl, options.sslKey, options.sslCert);
118 });
119 program
120 .command('build [target]')
121 .alias('b')
122 .description('output files to target directory')
123 .option('--brocfile-path <path>', 'the path to brocfile')
124 .option('--output-path <path>', 'the path to target output folder')
125 .option('--cwd <path>', 'the path to working folder')
126 .option('--watch', 'turn on the watcher')
127 .option('--watcher <watcher>', 'select sane watcher mode')
128 .option('-e, --environment <environment>', 'build environment [development]', 'development')
129 .option('--prod', 'alias for --environment=production')
130 .option('--dev', 'alias for --environment=development')
131 .action((outputDir, options) => {
132 if (outputDir && options.outputPath) {
133 ui.writeLine('option --output-path and [target] cannot be passed at same time', 'ERROR');
134 return process.exit(1);
135 }
136 if (options.outputPath) {
137 outputDir = options.outputPath;
138 }
139 if (!outputDir) {
140 outputDir = 'dist';
141 }
142 if (options.prod) {
143 options.environment = 'production';
144 }
145 else if (options.dev) {
146 options.environment = 'development';
147 }
148 try {
149 guardOutputDir(outputDir);
150 }
151 catch (e) {
152 if (e instanceof cli_1.default) {
153 ui.writeError(e);
154 return process.exit(1);
155 }
156 throw e;
157 }
158 const builder = getBuilder(options);
159 const Watcher = getWatcher(options);
160 const outputTree = new tree_sync_1.default(builder.outputPath, outputDir);
161 const watcher = new Watcher(builder, builder.watchedSourceNodeWrappers, buildWatcherOptions(options, ui));
162 watcher.on('buildSuccess', () => {
163 outputTree.sync();
164 messages_1.default.onBuildSuccess(builder, ui);
165 if (!options.watch) {
166 watcher.quit();
167 }
168 });
169 watcher.on('buildFailure', (err) => {
170 ui.writeLine('build failure', 'ERROR');
171 ui.writeError(err);
172 });
173 function cleanupAndExit() {
174 return watcher.quit();
175 }
176 process.on('SIGINT', cleanupAndExit);
177 process.on('SIGTERM', cleanupAndExit);
178 actionPromise = (async () => {
179 try {
180 await watcher.start();
181 }
182 catch (e) {
183 ui.writeError(e);
184 }
185 finally {
186 try {
187 builder.cleanup();
188 process.exit(0);
189 }
190 catch (e) {
191 ui.writeLine('Cleanup error:', 'ERROR');
192 ui.writeError(e);
193 process.exit(1);
194 }
195 }
196 })();
197 });
198 program.parse(args || process.argv);
199 if (actionPromise) {
200 return actionPromise;
201 }
202 else {
203 program.outputHelp();
204 process.exit(1);
205 }
206};
207//# sourceMappingURL=cli.js.map
\No newline at end of file