Skip to content

Pass correct parameters to gradle build #856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions lib/android-tools-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
///<reference path=".d.ts"/>
"use strict";

import * as path from "path";
import * as semver from "semver";

export class AndroidToolsInfo implements IAndroidToolsInfo {
private static ANDROID_TARGET_PREFIX = "android";
private static SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21", "android-22"];
private static MIN_REQUIRED_COMPILE_TARGET = 21;
private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=22";
private static VERSION_REGEX = /^(\d+\.){2}\d+$/;
private showWarningsAsErrors: boolean;
private toolsInfo: IAndroidToolsInfoData;
private selectedCompileSdk: number;
private installedTargetsCache: string[] = null;
private androidHome = process.env["ANDROID_HOME"];

constructor(private $childProcess: IChildProcess,
private $errors: IErrors,
private $fs: IFileSystem,
private $logger: ILogger,
private $options: IOptions) {}

public getToolsInfo(): IFuture<IAndroidToolsInfoData> {
return ((): IAndroidToolsInfoData => {
if(!this.toolsInfo) {
let infoData: IAndroidToolsInfoData = Object.create(null);
infoData.androidHomeEnvVar = this.androidHome;
infoData.compileSdkVersion = this.getCompileSdk().wait();
infoData.buildToolsVersion = this.getBuildToolsVersion().wait();
infoData.targetSdkVersion = this.getTargetSdk().wait();
infoData.supportLibraryVersion = this.getAndroidSupportLibVersion().wait();

this.toolsInfo = infoData;
}

return this.toolsInfo;
}).future<IAndroidToolsInfoData>()();
}

public validateInfo(options?: {showWarningsAsErrors: boolean, validateTargetSdk: boolean}): IFuture<void> {
return (() => {
this.showWarningsAsErrors = options && options.showWarningsAsErrors;
let toolsInfoData = this.getToolsInfo().wait();
if(!toolsInfoData.androidHomeEnvVar || !this.$fs.exists(toolsInfoData.androidHomeEnvVar).wait()) {
this.printMessage("The ANDROID_HOME environment variable is not set or it points to a non-existent directory. You will not be able to perform any build-related operations for Android.",
"To be able to perform Android build-related operations, set the ANDROID_HOME variable to point to the root of your Android SDK installation directory.");
}

if(!toolsInfoData.compileSdkVersion) {
this.printMessage(`Cannot find a compatible Android SDK for compilation. To be able to build for Android, install Android SDK ${AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET} or later.`,
"Run `$ android` to manage your Android SDK versions.");
}

if(!toolsInfoData.buildToolsVersion) {
this.printMessage(`You need to have the Android SDK Build-tools installed on your system. You can install any version in the following range: '${this.getBuildToolsRange()}'.`,
'Run "android" from your command-line to install required Android Build Tools.');
}

if(!toolsInfoData.supportLibraryVersion) {
this.printMessage(`You need to have the Android Support Library installed on your system. You can install any version in the following range: ${this.getAppCompatRange().wait() || ">=" + AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET}}.`,
'Run `$ android` to manage the Android Support Library.');
}

if(options && options.validateTargetSdk) {
let targetSdk = toolsInfoData.targetSdkVersion;
let newTarget = `${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-${targetSdk}`;
if(!_.contains(AndroidToolsInfo.SUPPORTED_TARGETS, newTarget)) {
let supportedVersions = AndroidToolsInfo.SUPPORTED_TARGETS.sort();
let minSupportedVersion = this.parseAndroidSdkString(_.first(supportedVersions));

if(targetSdk && (targetSdk < minSupportedVersion)) {
this.printMessage(`The selected Android target SDK ${newTarget} is not supported. You пкяш target ${minSupportedVersion} or later.`);
} else if(!targetSdk || targetSdk > this.getMaxSupportedVersion()) {
this.$logger.warn(`Support for the selected Android target SDK ${newTarget} is not verified. Your Android app might not work as expected.`);
}
}
}
}).future<void>()();
}

/**
* Prints messages on the screen. In case the showWarningsAsErrors flag is set to true, warnings are shown, else - errors.
* Uses logger.warn for warnings and errors.failWithoutHelp when erros must be shown.
* In case additional details must be shown as info message, use the second parameter.
* NOTE: The additional information will not be printed when showWarningsAsErrors flag is set.
* @param {string} msg The message that will be shown as warning or error.
* @param {string} additionalMsg The additional message that will be shown as info message.
* @return {void}
*/
private printMessage(msg: string, additionalMsg?: string): void {
if (this.showWarningsAsErrors) {
this.$errors.failWithoutHelp(msg);
} else {
this.$logger.warn(msg);
}

if(additionalMsg) {
this.$logger.info(additionalMsg);
}
}

private getCompileSdk(): IFuture<number> {
return ((): number => {
if(!this.selectedCompileSdk) {
let latestValidAndroidTarget = this.getLatestValidAndroidTarget().wait();
if(latestValidAndroidTarget) {
let integerVersion = this.parseAndroidSdkString(latestValidAndroidTarget);

if(integerVersion && integerVersion >= AndroidToolsInfo.MIN_REQUIRED_COMPILE_TARGET) {
this.selectedCompileSdk = integerVersion;
}
}
}

return this.selectedCompileSdk;
}).future<number>()();
}

private getTargetSdk(): IFuture<number> {
return ((): number => {
let targetSdk = this.$options.sdk ? parseInt(this.$options.sdk) : this.getCompileSdk().wait();
this.$logger.trace(`Selected targetSdk is: ${targetSdk}`);
return targetSdk;
}).future<number>()();
}

private getMatchingDir(pathToDir: string, versionRange: string): IFuture<string> {
return ((): string => {
let selectedVersion: string;
if(this.$fs.exists(pathToDir).wait()) {
let subDirs = this.$fs.readDirectory(pathToDir).wait()
.filter(buildTools => !!buildTools.match(AndroidToolsInfo.VERSION_REGEX));
this.$logger.trace(`Versions found in ${pathToDir} are ${subDirs.join(", ")}`);
selectedVersion = semver.maxSatisfying(subDirs, versionRange);
}

return selectedVersion;
}).future<string>()();
}

private getBuildToolsRange(): string {
return `${AndroidToolsInfo.REQUIRED_BUILD_TOOLS_RANGE_PREFIX} <=${this.getMaxSupportedVersion()}`;
}

private getBuildToolsVersion(): IFuture<string> {
return ((): string => {
let pathToBuildTools = path.join(this.androidHome, "build-tools");
let buildToolsRange = this.getBuildToolsRange();

return this.getMatchingDir(pathToBuildTools, buildToolsRange).wait();
}).future<string>()();
}

private getAppCompatRange(): IFuture<string> {
return ((): string => {
let compileSdkVersion = this.getCompileSdk().wait();
let requiredAppCompatRange: string;
if(compileSdkVersion) {
requiredAppCompatRange = `>=${compileSdkVersion} <${compileSdkVersion + 1}`;
}

return requiredAppCompatRange;
}).future<string>()();
}

private getAndroidSupportLibVersion(): IFuture<string> {
return ((): string => {
let pathToAppCompat = path.join(this.androidHome, "extras", "android", "m2repository", "com", "android", "support", "appcompat-v7");
let requiredAppCompatRange = this.getAppCompatRange().wait();
let selectedAppCompatVersion = requiredAppCompatRange ? this.getMatchingDir(pathToAppCompat, requiredAppCompatRange).wait() : undefined;
this.$logger.trace(`Selected AppCompat version is: ${selectedAppCompatVersion}`);
return selectedAppCompatVersion;
}).future<string>()();
}

private getLatestValidAndroidTarget(): IFuture<string> {
return (() => {
let installedTargets = this.getInstalledTargets().wait();
return _.findLast(AndroidToolsInfo.SUPPORTED_TARGETS.sort(), supportedTarget => _.contains(installedTargets, supportedTarget));
}).future<string>()();
}

private parseAndroidSdkString(androidSdkString: string): number {
return parseInt(androidSdkString.replace(`${AndroidToolsInfo.ANDROID_TARGET_PREFIX}-`, ""));
}

private getInstalledTargets(): IFuture<string[]> {
return (() => {
if (!this.installedTargetsCache) {
this.installedTargetsCache = [];
let output = this.$childProcess.exec('android list targets').wait();
output.replace(/id: \d+ or "(.+)"/g, (m:string, p1:string) => (this.installedTargetsCache.push(p1), m));
}
return this.installedTargetsCache;
}).future<string[]>()();
}

private getMaxSupportedVersion(): number {
return this.parseAndroidSdkString(_.last(AndroidToolsInfo.SUPPORTED_TARGETS.sort()));
}
}
$injector.register("androidToolsInfo", AndroidToolsInfo);
1 change: 1 addition & 0 deletions lib/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ $injector.requireCommand("init", "./commands/init");

