Skip to content

Commit d2e0c81

Browse files
committed
fix(cordova): add port forwarding for --consolelogs
1 parent 5db46d5 commit d2e0c81

File tree

14 files changed

+210
-123
lines changed

14 files changed

+210
-123
lines changed

packages/ionic/src/commands/build.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Footnote } from '@ionic/cli-framework';
22

33
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, CommandPreRun } from '../definitions';
4-
import { COMMON_BUILD_COMMAND_OPTIONS, build } from '../lib/build';
4+
import { COMMON_BUILD_COMMAND_OPTIONS } from '../lib/build';
55
import { input } from '../lib/color';
66
import { Command } from '../lib/command';
7-
import { FatalException } from '../lib/errors';
7+
import { FatalException, RunnerException } from '../lib/errors';
88

99
export class BuildCommand extends Command implements CommandPreRun {
1010
async getMetadata(): Promise<CommandMetadata> {
@@ -55,7 +55,17 @@ export class BuildCommand extends Command implements CommandPreRun {
5555
throw new FatalException(`Cannot run ${input('ionic build')} outside a project directory.`);
5656
}
5757

58-
// TODO: use runner directly
59-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, options);
58+
try {
59+
const runner = await this.project.requireBuildRunner();
60+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, options);
61+
62+
await runner.run(runnerOpts);
63+
} catch (e) {
64+
if (e instanceof RunnerException) {
65+
throw new FatalException(e.message);
66+
}
67+
68+
throw e;
69+
}
6070
}
6171
}

packages/ionic/src/commands/capacitor/run.ts

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import * as lodash from 'lodash';
55
import * as path from 'path';
66

77
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, CommandPreRun } from '../../definitions';
8-
import { build } from '../../lib/build';
98
import { input, strong, weak } from '../../lib/color';
10-
import { FatalException } from '../../lib/errors';
9+
import { FatalException, RunnerException } from '../../lib/errors';
1110
import { CAPACITOR_CONFIG_FILE, CapacitorConfig } from '../../lib/integrations/capacitor/config';
1211
import { generateOptionsForCapacitorBuild } from '../../lib/integrations/capacitor/utils';
13-
import { COMMON_SERVE_COMMAND_OPTIONS, LOCAL_ADDRESSES, serve } from '../../lib/serve';
12+
import { COMMON_SERVE_COMMAND_OPTIONS, LOCAL_ADDRESSES } from '../../lib/serve';
1413

1514
import { CapacitorCommand } from './base';
1615

@@ -132,39 +131,23 @@ For Android and iOS, you can setup Remote Debugging on your device with browser
132131

