1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const cli_framework_1 = require("@ionic/cli-framework");
|
4 | const utils_process_1 = require("@ionic/utils-process");
|
5 | const utils_subprocess_1 = require("@ionic/utils-subprocess");
|
6 | const Debug = require("debug");
|
7 | const color_1 = require("./color");
|
8 | const errors_1 = require("./errors");
|
9 | const hooks_1 = require("./hooks");
|
10 | const debug = Debug('ionic:lib:build');
|
11 | exports.BUILD_SCRIPT = 'ionic:build';
|
12 | exports.COMMON_BUILD_COMMAND_OPTIONS = [
|
13 | {
|
14 | name: 'engine',
|
15 | summary: `Target engine (e.g. ${['browser', 'cordova'].map(e => color_1.input(e)).join(', ')})`,
|
16 | groups: ["advanced" ],
|
17 | },
|
18 | {
|
19 | name: 'platform',
|
20 | summary: `Target platform on chosen engine (e.g. ${['ios', 'android'].map(e => color_1.input(e)).join(', ')})`,
|
21 | groups: ["advanced" ],
|
22 | },
|
23 | ];
|
24 | class BuildRunner {
|
25 | getPkgManagerBuildCLI() {
|
26 | return this.e.config.get('npmClient') === 'npm' ? new NpmBuildCLI(this.e) : new YarnBuildCLI(this.e);
|
27 | }
|
28 | createBaseOptionsFromCommandLine(inputs, options) {
|
29 | const separatedArgs = options['--'];
|
30 | const platform = options['platform'] ? String(options['platform']) : undefined;
|
31 | const engine = this.determineEngineFromCommandLine(options);
|
32 | const project = options['project'] ? String(options['project']) : undefined;
|
33 | const verbose = !!options['verbose'];
|
34 | return { '--': separatedArgs ? separatedArgs : [], engine, platform, project, verbose };
|
35 | }
|
36 | determineEngineFromCommandLine(options) {
|
37 | if (options['engine']) {
|
38 | return String(options['engine']);
|
39 | }
|
40 | if (options['cordova']) {
|
41 | return 'cordova';
|
42 | }
|
43 | return 'browser';
|
44 | }
|
45 | async beforeBuild(options) {
|
46 | const hook = new BuildBeforeHook(this.e);
|
47 | try {
|
48 | await hook.run({ name: hook.name, build: options });
|
49 | }
|
50 | catch (e) {
|
51 | if (e instanceof cli_framework_1.BaseError) {
|
52 | throw new errors_1.FatalException(e.message);
|
53 | }
|
54 | throw e;
|
55 | }
|
56 | }
|
57 | async run(options) {
|
58 | debug('build options: %O', options);
|
59 | if (options.engine === 'cordova' && !options.platform) {
|
60 | this.e.log.warn(`Cordova engine chosen without a target platform. This could cause issues. Please use the ${color_1.input('--platform')} option.`);
|
61 | }
|
62 | await this.beforeBuild(options);
|
63 | await this.buildProject(options);
|
64 | await this.afterBuild(options);
|
65 | }
|
66 | async afterBuild(options) {
|
67 | const hook = new BuildAfterHook(this.e);
|
68 | try {
|
69 | await hook.run({ name: hook.name, build: options });
|
70 | }
|
71 | catch (e) {
|
72 | if (e instanceof cli_framework_1.BaseError) {
|
73 | throw new errors_1.FatalException(e.message);
|
74 | }
|
75 | throw e;
|
76 | }
|
77 | }
|
78 | }
|
79 | exports.BuildRunner = BuildRunner;
|
80 | class BuildCLI {
|
81 | constructor(e) {
|
82 | this.e = e;
|
83 | |
84 |
|
85 |
|
86 | this.global = false;
|
87 | }
|
88 | get resolvedProgram() {
|
89 | if (this._resolvedProgram) {
|
90 | return this._resolvedProgram;
|
91 | }
|
92 | return this.program;
|
93 | }
|
94 | |
95 |
|
96 |
|
97 | async buildEnvVars(options) {
|
98 | return process.env;
|
99 | }
|
100 | async resolveScript() {
|
101 | if (typeof this.script === 'undefined') {
|
102 | return;
|
103 | }
|
104 | const pkg = await this.e.project.requirePackageJson();
|
105 | return pkg.scripts && pkg.scripts[this.script];
|
106 | }
|
107 | async build(options) {
|
108 | this._resolvedProgram = await this.resolveProgram();
|
109 | await this.runWrapper(options);
|
110 | }
|
111 | async runWrapper(options) {
|
112 | try {
|
113 | return await this.run(options);
|
114 | }
|
115 | catch (e) {
|
116 | if (!(e instanceof errors_1.BuildCLIProgramNotFoundException)) {
|
117 | throw e;
|
118 | }
|
119 | if (this.global) {
|
120 | this.e.log.nl();
|
121 | throw new errors_1.FatalException(`${color_1.input(this.pkg)} is required for this command to work properly.`);
|
122 | }
|
123 | this.e.log.nl();
|
124 | this.e.log.info(`Looks like ${color_1.input(this.pkg)} isn't installed in this project.\n` +
|
125 | `This package is required for this command to work properly.`);
|
126 | const installed = await this.promptToInstall();
|
127 | if (!installed) {
|
128 | this.e.log.nl();
|
129 | throw new errors_1.FatalException(`${color_1.input(this.pkg)} is required for this command to work properly.`);
|
130 | }
|
131 | return this.run(options);
|
132 | }
|
133 | }
|
134 | async run(options) {
|
135 | const args = await this.buildArgs(options);
|
136 | const env = await this.buildEnvVars(options);
|
137 | try {
|
138 | await this.e.shell.run(this.resolvedProgram, args, { stdio: 'inherit', cwd: this.e.project.directory, fatalOnNotFound: false, env: utils_process_1.createProcessEnv(env) });
|
139 | }
|
140 | catch (e) {
|
141 | if (e instanceof utils_subprocess_1.SubprocessError && e.code === utils_subprocess_1.ERROR_COMMAND_NOT_FOUND) {
|
142 | throw new errors_1.BuildCLIProgramNotFoundException(`${color_1.strong(this.resolvedProgram)} command not found.`);
|
143 | }
|
144 | throw e;
|
145 | }
|
146 | }
|
147 | async resolveProgram() {
|
148 | if (typeof this.script !== 'undefined') {
|
149 | debug(`Looking for ${color_1.ancillary(this.script)} npm script.`);
|
150 | if (await this.resolveScript()) {
|
151 | debug(`Using ${color_1.ancillary(this.script)} npm script.`);
|
152 | return this.e.config.get('npmClient');
|
153 | }
|
154 | }
|
155 | return this.program;
|
156 | }
|
157 | async promptToInstall() {
|
158 | const { pkgManagerArgs } = await Promise.resolve().then(() => require('./utils/npm'));
|
159 | const [manager, ...managerArgs] = await pkgManagerArgs(this.e.config.get('npmClient'), { command: 'install', pkg: this.pkg, saveDev: true, saveExact: true });
|
160 | this.e.log.nl();
|
161 | const confirm = await this.e.prompt({
|
162 | name: 'confirm',
|
163 | message: `Install ${color_1.input(this.pkg)}?`,
|
164 | type: 'confirm',
|
165 | });
|
166 | if (!confirm) {
|
167 | this.e.log.warn(`Not installing--here's how to install manually: ${color_1.input(`${manager} ${managerArgs.join(' ')}`)}`);
|
168 | return false;
|
169 | }
|
170 | await this.e.shell.run(manager, managerArgs, { cwd: this.e.project.directory });
|
171 | return true;
|
172 | }
|
173 | }
|
174 | exports.BuildCLI = BuildCLI;
|
175 | class PkgManagerBuildCLI extends BuildCLI {
|
176 | constructor() {
|
177 | super(...arguments);
|
178 | this.global = true;
|
179 | this.script = exports.BUILD_SCRIPT;
|
180 | }
|
181 | async resolveProgram() {
|
182 | return this.program;
|
183 | }
|
184 | async buildArgs(options) {
|
185 | const { pkgManagerArgs } = await Promise.resolve().then(() => require('./utils/npm'));
|
186 | const [, ...pkgArgs] = await pkgManagerArgs(this.program, { command: 'run', script: this.script, scriptArgs: [...options['--'] || []] });
|
187 | return pkgArgs;
|
188 | }
|
189 | }
|
190 | class NpmBuildCLI extends PkgManagerBuildCLI {
|
191 | constructor() {
|
192 | super(...arguments);
|
193 | this.name = 'npm CLI';
|
194 | this.pkg = 'npm';
|
195 | this.program = 'npm';
|
196 | }
|
197 | }
|
198 | exports.NpmBuildCLI = NpmBuildCLI;
|
199 | class YarnBuildCLI extends PkgManagerBuildCLI {
|
200 | constructor() {
|
201 | super(...arguments);
|
202 | this.name = 'Yarn';
|
203 | this.pkg = 'yarn';
|
204 | this.program = 'yarn';
|
205 | }
|
206 | }
|
207 | exports.YarnBuildCLI = YarnBuildCLI;
|
208 | class BuildBeforeHook extends hooks_1.Hook {
|
209 | constructor() {
|
210 | super(...arguments);
|
211 | this.name = 'build:before';
|
212 | }
|
213 | }
|
214 | class BuildAfterHook extends hooks_1.Hook {
|
215 | constructor() {
|
216 | super(...arguments);
|
217 | this.name = 'build:after';
|
218 | }
|
219 | }
|