Skip to content

Commit f05fd84

Browse files
committed
Merge pull request #1705 from NativeScript/kerezov/xcproj-doctor
Add xcproj check to tns doctor
2 parents 91132c3 + 1ee3585 commit f05fd84

File tree

7 files changed

+135
-33
lines changed

7 files changed

+135
-33
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ sudo ruby -e "$(curl -fsSL https://raw.githubusercontent.com/NativeScript/native
155155
* [Xcode command-line tools][12]
156156
* [xcodeproj ruby gem][13]
157157
* (Optional) [CocoaPods 0.38.2][CocoaPods 0.38.2]
158+
* (Optional) [Xcproj][Xcproj]
158159
* For Android development
159160
* [JDK 8][JDK 8] or a later stable official release
160161
* [Android SDK 22][Android SDK 22] or a later stable official release
@@ -608,6 +609,7 @@ This software is licensed under the Apache 2.0 license, quoted <a href="LICENSE"
608609
[Android SDK 22]: http://developer.android.com/sdk/index.html
609610
[Genymotion]: https://www.genymotion.com/#!/
610611
[CocoaPods 0.38.2]: https://guides.cocoapods.org/using/getting-started.html#getting-started
611-
[Android SDK Build-tools 22.0.0]: http://developer.android.com/sdk/index.html
612+
[Xcproj]: https://github.com/0xced/xcproj#installation
613+
[Android SDK Build-tools 23.0.0]: http://developer.android.com/sdk/index.html
612614
[Local Maven repository for Support Libraries]: http://developer.android.com/sdk/index.html
613615
![](https://ga-beacon.appspot.com/UA-111455-24/nativescript/nativescript-cli?pixel)

lib/bootstrap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ $injector.requireCommand("plugin|add", "./commands/plugin/add-plugin");
8383
$injector.requireCommand("plugin|remove", "./commands/plugin/remove-plugin");
8484

8585
$injector.require("doctorService", "./services/doctor-service");
86+
$injector.require("xcprojService", "./services/xcproj-service");
8687
$injector.require("versionsService", "./services/versions-service");
8788
$injector.requireCommand("install", "./commands/install");
8889

lib/declarations.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,43 @@ interface IProjectNameService {
320320
ensureValidName(projectName: string, validateOptions?: { force: boolean }): IFuture<string>;
321321
}
322322

323+
/**
324+
* Designed for getting information about xcproj.
325+
*/
326+
interface IXcprojService {
327+
/**
328+
* Checks whether the system needs xcproj to execute ios builds successfully.
329+
* In case the system does need xcproj but does not have it, prints an error message.
330+
* @param {boolean} whether to fail with error message or not
331+
* @return {IFuture<boolean>} whether an error occurred or not.
332+
*/
333+
verifyXcproj(shouldFail: boolean): IFuture<boolean>;
334+
/**
335+
* Collects information about xcproj.
336+
* @return {IFuture<XcprojInfo>} collected info about xcproj.
337+
*/
338+
getXcprojInfo(): IFuture<IXcprojInfo>;
339+
}
340+
341+
/**
342+
* Describes information about xcproj brew formula.
343+
*/
344+
interface IXcprojInfo {
345+
/**
346+
* determines whether the system needs xcproj to execute ios builds sucessfully
347+
*/
348+
shouldUseXcproj: boolean;
349+
/**
350+
* pod version string, as returned by `pod --version`
351+
*/
352+
cocoapodVer: string;
353+
/**
354+
* Xcode's version
355+
*/
356+
xcodeVersion: IVersionData;
357+
/**
358+
* determines whether xcproj can be called from the command line
359+
*/
360+
xcprojAvailable: boolean;
361+
}
362+

lib/services/doctor-service.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class DoctorService implements IDoctorService {
2828
private $opener: IOpener,
2929
private $prompter: IPrompter,
3030
private $fs: IFileSystem,
31-
private $versionsService: IVersionsService) { }
31+
private $versionsService: IVersionsService,
32+
private $xcprojService: IXcprojService) { }
3233