133132
async run(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
134133
if (!this.project) {
135-
throw new FatalException(`Cannot run ${input('ionic cordova run/emulate')} outside a project directory.`);
134+
throw new FatalException(`Cannot run ${input('ionic capacitor run/emulate')} outside a project directory.`);
136135
}
137136

138137
const [ platform ] = inputs;
139138

140-
if (options['livereload']) {
141-
let livereloadUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
142-
143-
if (!livereloadUrl) {
144-
// TODO: use runner directly
145-
const details = await serve({ flags: this.env.flags, config: this.env.config, log: this.env.log, prompt: this.env.prompt, shell: this.env.shell, project: this.project }, inputs, generateOptionsForCapacitorBuild(inputs, options));
146-
147-
if (details.externallyAccessible === false) {
148-
const extra = LOCAL_ADDRESSES.includes(details.externalAddress) ? '\nEnsure you have proper port forwarding setup from your device to your computer.' : '';
149-
this.env.log.warn(`Your device or emulator may not be able to access ${strong(details.externalAddress)}.${extra}\n\n`);
150-
}
151-
152-
livereloadUrl = `${details.protocol || 'http'}://${details.externalAddress}:${details.port}`;
139+
try {
140+
if (options['livereload']) {
141+
await this.runServe(inputs, options);
142+
} else {
143+
await this.runBuild(inputs, options);
153144
}
154-
155-
const conf = new CapacitorConfig(path.resolve(this.project.directory, CAPACITOR_CONFIG_FILE));
156-
157-
onBeforeExit(async () => {
158-
conf.resetServerUrl();
159-
});
160-
161-
conf.setServerUrl(livereloadUrl);
162-
163-
} else {
164-
if (options['build']) {
165-
// TODO: use runner directly
166-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, generateOptionsForCapacitorBuild(inputs, options));
145+
} catch (e) {
146+
if (e instanceof RunnerException) {
147+
throw new FatalException(e.message);
167148
}
149+
150+
throw e;
168151
}
169152

170153
// copy assets and capacitor.config.json into place
@@ -191,4 +174,54 @@ For Android and iOS, you can setup Remote Debugging on your device with browser
191174
await sleepForever();
192175
}
193176
}
177+
178+
async runServe(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
179+
if (!this.project) {
180+
throw new FatalException(`Cannot run ${input('ionic capacitor run/emulate')} outside a project directory.`);
181+
}
182+
183+
const runner = await this.project.requireServeRunner();
184+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, generateOptionsForCapacitorBuild(inputs, options));
185+
186+
let serverUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
187+
188+
if (!serverUrl) {
189+
const details = await runner.run(runnerOpts);
190+
191+
if (details.externallyAccessible === false) {
192+
const extra = LOCAL_ADDRESSES.includes(details.externalAddress) ? '\nEnsure you have proper port forwarding setup from your device to your computer.' : '';
193+
this.env.log.warn(`Your device or emulator may not be able to access ${strong(details.externalAddress)}.${extra}\n\n`);
194+
}
195+
196+
serverUrl = `${details.protocol || 'http'}://${details.externalAddress}:${details.port}`;
197+
}
198+
199+
const conf = new CapacitorConfig(path.resolve(this.project.directory, CAPACITOR_CONFIG_FILE));
200+
201+
onBeforeExit(async () => {
202+
conf.resetServerUrl();
203+
});
204+
205+
conf.setServerUrl(serverUrl);
206+
}
207+
208+
async runBuild(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
209+
if (!this.project) {
210+
throw new FatalException(`Cannot run ${input('ionic capacitor run/emulate')} outside a project directory.`);
211+
}
212+
213+
if (options['build']) {
214+
try {
215+
const runner = await this.project.requireBuildRunner();
216+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, generateOptionsForCapacitorBuild(inputs, options));
217+
await runner.run(runnerOpts);
218+
} catch (e) {
219+
if (e instanceof RunnerException) {
220+
throw new FatalException(e.message);
221+
}
222+
223+
throw e;
224+
}
225+
}
226+
}
194227
}

packages/ionic/src/commands/cordova/build.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { CommandMetadataOption, Footnote, validators } from '@ionic/cli-framework';
22

33
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandPreRun } from '../../definitions';
4-
import { build } from '../../lib/build';
54
import { input, strong } from '../../lib/color';
6-
import { FatalException } from '../../lib/errors';
5+
import { FatalException, RunnerException } from '../../lib/errors';
76
import { filterArgumentsForCordova, generateOptionsForCordovaBuild } from '../../lib/integrations/cordova/utils';
87

98
import { CORDOVA_BUILD_EXAMPLE_COMMANDS, CORDOVA_COMPILE_OPTIONS, CordovaCommand } from './base';
@@ -89,8 +88,17 @@ The Cordova CLI requires a separator for platform-specific arguments for Android
8988
}
9089

9190
if (options.build) {
92-
// TODO: use runner directly
93-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
91+
try {
92+
const runner = await this.project.requireBuildRunner();
93+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
94+
await runner.run(runnerOpts);
95+
} catch (e) {
96+
if (e instanceof RunnerException) {
97+
throw new FatalException(e.message);
98+
}
99+
100+
throw e;
101+
}
94102
}
95103

96104
const cordovaArgs = filterArgumentsForCordova(metadata, options);

packages/ionic/src/commands/cordova/prepare.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { CommandMetadataOption, Footnote } from '@ionic/cli-framework';
22

33
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandPreRun } from '../../definitions';
4-
import { build } from '../../lib/build';
54
import { input, strong } from '../../lib/color';
6-
import { FatalException } from '../../lib/errors';
5+
import { FatalException, RunnerException } from '../../lib/errors';
76
import { filterArgumentsForCordova, generateOptionsForCordovaBuild } from '../../lib/integrations/cordova/utils';
87

