11import * as path from "path" ;
2- import * as semver from "semver" ;
32import { cache } from "./common/decorators" ;
43import { androidToolsInfo } from "nativescript-doctor" ;
54
65export class AndroidToolsInfo implements IAndroidToolsInfo {
7- private static ANDROID_TARGET_PREFIX = "android" ;
8- private static SUPPORTED_TARGETS = [
9- "android-17" ,
10- "android-18" ,
11- "android-19" ,
12- "android-21" ,
13- "android-22" ,
14- "android-23" ,
15- "android-24" ,
16- "android-25" ,
17- "android-26" ,
18- "android-27" ,
19- "android-28" ,
20- ] ;
21- private static MIN_REQUIRED_COMPILE_TARGET = 28 ;
22- private static REQUIRED_BUILD_TOOLS_RANGE_PREFIX = ">=23" ;
23- private static VERSION_REGEX = / ( ( \d + \. ) { 2 } \d + ) / ;
24-
25- private showWarningsAsErrors : boolean ;
26- private toolsInfo : IAndroidToolsInfoData ;
27- private selectedCompileSdk : number ;
28- private get androidHome ( ) : string {
29- return process . env [ "ANDROID_HOME" ] ;
30- }
31-
326 constructor ( private $errors : IErrors ,
33- private $fs : IFileSystem ,
347 private $logger : ILogger ,
358 private $options : IOptions ,
369 protected $staticConfig : Config . IStaticConfig ) {
3710 }
3811
3912 @cache ( )
40- public getToolsInfo ( ) : IAndroidToolsInfoData {
41- if ( ! this . toolsInfo ) {
42- const infoData : IAndroidToolsInfoData = Object . create ( null ) ;
43- infoData . androidHomeEnvVar = this . androidHome ;
44- infoData . compileSdkVersion = this . getCompileSdkVersion ( ) ;
45- infoData . buildToolsVersion = this . getBuildToolsVersion ( ) ;
46- infoData . targetSdkVersion = this . getTargetSdk ( ) ;
47- infoData . generateTypings = this . shouldGenerateTypings ( ) ;
48-
49- this . toolsInfo = infoData ;
50- }
13+ public getToolsInfo ( config : IProjectDir ) : IAndroidToolsInfoData {
14+ const infoData : IAndroidToolsInfoData = < IAndroidToolsInfoData > ( androidToolsInfo . getToolsInfo ( { projectDir : config . projectDir } ) ) ;
15+
16+ infoData . androidHomeEnvVar = androidToolsInfo . androidHome ;
17+ infoData . compileSdkVersion = this . getCompileSdkVersion ( infoData . installedTargets , infoData . compileSdkVersion ) ;
18+ infoData . targetSdkVersion = this . getTargetSdk ( infoData . compileSdkVersion ) ;
19+ infoData . generateTypings = this . shouldGenerateTypings ( ) ;
20+
21+ this . $logger . trace ( "Installed Android Targets are: " , infoData . installedTargets ) ;
22+ this . $logger . trace ( "Selected buildToolsVersion is:" , infoData . buildToolsVersion ) ;
5123
52- return this . toolsInfo ;
24+ return infoData ;
5325 }
5426
5527 public validateInfo ( options ?: IAndroidToolsInfoValidateInput ) : boolean {
5628 let detectedErrors = false ;
57- this . showWarningsAsErrors = options && options . showWarningsAsErrors ;
58- const isAndroidHomeValid = this . validateAndroidHomeEnvVariable ( ) ;
29+ const showWarningsAsErrors = options && options . showWarningsAsErrors ;
30+ const isAndroidHomeValid = this . validateAndroidHomeEnvVariable ( options ) ;
5931
60- detectedErrors = androidToolsInfo . validateInfo ( ) . map ( warning => this . printMessage ( warning . warning ) ) . length > 0 ;
32+ detectedErrors = androidToolsInfo . validateInfo ( { projectDir : options . projectDir } ) . map ( warning => this . printMessage ( warning . warning , showWarningsAsErrors ) ) . length > 0 ;
6133
6234 if ( options && options . validateTargetSdk ) {
63- detectedErrors = this . validateTargetSdk ( ) ;
35+ detectedErrors = this . validateTargetSdk ( options ) ;
6436 }
6537
6638 return detectedErrors || ! isAndroidHomeValid ;
6739 }
6840
69- public validateTargetSdk ( options ? : IAndroidToolsInfoOptions ) : boolean {
70- this . showWarningsAsErrors = options && options . showWarningsAsErrors ;
41+ public validateTargetSdk ( options : IAndroidToolsInfoOptions ) : boolean {
42+ let detectedErrors = false ;
7143
72- const toolsInfoData = this . getToolsInfo ( ) ;
44+ const toolsInfoData = this . getToolsInfo ( { projectDir : options . projectDir } ) ;
7345 const targetSdk = toolsInfoData . targetSdkVersion ;
74- const newTarget = `${ AndroidToolsInfo . ANDROID_TARGET_PREFIX } -${ targetSdk } ` ;
7546
76- if ( ! _ . includes ( AndroidToolsInfo . SUPPORTED_TARGETS , newTarget ) ) {
77- const supportedVersions = AndroidToolsInfo . SUPPORTED_TARGETS . sort ( ) ;
78- const minSupportedVersion = this . parseAndroidSdkString ( _ . first ( supportedVersions ) ) ;
47+ detectedErrors = androidToolsInfo . validateMinSupportedTargetSdk ( { targetSdk, projectDir : options . projectDir } ) . map ( warning => this . printMessage ( warning . warning , options . showWarningsAsErrors ) ) . length > 0 ;
7948
80- if ( targetSdk && ( targetSdk < minSupportedVersion ) ) {
81- this . printMessage ( `The selected Android target SDK ${ newTarget } is not supported. You must target ${ minSupportedVersion } or later.` ) ;
82- return true ;
83- } else if ( ! targetSdk || targetSdk > this . getMaxSupportedVersion ( ) ) {
84- this . $logger . warn ( `Support for the selected Android target SDK ${ newTarget } is not verified. Your Android app might not work as expected.` ) ;
85- }
49+ if ( ! detectedErrors ) {
50+ androidToolsInfo . validataMaxSupportedTargetSdk ( { targetSdk, projectDir : options . projectDir } ) . map ( warning => this . $logger . warn ( warning . warning ) ) ;
8651 }
8752
88- return false ;
53+ return detectedErrors ;
8954 }
9055
9156 public validateJavacVersion ( installedJavacVersion : string , options ?: IAndroidToolsInfoOptions ) : boolean {
92- if ( options ) {
93- this . showWarningsAsErrors = options . showWarningsAsErrors ;
94- }
57+ const showWarningsAsErrors = options && options . showWarningsAsErrors ;
9558
96- return androidToolsInfo . validateJavacVersion ( installedJavacVersion ) . map ( warning => this . printMessage ( warning . warning ) ) . length > 0 ;
59+ return androidToolsInfo . validateJavacVersion ( installedJavacVersion ) . map ( warning => this . printMessage ( warning . warning , showWarningsAsErrors ) ) . length > 0 ;
9760 }
9861
9962 public async getPathToAdbFromAndroidHome ( ) : Promise < string > {
@@ -102,19 +65,17 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
10265 } catch ( err ) {
10366 // adb does not exist, so ANDROID_HOME is not set correctly
10467 // try getting default adb path (included in CLI package)
105- this . $logger . trace ( `Error while executing '${ path . join ( this . androidHome , "platform-tools" , "adb" ) } help'. Error is: ${ err . message } ` ) ;
68+ this . $logger . trace ( `Error while executing '${ path . join ( androidToolsInfo . androidHome , "platform-tools" , "adb" ) } help'. Error is: ${ err . message } ` ) ;
10669 }
10770
10871 return null ;
10972 }
11073
11174 @cache ( )
11275 public validateAndroidHomeEnvVariable ( options ?: IAndroidToolsInfoOptions ) : boolean {
113- if ( options ) {
114- this . showWarningsAsErrors = options . showWarningsAsErrors ;
115- }
76+ const showWarningsAsErrors = options && options . showWarningsAsErrors ;
11677
117- return androidToolsInfo . validateAndroidHomeEnvVariable ( ) . map ( warning => this . printMessage ( warning . warning ) ) . length > 0 ;
78+ return androidToolsInfo . validateAndroidHomeEnvVariable ( ) . map ( warning => this . printMessage ( warning . warning , showWarningsAsErrors ) ) . length > 0 ;
11879 }
11980
12081 private shouldGenerateTypings ( ) : boolean {
@@ -127,119 +88,36 @@ export class AndroidToolsInfo implements IAndroidToolsInfo {
12788 * In case additional details must be shown as info message, use the second parameter.
12889 * NOTE: The additional information will not be printed when showWarningsAsErrors flag is set.
12990 * @param {string } msg The message that will be shown as warning or error.
130- * @param {string } additionalMsg The additional message that will be shown as info message.
13191 * @return {void }
13292 */
133- private printMessage ( msg : string , additionalMsg ?: string ) : void {
134- if ( this . showWarningsAsErrors ) {
93+ private printMessage ( msg : string , showWarningsAsErrors : boolean ) : void {
94+ if ( showWarningsAsErrors ) {
13595 this . $errors . failWithoutHelp ( msg ) ;
13696 } else {
13797 this . $logger . warn ( msg ) ;
13898 }
139-
140- if ( additionalMsg ) {
141- this . $logger . printMarkdown ( additionalMsg ) ;
142- }
14399 }
144100
145- private getCompileSdkVersion ( ) : number {
146- if ( ! this . selectedCompileSdk ) {
147- const userSpecifiedCompileSdk = this . $options . compileSdk ;
148- if ( userSpecifiedCompileSdk ) {
149- const installedTargets = this . getInstalledTargets ( ) ;
150- const androidCompileSdk = `${ AndroidToolsInfo . ANDROID_TARGET_PREFIX } -${ userSpecifiedCompileSdk } ` ;
151- if ( ! _ . includes ( installedTargets , androidCompileSdk ) ) {
152- this . $errors . failWithoutHelp ( `You have specified '${ userSpecifiedCompileSdk } ' for compile sdk, but it is not installed on your system.` ) ;
153- }
154-
155- this . selectedCompileSdk = userSpecifiedCompileSdk ;
156- } else {
157- const latestValidAndroidTarget = this . getLatestValidAndroidTarget ( ) ;
158- if ( latestValidAndroidTarget ) {
159- const integerVersion = this . parseAndroidSdkString ( latestValidAndroidTarget ) ;
160-
161- if ( integerVersion && integerVersion >= AndroidToolsInfo . MIN_REQUIRED_COMPILE_TARGET ) {
162- this . selectedCompileSdk = integerVersion ;
163- }
164- }
165- }
166- }
101+ private getCompileSdkVersion ( installedTargets : string [ ] , latestCompileSdk : number ) : number {
102+ const userSpecifiedCompileSdk = this . $options . compileSdk ;
167103
168- return this . selectedCompileSdk ;
169- }
170-
171- private getTargetSdk ( ) : number {
172- const targetSdk = this . $options . sdk ? parseInt ( this . $options . sdk ) : this . getCompileSdkVersion ( ) ;
173- this . $logger . trace ( `Selected targetSdk is: ${ targetSdk } ` ) ;
174- return targetSdk ;
175- }
176-
177- private getMatchingDir ( pathToDir : string , versionRange : string ) : string {
178- let selectedVersion : string ;
179- if ( this . $fs . exists ( pathToDir ) ) {
180- const subDirs = this . $fs . readDirectory ( pathToDir ) ;
181- this . $logger . trace ( `Directories found in ${ pathToDir } are ${ subDirs . join ( ", " ) } ` ) ;
182-
183- const subDirsVersions = subDirs
184- . map ( dirName => {
185- const dirNameGroups = dirName . match ( AndroidToolsInfo . VERSION_REGEX ) ;
186- if ( dirNameGroups ) {
187- return dirNameGroups [ 1 ] ;
188- }
189-
190- return null ;
191- } )
192- . filter ( dirName => ! ! dirName ) ;
193- this . $logger . trace ( `Versions found in ${ pathToDir } are ${ subDirsVersions . join ( ", " ) } ` ) ;
194- const version = semver . maxSatisfying ( subDirsVersions , versionRange ) ;
195- if ( version ) {
196- selectedVersion = _ . find ( subDirs , dir => dir . indexOf ( version ) !== - 1 ) ;
104+ if ( userSpecifiedCompileSdk ) {
105+ const androidCompileSdk = `${ androidToolsInfo . ANDROID_TARGET_PREFIX } -${ userSpecifiedCompileSdk } ` ;
106+ if ( ! _ . includes ( installedTargets , androidCompileSdk ) ) {
107+ this . $errors . failWithoutHelp ( `You have specified '${ userSpecifiedCompileSdk } ' for compile sdk, but it is not installed on your system.` ) ;
197108 }
198- }
199- this . $logger . trace ( "Selected version is: " , selectedVersion ) ;
200- return selectedVersion ;
201- }
202-
203- private getBuildToolsRange ( ) : string {
204- return `${ AndroidToolsInfo . REQUIRED_BUILD_TOOLS_RANGE_PREFIX } <=${ this . getMaxSupportedVersion ( ) } ` ;
205- }
206109
207- private getBuildToolsVersion ( ) : string {
208- let buildToolsVersion : string ;
209- if ( this . androidHome ) {
210- const pathToBuildTools = path . join ( this . androidHome , "build-tools" ) ;
211- const buildToolsRange = this . getBuildToolsRange ( ) ;
212- buildToolsVersion = this . getMatchingDir ( pathToBuildTools , buildToolsRange ) ;
110+ return userSpecifiedCompileSdk ;
213111 }
214112
215- return buildToolsVersion ;
216- }
217-
218- private getLatestValidAndroidTarget ( ) : string {
219- const installedTargets = this . getInstalledTargets ( ) ;
220- return _ . findLast ( AndroidToolsInfo . SUPPORTED_TARGETS . sort ( ) , supportedTarget => _ . includes ( installedTargets , supportedTarget ) ) ;
221- }
222-
223- private parseAndroidSdkString ( androidSdkString : string ) : number {
224- return parseInt ( androidSdkString . replace ( `${ AndroidToolsInfo . ANDROID_TARGET_PREFIX } -` , "" ) ) ;
113+ return latestCompileSdk ;
225114 }
226115
227- @cache ( )
228- private getInstalledTargets ( ) : string [ ] {
229- let installedTargets : string [ ] = [ ] ;
230- if ( this . androidHome ) {
231- const pathToInstalledTargets = path . join ( this . androidHome , "platforms" ) ;
232- if ( this . $fs . exists ( pathToInstalledTargets ) ) {
233- installedTargets = this . $fs . readDirectory ( pathToInstalledTargets ) ;
234- }
235- }
236- this . $logger . trace ( "Installed Android Targets are: " , installedTargets ) ;
237-
238- return installedTargets ;
239- }
240-
241- private getMaxSupportedVersion ( ) : number {
242- return this . parseAndroidSdkString ( _ . last ( AndroidToolsInfo . SUPPORTED_TARGETS . sort ( ) ) ) ;
116+ // TODO check if still needed
117+ private getTargetSdk ( compileSdk : number ) : number {
118+ const targetSdk = this . $options . sdk ? parseInt ( this . $options . sdk ) : compileSdk ;
119+ this . $logger . trace ( `Selected targetSdk is: ${ targetSdk } ` ) ;
120+ return targetSdk ;
243121 }
244122}
245123$injector . register ( "androidToolsInfo" , AndroidToolsInfo ) ;
0 commit comments