Skip to content

Commit 80c9aac

Browse files
Allow prepare for Android without ANDROID_HOME (#2904)
* Allow prepare for Android without ANDROID_HOME Allow preparing Android project without the requirement to have ANDROID_HOME set. The change is in the required services, which should work without ANDROID_HOME in some cases. However the commands should not allow this, so move the validation in the commands. * Fix unable to uninstall application on macOS Update ios-device-lib where a fix for uninstalling application on macOS was not working. Update common lib where the following fixes are applied: * Fix `tns devices` not showing attached iOS devices. * Do not call uninstall of application when it is not installed - this produces some confusing warnings. * Fix execution of livesync hooks when there are no node_modules In case `node_modules` are deleted from the project and `tns run <platform>` or `tns debug <platform>` is executed, the livesync hook fails as the package that's required in it is not installed. In order to fix this, extract the logic of the liveSync method in a separate method and decorate it with the hook. In the public method make sure all dependencies are installed and call the private method. This way the hook will be executed correctly.
1 parent e3ce4e6 commit 80c9aac

21 files changed

+192
-93
lines changed

lib/android-tools-info.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,12 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
317317
@cache()
318318
private getInstalledTargets(): string[] {
319319
let installedTargets: string[] = [];
320-
const pathToInstalledTargets = path.join(this.androidHome, "platforms");
321-
if (this.$fs.exists(pathToInstalledTargets)) {
322-
installedTargets = this.$fs.readDirectory(pathToInstalledTargets);
320+
if (this.androidHome) {
321+
const pathToInstalledTargets = path.join(this.androidHome, "platforms");
322+
if (this.$fs.exists(pathToInstalledTargets)) {
323+
installedTargets = this.$fs.readDirectory(pathToInstalledTargets);
324+
}
323325
}
324-
325326
this.$logger.trace("Installed Android Targets are: ", installedTargets);
326327

327328
return installedTargets;

lib/commands/add-platform.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export class AddPlatformCommand implements ICommand {
44
constructor(private $options: IOptions,
55
private $platformService: IPlatformService,
66
private $projectData: IProjectData,
7+
private $platformsData: IPlatformsData,
78
private $errors: IErrors) {
89
this.$projectData.initializeProjectData();
910
}
@@ -17,7 +18,12 @@ export class AddPlatformCommand implements ICommand {
1718
this.$errors.fail("No platform specified. Please specify a platform to add");
1819
}
1920

20-
_.each(args, arg => this.$platformService.validatePlatform(arg, this.$projectData));
21+
for (let arg of args) {
22+
this.$platformService.validatePlatform(arg, this.$projectData);
23+
const platformData = this.$platformsData.getPlatformData(arg, this.$projectData);
24+
const platformProjectService = platformData.platformProjectService;
25+
await platformProjectService.validate(this.$projectData);
26+
}
2127

2228
return true;
2329
}

lib/commands/build.ts

+5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ export class BuildAndroidCommand extends BuildCommandBase implements ICommand {
8484
if (this.$options.release && (!this.$options.keyStorePath || !this.$options.keyStorePassword || !this.$options.keyStoreAlias || !this.$options.keyStoreAliasPassword)) {
8585
this.$errors.fail("When producing a release build, you need to specify all --key-store-* options.");
8686
}
87+
88+
const platformData = this.$platformsData.getPlatformData(this.$devicePlatformsConstants.Android, this.$projectData);
89+
const platformProjectService = platformData.platformProjectService;
90+
await platformProjectService.validate(this.$projectData);
91+
8792
return args.length === 0 && await this.$platformService.validateOptions(this.$options.provision, this.$projectData, this.$platformsData.availablePlatforms.Android);
8893
}
8994
}

lib/commands/clean-app.ts

+34-26
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,64 @@
1-
export class CleanAppCommandBase {
1+
export class CleanAppCommandBase implements ICommand {
2+
public allowedParameters: ICommandParameter[] = [];
3+
4+
protected platform: string;
5+
26
constructor(protected $options: IOptions,
37
protected $projectData: IProjectData,
4-
protected $platformService: IPlatformService) {
8+
protected $platformService: IPlatformService,
9+
protected $errors: IErrors,
10+
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
11+
protected $platformsData: IPlatformsData) {
12+
513
this.$projectData.initializeProjectData();
614
}
715

816
public async execute(args: string[]): Promise<void> {
9-
let platform = args[0].toLowerCase();
1017
const appFilesUpdaterOptions: IAppFilesUpdaterOptions = { bundle: this.$options.bundle, release: this.$options.release };
11-
return this.$platformService.cleanDestinationApp(platform, appFilesUpdaterOptions, this.$options.platformTemplate, this.$projectData, this.$options);
18+
return this.$platformService.cleanDestinationApp(this.platform.toLowerCase(), appFilesUpdaterOptions, this.$options.platformTemplate, this.$projectData, this.$options);
19+
}
20+
21+
public async canExecute(args: string[]): Promise<boolean> {
22+
if (!this.$platformService.isPlatformSupportedForOS(this.platform, this.$projectData)) {
23+
this.$errors.fail(`Applications for platform ${this.platform} can not be built on this OS`);
24+
}
25+
26+
let platformData = this.$platformsData.getPlatformData(this.platform, this.$projectData);
27+
let platformProjectService = platformData.platformProjectService;
28+
await platformProjectService.validate(this.$projectData);
29+
return true;
1230
}
1331
}
1432

1533
export class CleanAppIosCommand extends CleanAppCommandBase implements ICommand {
1634
constructor(protected $options: IOptions,
17-
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
18-
private $platformsData: IPlatformsData,
19-
private $errors: IErrors,
35+
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
36+
protected $platformsData: IPlatformsData,
37+
protected $errors: IErrors,
2038
$platformService: IPlatformService,
2139
$projectData: IProjectData) {
22-
super($options, $projectData, $platformService);
40+
super($options, $projectData, $platformService, $errors, $devicePlatformsConstants, $platformsData);
2341
}
2442

25-
public allowedParameters: ICommandParameter[] = [];
26-
27-
public async execute(args: string[]): Promise<void> {
28-
if (!this.$platformService.isPlatformSupportedForOS(this.$devicePlatformsConstants.iOS, this.$projectData)) {
29-
this.$errors.fail(`Applications for platform ${this.$devicePlatformsConstants.iOS} can not be built on this OS`);
30-
}
31-
return super.execute([this.$platformsData.availablePlatforms.iOS]);
43+
protected get platform(): string {
44+
return this.$devicePlatformsConstants.iOS;
3245
}
3346
}
3447

3548
$injector.registerCommand("clean-app|ios", CleanAppIosCommand);
3649

3750
export class CleanAppAndroidCommand extends CleanAppCommandBase implements ICommand {
38-
public allowedParameters: ICommandParameter[] = [];
39-
4051
constructor(protected $options: IOptions,
41-
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
42-
private $platformsData: IPlatformsData,
43-
private $errors: IErrors,
52+
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
53+
protected $platformsData: IPlatformsData,
54+
protected $errors: IErrors,
4455
$platformService: IPlatformService,
4556
$projectData: IProjectData) {
46-
super($options, $projectData, $platformService);
57+
super($options, $projectData, $platformService, $errors, $devicePlatformsConstants, $platformsData);
4758
}
4859

49-
public async execute(args: string[]): Promise<void> {
50-
if (!this.$platformService.isPlatformSupportedForOS(this.$devicePlatformsConstants.iOS, this.$projectData)) {
51-
this.$errors.fail(`Applications for platform ${this.$devicePlatformsConstants.iOS} can not be built on this OS`);
52-
}
53-
return super.execute([this.$platformsData.availablePlatforms.Android]);
60+
protected get platform(): string {
61+
return this.$devicePlatformsConstants.Android;
5462
}
5563
}
5664

lib/commands/debug.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
protected $options: IOptions,
1111
protected $platformsData: IPlatformsData,
1212
protected $logger: ILogger,
13+
protected $errors: IErrors,
1314
private $debugLiveSyncService: IDebugLiveSyncService,
1415
private $config: IConfiguration) {
1516
this.$projectData.initializeProjectData();
@@ -73,6 +74,14 @@
7374
}
7475

7576
public async canExecute(args: string[]): Promise<boolean> {
77+
if (!this.$platformService.isPlatformSupportedForOS(this.platform, this.$projectData)) {
78+
this.$errors.fail(`Applications for platform ${this.platform} can not be built on this OS`);
79+
}
80+
81+
const platformData = this.$platformsData.getPlatformData(this.platform, this.$projectData);
82+
const platformProjectService = platformData.platformProjectService;
83+
await platformProjectService.validate(this.$projectData);
84+
7685
await this.$devicesService.initialize({
7786
platform: this.platform,
7887
deviceId: this.$options.device,
@@ -97,7 +106,7 @@
97106
}
98107

99108
export class DebugIOSCommand extends DebugPlatformCommand {
100-
constructor(private $errors: IErrors,
109+
constructor(protected $errors: IErrors,
101110
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
102111
$logger: ILogger,
103112
$iOSDebugService: IPlatformDebugService,
@@ -110,7 +119,8 @@ export class DebugIOSCommand extends DebugPlatformCommand {
110119
$platformsData: IPlatformsData,
111120
$iosDeviceOperations: IIOSDeviceOperations,
112121
$debugLiveSyncService: IDebugLiveSyncService) {
113-
super($iOSDebugService, $devicesService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger, $debugLiveSyncService, $config);
122+
super($iOSDebugService, $devicesService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger,
123+
$errors, $debugLiveSyncService, $config);
114124
// Do not dispose ios-device-lib, so the process will remain alive and the debug application (NativeScript Inspector or Chrome DevTools) will be able to connect to the socket.
115125
// In case we dispose ios-device-lib, the socket will be closed and the code will fail when the debug application tries to read/send data to device socket.
116126
// That's why the `$ tns debug ios --justlaunch` command will not release the terminal.
@@ -132,7 +142,7 @@ export class DebugIOSCommand extends DebugPlatformCommand {
132142
$injector.registerCommand("debug|ios", DebugIOSCommand);
133143

134144
export class DebugAndroidCommand extends DebugPlatformCommand {
135-
constructor(private $errors: IErrors,
145+
constructor(protected $errors: IErrors,
136146
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
137147
$logger: ILogger,
138148
$androidDebugService: IPlatformDebugService,
@@ -144,14 +154,11 @@ export class DebugAndroidCommand extends DebugPlatformCommand {
144154
$projectData: IProjectData,
145155
$platformsData: IPlatformsData,
146156
$debugLiveSyncService: IDebugLiveSyncService) {
147-
super($androidDebugService, $devicesService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger, $debugLiveSyncService, $config);
157+
super($androidDebugService, $devicesService, $debugDataService, $platformService, $projectData, $options, $platformsData, $logger,
158+
$errors, $debugLiveSyncService, $config);
148159
}
149160

150161
public async canExecute(args: string[]): Promise<boolean> {
151-
if (!this.$platformService.isPlatformSupportedForOS(this.$devicePlatformsConstants.Android, this.$projectData)) {
152-
this.$errors.fail(`Applications for platform ${this.$devicePlatformsConstants.Android} can not be built on this OS`);
153-
}
154-
155162
return await super.canExecute(args) && await this.$platformService.validateOptions(this.$options.provision, this.$projectData, this.$platformsData.availablePlatforms.Android);
156163
}
157164

lib/commands/deploy.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ export class DeployOnDeviceCommand implements ICommand {
66
private $options: IOptions,
77
private $projectData: IProjectData,
88
private $errors: IErrors,
9-
private $mobileHelper: Mobile.IMobileHelper) {
9+
private $mobileHelper: Mobile.IMobileHelper,
10+
private $platformsData: IPlatformsData) {
1011
this.$projectData.initializeProjectData();
1112
}
1213

@@ -43,6 +44,10 @@ export class DeployOnDeviceCommand implements ICommand {
4344
this.$errors.fail("When producing a release build, you need to specify all --key-store-* options.");
4445
}
4546

47+
const platformData = this.$platformsData.getPlatformData(args[0], this.$projectData);
48+
const platformProjectService = platformData.platformProjectService;
49+
await platformProjectService.validate(this.$projectData);
50+
4651
return this.$platformService.validateOptions(this.$options.provision, this.$projectData, args[0]);
4752
}
4853
}

lib/commands/install.ts

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export class InstallCommand implements ICommand {
3131
const frameworkPackageData = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName);
3232
if (frameworkPackageData && frameworkPackageData.version) {
3333
try {
34+
const platformProjectService = platformData.platformProjectService;
35+
await platformProjectService.validate(this.$projectData);
36+
3437
await this.$platformService.addPlatforms([`${platform}@${frameworkPackageData.version}`], this.$options.platformTemplate, this.$projectData, this.$options, this.$options.frameworkPath);
3538
} catch (err) {
3639
error = `${error}${EOL}${err}`;

lib/commands/platform-clean.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export class CleanCommand implements ICommand {
44
constructor(private $options: IOptions,
55
private $projectData: IProjectData,
66
private $platformService: IPlatformService,
7-
private $errors: IErrors) {
7+
private $errors: IErrors,
8+
private $platformsData: IPlatformsData) {
89
this.$projectData.initializeProjectData();
910
}
1011

@@ -17,7 +18,13 @@ export class CleanCommand implements ICommand {
1718
this.$errors.fail("No platform specified. Please specify a platform to clean");
1819
}
1920

20-
_.each(args, arg => this.$platformService.validatePlatformInstalled(arg, this.$projectData));
21+
for (let platform of args) {
22+
this.$platformService.validatePlatformInstalled(platform, this.$projectData);
23+
24+
const platformData = this.$platformsData.getPlatformData(platform, this.$projectData);
25+
const platformProjectService = platformData.platformProjectService;
26+
await platformProjectService.validate(this.$projectData);
27+
}
2128

2229
return true;
2330
}

lib/commands/prepare.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export class PrepareCommand implements ICommand {
44
constructor(private $options: IOptions,
55
private $platformService: IPlatformService,
66
private $projectData: IProjectData,
7-
private $platformCommandParameter: ICommandParameter) {
7+
private $platformCommandParameter: ICommandParameter,
8+
private $platformsData: IPlatformsData) {
89
this.$projectData.initializeProjectData();
910
}
1011

@@ -14,7 +15,15 @@ export class PrepareCommand implements ICommand {
1415
}
1516

1617
public async canExecute(args: string[]): Promise<boolean> {
17-
return await this.$platformCommandParameter.validate(args[0]) && await this.$platformService.validateOptions(this.$options.provision, this.$projectData, args[0]);
18+
const platform = args[0];
19+
const result = await this.$platformCommandParameter.validate(platform) && await this.$platformService.validateOptions(this.$options.provision, this.$projectData, platform);
20+
if (result) {
21+
const platformData = this.$platformsData.getPlatformData(platform, this.$projectData);
22+
const platformProjectService = platformData.platformProjectService;
23+
await platformProjectService.validate(this.$projectData);
24+
}
25+
26+
return result;
1827
}
1928
}
2029

lib/commands/remove-platform.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ export class RemovePlatformCommand implements ICommand {
33

44
constructor(private $platformService: IPlatformService,
55
private $projectData: IProjectData,
6-
private $errors: IErrors) {
7-
this.$projectData.initializeProjectData();
8-
}
6+
private $errors: IErrors,
7+
private $platformsData: IPlatformsData) {
8+
this.$projectData.initializeProjectData();
9+
}
910

1011
public execute(args: string[]): Promise<void> {
1112
return this.$platformService.removePlatforms(args, this.$projectData);
@@ -16,7 +17,12 @@ export class RemovePlatformCommand implements ICommand {
1617
this.$errors.fail("No platform specified. Please specify a platform to remove");
1718
}
1819

19-
_.each(args, arg => this.$platformService.validatePlatformInstalled(arg, this.$projectData));
20+
for (let platform of args) {
21+
this.$platformService.validatePlatformInstalled(platform, this.$projectData);
22+
const platformData = this.$platformsData.getPlatformData(platform, this.$projectData);
23+
const platformProjectService = platformData.platformProjectService;
24+
await platformProjectService.validate(this.$projectData);
25+
}
2026

2127
return true;
2228
}

lib/commands/run.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export class RunCommandBase implements ICommand {
1313
private $devicesService: Mobile.IDevicesService,
1414
private $hostInfo: IHostInfo,
1515
private $iosDeviceOperations: IIOSDeviceOperations,
16-
private $mobileHelper: Mobile.IMobileHelper) {
16+
private $mobileHelper: Mobile.IMobileHelper,
17+
protected $platformsData: IPlatformsData) {
1718
}
1819

1920
public allowedParameters: ICommandParameter[] = [];
@@ -31,6 +32,13 @@ export class RunCommandBase implements ICommand {
3132
this.platform = this.$devicePlatformsConstants.Android;
3233
}
3334

35+
const availablePlatforms = this.platform ? [this.platform] : this.$platformsData.availablePlatforms;
36+
for (let platform of availablePlatforms) {
37+
const platformData = this.$platformsData.getPlatformData(platform, this.$projectData);
38+
const platformProjectService = platformData.platformProjectService;
39+
await platformProjectService.validate(this.$projectData);
40+
}
41+
3442
return true;
3543
}
3644

@@ -46,6 +54,7 @@ export class RunCommandBase implements ICommand {
4654
skipDeviceDetectionInterval: true,
4755
skipInferPlatform: !this.platform
4856
});
57+
4958
await this.$devicesService.detectCurrentlyAttachedDevices();
5059

5160
const devices = this.$devicesService.getDeviceInstances();
@@ -118,7 +127,7 @@ export class RunIosCommand extends RunCommandBase implements ICommand {
118127
}
119128

120129
constructor($platformService: IPlatformService,
121-
private $platformsData: IPlatformsData,
130+
protected $platformsData: IPlatformsData,
122131
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
123132
protected $errors: IErrors,
124133
$liveSyncService: ILiveSyncService,
@@ -129,7 +138,8 @@ export class RunIosCommand extends RunCommandBase implements ICommand {
129138
$hostInfo: IHostInfo,
130139
$iosDeviceOperations: IIOSDeviceOperations,
131140
$mobileHelper: Mobile.IMobileHelper) {
132-
super($platformService, $liveSyncService, $projectData, $options, $emulatorPlatformService, $devicePlatformsConstants, $errors, $devicesService, $hostInfo, $iosDeviceOperations, $mobileHelper);
141+
super($platformService, $liveSyncService, $projectData, $options, $emulatorPlatformService, $devicePlatformsConstants, $errors,
142+
$devicesService, $hostInfo, $iosDeviceOperations, $mobileHelper, $platformsData);
133143
}
134144

135145
public async execute(args: string[]): Promise<void> {
@@ -154,7 +164,7 @@ export class RunAndroidCommand extends RunCommandBase implements ICommand {
154164
}
155165

156166
constructor($platformService: IPlatformService,
157-
private $platformsData: IPlatformsData,
167+
protected $platformsData: IPlatformsData,
158168
protected $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
159169
protected $errors: IErrors,
160170
$liveSyncService: ILiveSyncService,
@@ -165,7 +175,8 @@ export class RunAndroidCommand extends RunCommandBase implements ICommand {
165175
$hostInfo: IHostInfo,
166176
$iosDeviceOperations: IIOSDeviceOperations,
167177
$mobileHelper: Mobile.IMobileHelper) {
168-
super($platformService, $liveSyncService, $projectData, $options, $emulatorPlatformService, $devicePlatformsConstants, $errors, $devicesService, $hostInfo, $iosDeviceOperations, $mobileHelper);
178+
super($platformService, $liveSyncService, $projectData, $options, $emulatorPlatformService, $devicePlatformsConstants, $errors,
179+
$devicesService, $hostInfo, $iosDeviceOperations, $mobileHelper, $platformsData);
169180
}
170181

171182
public async execute(args: string[]): Promise<void> {

0 commit comments

Comments
 (0)