3334
public printWarnings(configOptions?: { trackResult: boolean }): IFuture<boolean> {
3435
return (() => {
@@ -101,6 +102,10 @@ class DoctorService implements IDoctorService {
101102
+ `To be able to build such projects, verify that you have at least ${DoctorService.MIN_SUPPORTED_POD_VERSION} version installed.`);
102103
result = true;
103104
}
105+
106+
if (this.$xcprojService.verifyXcproj(false).wait()) {
107+
result = true;
108+
}
104109
} else {
105110
this.$logger.out("NOTE: You can develop for iOS only on Mac OS X systems.");
106111
this.$logger.out("To be able to work with iOS devices and projects, you need Mac OS X Mavericks or later." + EOL);
@@ -198,11 +203,16 @@ class DoctorService implements IDoctorService {
198203
this.$config.USE_POD_SANDBOX ? "sandbox-pod" : "pod",
199204
["install"],
200205
"exit",
201-
{ stdio: "inherit", cwd: iosDir },
202-
{ throwError: true }
206+
{ cwd: iosDir },
207+
{ throwError: false }
203208
);
204209

205210
this.$progressIndicator.showProgressIndicator(future, 5000).wait();
211+
let result = future.get();
212+
if(result.exitCode) {
213+
this.$logger.out(result.stdout, result.stderr);
214+
return true;
215+
}
206216

207217
return !(this.$fs.exists(path.join(iosDir, "__PROJECT_NAME__.xcworkspace")).wait());
208218
} catch (err) {

lib/services/ios-project-service.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
4040
private $devicesService: Mobile.IDevicesService,
4141
private $mobileHelper: Mobile.IMobileHelper,
4242
private $pluginVariablesService: IPluginVariablesService,
43-
private $staticConfig: IStaticConfig,
44-
private $sysInfo: ISysInfo,
45-
private $xcodeSelectService: IXcodeSelectService) {
43+
private $xcprojService: IXcprojService) {
4644
super($fs, $projectData, $projectDataService);
4745
}
4846

@@ -661,30 +659,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
661659
this.$errors.failWithoutHelp("CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again.");
662660
}
663661

664-
let cocoapodsVer = this.$sysInfo.getSysInfo(this.$staticConfig.pathToPackageJson).wait().cocoapodVer,
665-
xcodeVersion = this.$xcodeSelectService.getXcodeVersion().wait();
666-
667-
if(!semver.valid(cocoapodsVer)) {
668-
// Cocoapods betas have names like 1.0.0.beta.8
669-
// These 1.0.0 betas are not valid semver versions, but they are working fine with XCode 7.3
670-
// So get only the major.minor.patch version and consider them as 1.0.0
671-
cocoapodsVer = _.take(cocoapodsVer.split("."), 3).join(".");
672-
}
673-
674-
xcodeVersion.patch = xcodeVersion.patch || "0";
675-
let shouldUseXcproj = semver.lt(cocoapodsVer, "1.0.0") && ~helpers.versionCompare(xcodeVersion, "7.3.0");
676-
677-
// CocoaPods with version lower than 1.0.0 don't support Xcode 7.3 yet
678-
// https://github.com/CocoaPods/CocoaPods/issues/2530#issuecomment-210470123
679-
// as a result of this all .pbxprojects touched by CocoaPods get converted to XML plist format
680-
if (shouldUseXcproj) {
681-
// if that's the case we can use xcproj gem to convert them back to ASCII plist format
682-
try {
683-
this.$childProcess.exec("xcproj --version").wait();
684-
} catch(e) {
685-
this.$errors.failWithoutHelp(`You are using CocoaPods version ${cocoapodsVer} which does not support Xcode ${xcodeVersion.major}.${xcodeVersion.minor} yet. In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH.`);
686-
}
687-
}
662+
this.$xcprojService.verifyXcproj(true).wait();
688663

689664
this.$logger.info("Installing pods...");
690665
let podTool = this.$config.USE_POD_SANDBOX ? "sandbox-pod" : "pod";
@@ -705,7 +680,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
705680
}
706681
}
707682