98
import { CordovaCommand } from './base';
@@ -98,8 +97,17 @@ You may wish to use ${input('ionic cordova prepare')} if you run your project wi
9897
const buildOptions = generateOptionsForCordovaBuild(metadata, inputs, options);
9998

10099
if (buildOptions['platform']) {
101-
// TODO: use runner directly
102-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, buildOptions);
100+
try {
101+
const runner = await this.project.requireBuildRunner();
102+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, buildOptions);
103+
await runner.run(runnerOpts);
104+
} catch (e) {
105+
if (e instanceof RunnerException) {
106+
throw new FatalException(e.message);
107+
}
108+
109+
throw e;
110+
}
103111
} else {
104112
this.env.log.warn(
105113
`Cannot perform Ionic build without ${input('platform')}. Falling back to just ${input('cordova prepare')}.\n` +

packages/ionic/src/commands/cordova/run.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ import { Footnote, MetadataGroup } from '@ionic/cli-framework';
22
import { onBeforeExit, sleepForever } from '@ionic/utils-process';
33
import * as Debug from 'debug';
44
import * as lodash from 'lodash';
5-
import * as url from 'url';
65

7-
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, CommandPreRun, IShellRunOptions } from '../../definitions';
8-
import { COMMON_BUILD_COMMAND_OPTIONS, build } from '../../lib/build';
6+
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, CommandPreRun, IShellRunOptions, ServeDetails } from '../../definitions';
7+
import { COMMON_BUILD_COMMAND_OPTIONS } from '../../lib/build';
98
import { input, strong, weak } from '../../lib/color';
10-
import { FatalException } from '../../lib/errors';
9+
import { FatalException, RunnerException } from '../../lib/errors';
1110
import { loadConfigXml } from '../../lib/integrations/cordova/config';
1211
import { getPackagePath } from '../../lib/integrations/cordova/project';
1312
import { filterArgumentsForCordova, generateOptionsForCordovaBuild } from '../../lib/integrations/cordova/utils';
1413
import { SUPPORTED_PLATFORMS, checkNativeRun, createNativeRunArgs, createNativeRunListArgs, getNativeTargets, runNativeRun } from '../../lib/native-run';
15-
import { COMMON_SERVE_COMMAND_OPTIONS, LOCAL_ADDRESSES, serve } from '../../lib/serve';
14+
import { COMMON_SERVE_COMMAND_OPTIONS, LOCAL_ADDRESSES } from '../../lib/serve';
1615
import { createPrefixedWriteStream } from '../../lib/utils/logger';
1716

1817
import { CORDOVA_BUILD_EXAMPLE_COMMANDS, CORDOVA_RUN_OPTIONS, CordovaCommand } from './base';
@@ -233,49 +232,64 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
233232
}
234233