$injector.require("projectFilesManager", "./services/project-files-manager");
$injector.requireCommand("livesync", "./commands/livesync");
$injector.require("androidToolsInfo", "./android-tools-info");
50 changes: 50 additions & 0 deletions lib/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,53 @@ interface IProjectFilesManager {
interface IInitService {
initialize(): IFuture<void>;
}

/**
* Provides access to information about installed Android tools and SDKs versions.
*/
interface IAndroidToolsInfo {
/**
* Provides information about installed Android SDKs, Build Tools, Support Library
* and ANDROID_HOME environement variable.
* @return {IAndroidToolsInfoData} Information about installed Android Tools and SDKs.
*/
getToolsInfo(): IFuture<IAndroidToolsInfoData>;

/**
* Validates the information about required Android tools and SDK versions.
* @param {any} options Defines if the warning messages should treated as error and if the targetSdk value should be validated as well.
* @return {void}
*/
validateInfo(options?: {showWarningsAsErrors: boolean, validateTargetSdk: boolean}): IFuture<void>;
}

/**
* Describes information about installed Android tools and SDKs.
*/
interface IAndroidToolsInfoData {
/**
* The value of ANDROID_HOME environment variable.
*/
androidHomeEnvVar: string;

/**
* The latest installed version of Android Build Tools that satisfies CLI's requirements.
*/
buildToolsVersion: string;

/**
* The latest installed version of Android SDK that satisfies CLI's requirements.
*/
compileSdkVersion: number;

/**
* The latest installed version of Android Support Library that satisfies CLI's requirements.
*/
supportLibraryVersion: string;

/**
* The Android targetSdkVersion specified by the user.
* In case it is not specified, compileSdkVersion will be used for targetSdkVersion.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments are totally awesome!

targetSdkVersion: number;
}
Loading