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