235234
async run(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
236-
if (options['livereload']) {
237-
await this.runServeDeploy(inputs, options);
238-
} else {
239-
await this.runBuildDeploy(inputs, options);
235+
try {
236+
if (options['livereload']) {
237+
await this.runServeDeploy(inputs, options);
238+
} else {
239+
await this.runBuildDeploy(inputs, options);
240+
}
241+
} catch (e) {
242+
if (e instanceof RunnerException) {
243+
throw new FatalException(e.message);
244+
}
245+
246+
throw e;
240247
}
241248
}
242249

243-
protected async runServeDeploy(inputs: CommandLineInputs, options: CommandLineOptions) {
250+
protected async runServeDeploy(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
244251
const conf = await loadConfigXml(this.integration);
245252
const metadata = await this.getMetadata();
246253

247254
if (!this.project) {
248255
throw new FatalException(`Cannot run ${input(`ionic cordova ${metadata.name}`)} outside a project directory.`);
249256
}
250257

251-
let livereloadUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
258+
const runner = await this.project.requireServeRunner();
259+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
252260

253-
if (!livereloadUrl) {
254-
// TODO: use runner directly
255-
const details = await serve({ flags: this.env.flags, config: this.env.config, log: this.env.log, prompt: this.env.prompt, shell: this.env.shell, project: this.project }, inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
261+
/**
262+
* With the --livereload-url option, this command won't perform a serve. If
263+
* this is the case, details will be undefined.
264+
*/
265+
let details: ServeDetails | undefined;
266+
let serverUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
267+
268+
if (!serverUrl) {
269+
details = await runner.run(runnerOpts);
256270

257271
if (details.externallyAccessible === false && !options['native-run']) {
258272
const extra = LOCAL_ADDRESSES.includes(details.externalAddress) ? '\nEnsure you have proper port forwarding setup from your device to your computer.' : '';
259273
this.env.log.warn(`Your device or emulator may not be able to access ${strong(details.externalAddress)}.${extra}\n\n`);
260274
}
261275

262-
livereloadUrl = `${details.protocol || 'http'}://${options['native-run'] ? details.localAddress : details.externalAddress}:${details.port}`;
276+
serverUrl = `${details.protocol || 'http'}://${details.externalAddress}:${details.port}`;
263277
}
264278

265279
onBeforeExit(async () => {
266280
conf.resetContentSrc();
267281
await conf.save();
268282
});
269283

270-
conf.writeContentSrc(livereloadUrl);
284+
conf.writeContentSrc(serverUrl);
271285
await conf.save();
272286

273287
const cordovalogws = createPrefixedWriteStream(this.env.log, weak(`[cordova]`));
274288

275289
if (options['native-run']) {
276290
const [ platform ] = inputs;
277291
const packagePath = await getPackagePath(conf.getProjectInfo().name, platform, !options['device']);
278-
const { port: portForward } = url.parse(livereloadUrl);
292+
const forwardedPorts = details ? runner.getUsedPorts(runnerOpts, details) : [];
279293

280294
const buildOpts: IShellRunOptions = { stream: cordovalogws };
281295
// ignore very verbose compiler output unless --verbose (still pipe stderr)
@@ -284,14 +298,14 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
284298
}
285299

286300
await this.runCordova(filterArgumentsForCordova({ ...metadata, name: 'build' }, options), buildOpts);
287-
await this.runNativeRun(createNativeRunArgs({ packagePath, platform, portForward }, options));
301+
await this.runNativeRun(createNativeRunArgs({ packagePath, platform, forwardedPorts }, options));
288302
} else {
289303
await this.runCordova(filterArgumentsForCordova(metadata, options), { stream: cordovalogws });
290304
await sleepForever();
291305
}
292306
}
293307

294-
protected async runBuildDeploy(inputs: CommandLineInputs, options: CommandLineOptions) {
308+
protected async runBuildDeploy(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
295309
const conf = await loadConfigXml(this.integration);
296310
const metadata = await this.getMetadata();
297311

@@ -300,8 +314,17 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
300314
}
301315

302316
if (options.build) {
303-
// TODO: use runner directly
304-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
317+
try {
318+
const runner = await this.project.requireBuildRunner();
319+
const runnerOpts = runner.createOptionsFromCommandLine(inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
320+
await runner.run(runnerOpts);
321+
} catch (e) {
322+
if (e instanceof RunnerException) {
323+
throw new FatalException(e.message);
324+
}
325+
326+
throw e;
327+
}
305328
}
306329

307330
if (options['native-run']) {

packages/ionic/src/commands/monitoring/syncmaps.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import * as path from 'path';
55

66
import { APIResponseSuccess, CommandLineInputs, CommandLineOptions, CommandMetadata } from '../../definitions';
77
import { isSuperAgentError } from '../../guards';
8-
import { build } from '../../lib/build';
98
import { input, strong, weak } from '../../lib/color';
109
import { Command } from '../../lib/command';
1110
import { FatalException } from '../../lib/errors';
@@ -64,8 +63,9 @@ By default, ${input('ionic monitoring syncmaps')} will upload the sourcemap file
6463
let sourcemapsExist = await pathExists(sourcemapsDir);
6564

6665
if (doBuild || !sourcemapsExist) {
67-
// TODO: use runner directly
68-
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, [], { _: [], prod: true });
66+
const runner = await this.project.requireBuildRunner();
67+
const runnerOpts = runner.createOptionsFromCommandLine([], { _: [], prod: true });
68+
await runner.run(runnerOpts);
6969
}
7070

7171
sourcemapsExist = await pathExists(sourcemapsDir);

0 commit comments

Comments
 (0)