708-
if (shouldUseXcproj) {
683+
if (this.$xcprojService.getXcprojInfo().wait().shouldUseXcproj) {
709684
this.$childProcess.exec(`xcproj --project ${this.xcodeprojPath} touch`).wait();
710685
this.$childProcess.exec(`xcproj --project ${this.cocoaPodsXcodeprojPath} touch`).wait();
711686
}

lib/services/xcproj-service.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
import * as semver from "semver";
4+
import * as helpers from "../common/helpers";
5+
import {EOL} from "os";
6+
7+
class XcprojService implements IXcprojService {
8+
private xcprojInfoCache: IXcprojInfo;
9+
10+
constructor(private $childProcess: IChildProcess,
11+
private $errors: IErrors,
12+
private $logger: ILogger,
13+
private $staticConfig: IStaticConfig,
14+
private $sysInfo: ISysInfo,
15+
private $xcodeSelectService: IXcodeSelectService) {
16+
}
17+
18+
public verifyXcproj(shouldFail: boolean): IFuture<boolean> {
19+
return ((): boolean => {
20+
let xcprojInfo = this.getXcprojInfo().wait();
21+
if (xcprojInfo.shouldUseXcproj && !xcprojInfo.xcprojAvailable) {
22+
let errorMessage = `You are using CocoaPods version ${xcprojInfo.cocoapodVer} which does not support Xcode ${xcprojInfo.xcodeVersion.major}.${xcprojInfo.xcodeVersion.minor} yet.${EOL}In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH. Xcproj can be installed with homebrew by running $ brew install xcproj from the terminal`;
23+
if (shouldFail) {
24+
this.$errors.failWithoutHelp(errorMessage);
25+
} else {
26+
this.$logger.warn(errorMessage);
27+
}
28+
29+
return true;
30+
}
31+
32+
return false;
33+
}).future<boolean>()();
34+
}
35+
36+
public getXcprojInfo(): IFuture<IXcprojInfo> {
37+
return ((): IXcprojInfo => {
38+
if (!this.xcprojInfoCache) {
39+
let cocoapodVer = this.$sysInfo.getSysInfo(this.$staticConfig.pathToPackageJson).wait().cocoapodVer,
40+
xcodeVersion = this.$xcodeSelectService.getXcodeVersion().wait();
41+
42+
if(!semver.valid(cocoapodVer)) {
43+
// Cocoapods betas have names like 1.0.0.beta.8
44+
// These 1.0.0 betas are not valid semver versions, but they are working fine with XCode 7.3
45+
// So get only the major.minor.patch version and consider them as 1.0.0
46+
cocoapodVer = _.take(cocoapodVer.split("."), 3).join(".");
47+
}
48+
49+
xcodeVersion.patch = xcodeVersion.patch || "0";
50+
// CocoaPods with version lower than 1.0.0 don't support Xcode 7.3 yet
51+
// https://github.com/CocoaPods/CocoaPods/issues/2530#issuecomment-210470123
52+
// as a result of this all .pbxprojects touched by CocoaPods get converted to XML plist format
53+
let shouldUseXcproj = !!(semver.lt(cocoapodVer, "1.0.0") && ~helpers.versionCompare(xcodeVersion, "7.3.0")),
54+
xcprojAvailable: boolean;
55+
56+
if (shouldUseXcproj) {
57+
// if that's the case we can use xcproj gem to convert them back to ASCII plist format
58+
try {
59+
this.$childProcess.exec("xcproj --version").wait();
60+
xcprojAvailable = true;
61+
} catch(e) {
62+
xcprojAvailable = false;
63+
}
64+
}
65+
66+
this.xcprojInfoCache = { cocoapodVer, xcodeVersion, shouldUseXcproj, xcprojAvailable };
67+
}
68+
69+
return this.xcprojInfoCache;
70+
}).future<IXcprojInfo>()();
71+
}
72+
}
73+
74+
$injector.register("xcprojService", XcprojService);

test/ios-project-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function createTestInjector(projectPath: string, projectName: string): IInjector
7676
testInjector.register("loggingLevels", LoggingLevels);
7777
testInjector.register("utils", Utils);
7878
testInjector.register("iTunesValidator", {});
79-
testInjector.register("sysInfo", {});
79+
testInjector.register("xcprojService", {});
8080
testInjector.register("pluginVariablesService", PluginVariablesService);
8181
testInjector.register("pluginVariablesHelper", PluginVariablesHelper);
8282
return testInjector;

0 commit comments

Comments
 (0)