1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | const tree_sync_1 = __importDefault(require("tree-sync"));
|
6 | const child_process_1 = __importDefault(require("child_process"));
|
7 | const fs_1 = __importDefault(require("fs"));
|
8 | const path_1 = __importDefault(require("path"));
|
9 | const cli_1 = __importDefault(require("./errors/cli"));
|
10 | const index_1 = __importDefault(require("./index"));
|
11 | const messages_1 = __importDefault(require("./messages"));
|
12 | const WatchDetector = require('watch-detector');
|
13 | const UI = require('console-ui');
|
14 | function getBuilder(options) {
|
15 | const brocfile = index_1.default.loadBrocfile(options);
|
16 | return new index_1.default.Builder(brocfile(buildBrocfileOptions(options)));
|
17 | }
|
18 | function getWatcher(options) {
|
19 | return options.watch ? index_1.default.Watcher : require('./dummy-watcher');
|
20 | }
|
21 | function 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 | }
|
44 | function buildBrocfileOptions(options) {
|
45 | return {
|
46 | env: options.environment,
|
47 | };
|
48 | }
|
49 | function 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 | }
|
54 | function 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 | }
|
69 | module.exports = function broccoliCLI(args, ui = new UI()) {
|
70 |
|
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 |
|
\ | No newline at end of file |