diff --git a/README.md b/README.md index 4886025019..f11e666641 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ AutoRest can be run on OSX and Unix using Mono or by running Docker container: ## Building AutoRest AutoRest is developed primarily in C# but generates code for multiple languages. See [this link](Documentation/building-code.md) to build and test AutoRest. +> Hint: There is a powershell script (`verify-settings.ps1`) in the `Tools` folder that can verify that you have the required compilers/tools/libraries installed on your development system before trying to build. + ## Hello World For this version of Hello World, we will use **AutoRest** to generate a client library and use it to call a web service. The trivial web service that just returns a string is defined as follows: ``` diff --git a/Tools/Install-AndroidSDK.ps1 b/Tools/Install-AndroidSDK.ps1 new file mode 100644 index 0000000000..b9b4944571 --- /dev/null +++ b/Tools/Install-AndroidSDK.ps1 @@ -0,0 +1,481 @@ +<# + This script can install additional Android SDK packages + (assuming that you installed at least something) + Gleefully borrowed from the VS 2015 installer. + + Usage: + + # Install the SDK for Android level 23: + # AS ADMIN!! + + .\Install-AndroidSDK.ps1 -RequestedAndroidPackages android-23 -apilevel 23 +#> +param +( + [String[]]$RequestedAndroidPackages, + [String]$Operation, + [String]$LogFileName, + [String]$APILevel +) + +function add-content( $path, $text ) { + write-host "LOG: $text" + Microsoft.PowerShell.Management\add-content $path $text +} + +function Set-InstallResult ($Succeeded, $details,$ReturnCode ) { + write-host $Succeeded $details $ReturnCode +} + +<# +Download and install Android SDK +#> +Function Invoke-InteractiveProcess([String]$FilePath, [string[]]$ArgumentList) +{ + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = $FilePath + $startInfo.Arguments = $ArgumentList + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardInput = $true + $startInfo.RedirectStandardOutput = $true + $startInfo.CreateNoWindow = $true + $process = [System.Diagnostics.Process]::Start($startInfo) + + return $process +} + + +# Android helper functions +Function Get-AndroidHomeFromRegistry +{ + + # if ([Environment]::Is64BitOperatingSystem) + # powershell v1 doesn't have is 64 bit flag. + if ([environment]::GetEnvironmentVariable("ProgramFiles(x86)")) + { + $androidRegistryKey = "HKLM:\SOFTWARE\Wow6432Node\Android SDK Tools" + } + else + { + $androidRegistryKey = "HKLM:\SOFTWARE\Android SDK Tools" + } + + if (Test-Path $androidRegistryKey) + { + $path = (Get-ItemProperty $androidRegistryKey Path).Path + + if (-not (Test-Path $path)) + { + $path = $null + } + } + + return $path +} + + +Function Format-PackageList($packages) +{ + "$([Environment]::Newline) $($packages -join "$([Environment]::Newline) ")$([Environment]::Newline)" +} + +Function Get-AVDConfiguration([String]$FilePath) +{ + $result = @{} + + if (Test-Path $FilePath) + { + ForEach ($pair in (Get-Content $FilePath) -split "`n") + { + $pair = $pair -split "=" + + if ($pair.Count -eq 2) + { + $result[$pair[0]] = $pair[1] + } + } + } + + return $result +} + +Function Set-AVDConfiguration([String]$FilePath, [Hashtable]$configHashtable) +{ + Remove-Item $FilePath + + ForEach ($key in $configHashtable.Keys | Sort-Object) + { + $keyValuePair = "$key=$($configHashtable[$key])" + Add-Content $FilePath $keyValuePair + } +} + +Function Create-AVD([String]$Name, [String]$DeviceDefinition, [Hashtable]$ConfigurationOptions) +{ + if (-not $Name) + { + return + } + + add-content $logFile "Creating AVD $Name" + + $processArgs = @("create avd", + "-n $Name", + "-t $currentApiLevel", + "-b default/armeabi-v7a") + + if ($DeviceDefinition) + { + $processArgs += "-d `"$DeviceDefinition`"" + } + + # Create the AVD + $process = Invoke-InteractiveProcess ` + -FilePath "$androidHome\tools\android.bat" ` + -ArgumentList $processArgs + + while (-not $process.StandardOutput.EndOfStream) + { + # Answer 'no' to: Do you wish to create a custom hardware profile [no] + $firstChar = $process.StandardOutput.Peek() + if ($firstChar -eq 68) + { + $process.StandardInput.WriteLine("no") + } + + $line = $process.StandardOutput.ReadLine() + + add-content $logFile "$line$([Environment]::NewLine)" + } + + # needs to kill adb process here because if SecondaryInstaller is launched via ARP, adb + # server will be launched and prevent ARP from installing other things. + # need to have -erroraction silentlycontinue, otherwise we'll get an error when adb doesn't exist + $processAdb = Get-Process adb -erroraction silentlycontinue + if ($processAdb) + { + $processAdb.Kill() + } + if (!$process.HasExited) + { + $process.CloseMainWindow() + } + $process.Dispose() + + $avdConfigFile = "$env:HOMEPATH\.android\avd\$defaultAVDName.avd\config.ini" + + if (Test-Path $avdConfigFile) + { + $configHashtable = Get-AVDConfiguration $avdConfigFile + + foreach ($key in $ConfigurationOptions.Keys) + { + $configHashtable[$key] = $ConfigurationOptions[$key] + } + + Set-AVDConfiguration $avdConfigFile $configHashtable + + add-content $logFile "Updating AVD $Name to the following hardware config:$([Environment]::NewLine)" + + Get-Content $avdConfigFile | Microsoft.PowerShell.Management\add-content $logFile + + add-content $logFile "$([Environment]::NewLine)" + } +} + +Function Get-DeviceDefinitionNames() +{ + return (& $androidBatch list devices) ` + | Select-String ` + -AllMatches ` + -Pattern 'id: (?\d+) or "(?[\s-_A-Za-z0-9\.]+)"' ` + | Select-Object -ExpandProperty Matches ` + | Foreach-Object {$_.Groups['deviceName'].Value} +} + +Function Get-PreferredAVDDeviceDefinition() +{ + $nexusDevices = Get-DeviceDefinitionNames | Where-Object { $_.Contains("Nexus")} + + $deviceDefinition = "" + $preferredDeviceDefinition = "Galaxy Nexus" + + if ($nexusDevices.Length -gt 0) + { + if ($nexusDevices -contains $preferredDeviceDefinition) + { + $deviceDefinition = $preferredDeviceDefinition + } + else + { + $deviceDefinition = $nexusDevices[0] + } + } + + return $deviceDefinition +} + +Function Get-FileNameWithTimeStamp([String]$OldFileName) +{ + [string]$strippedFileName = [System.IO.Path]::GetFileNameWithoutExtension($OldFileName); + [string]$extension = [System.IO.Path]::GetExtension($OldFileName); + [string]$newFileName = $strippedFileName + [DateTime]::Now.ToString("yyyyMMdd-HHmmss") + $extension; + [string]$newFilePath = [System.IO.Path]::Combine($Env:temp, $newFileName); + + return $newFilePath +} + +# OUTPUT: [String[]]A list of packages installed previously. +# Operation: +# Go to HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller\AndroidSDKSelector +# Extract the list of key names. +Function Get-InstalledPackagesFromRegistry() +{ + [String[]]$installedPackagesResult = @() + + $androidPackageSelectorRootRegistryKey = "HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller\AndroidSDKSelector" + + if (Test-Path $androidPackageSelectorRootRegistryKey) + { + $installedPackagesItems = Get-ChildItem $androidPackageSelectorRootRegistryKey -ErrorAction SilentlyContinue + + $installedPackagesResult = $installedPackagesItems | Select-Object -ExpandProperty PSChildName + } + + return $installedPackagesResult +} + +# INPUT: TargetPackages - a list of packages the user wants to install. +# INPUT: TargetOperation - the current operation. +# OUTPUT: A list of packages the script should install. +# Operation: +# If the TargetOperation is Repair and no TargetPackages is passed in return a list of alreadyInstalledPackages. +# Else +# Return a list of TargetPackages that are not already been installed. +Function Get-DesiredPackages([String[]]$TargetPackages, [String]$TargetOperation) +{ + $alreadyInstalledPackages = Get-InstalledPackagesFromRegistry + + add-content $logFile "Here are list of packages already installed on this system: $alreadyInstalledPackages" + + if ($TargetOperation -eq "Repair") + { + # if the user pass in specific packages, then we should repair those. + if ($TargetPackages) + { + add-content $logFile "Repair the following: $TargetPackages" + return $TargetPackages + } + + add-content $logFile "Repair the following: $alreadyInstalledPackages" + + return $alreadyInstalledPackages + } + + $packagesDontNeedToBeInstalled = $TargetPackages | Where { $alreadyInstalledPackages -contains $_ } + add-content $logFile "Skipping followings because they were installed previously: $packagesDontNeedToBeInstalled" + $packagesNeedToBeInstalled = $TargetPackages | Where { $alreadyInstalledPackages -notcontains $_ } + Add-Content $logFile "Install the followings: $packagesNeedToBeInstalled" + + return $packagesNeedToBeInstalled +} + +# INPUT: TargetPackages - a list of packages that were installed successfully. +# INPUT: TargetOperation - the current operation. +# Operation: +# If the TargetOperation is Repair, no opt. +# Else +# Write a list of intalled packages to the registry. +Function Set-InstalledPackages([String[]]$InstalledPackages, [String]$TargetOperation) +{ + if ($TargetOperation -eq "Repair") + { + add-content $logFile "Repair operation, no registry is set." + } + else + { + add-content $logFile "Recording the list of installed package. (This step will not remove previously installed items)" + + foreach($p in $InstalledPackages) + { + $androidPackageSelectorRegistryKey = "HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller\AndroidSDKSelector\$p" + + add-content $logFile "Recorded Installed item: $androidPackageSelectorRegistryKey" + + if (-not (Test-Path $androidPackageSelectorRegistryKey)) + { + $newRegistryItem = New-Item -Force -Path $androidPackageSelectorRegistryKey -ErrorAction SilentlyContinue + } + } + } +} + +# INPUT: +# [String[]]$RequestedAndroidPackages, +# [String]$Operation, +# [String]$LogFileName, +# [Int]$APILevel + +# Get Start Time +$startDTM = (Get-Date) + +$logFile = Get-FileNameWithTimeStamp $LogFileName +if ([IO.File]::Exists($logFile)) +{ + Remove-Item $logFile +} + +add-content $logFile "AndroidSDKInstall: -RequestedAndroidPackages $RequestedAndroidPackages -Operation $Operation -LogFilename $LogFileName -APILevel $APILevel" +add-content $logFile "Android SDK Install starting ..." + +$androidHome = Get-AndroidHomeFromRegistry + +# if androidHome doesn't exist then we don't have to select products. +if (!$androidHome) +{ + add-content $logFile "No Android SDK detected." + + Set-InstallResult -Succeeded $true + exit +} + +add-content $logFile "AndroidHome:" +add-content $logFile $androidHome + +$androidBatch = Join-Path $androidHome "tools\android.bat" + +$packageListingOutputRaw = & $androidBatch list sdk --all --extended +$anyAVDsFound = (& $androidBatch list avd) -match "Name: " + +$packageRegex = 'id: \d+ or "(?[-_A-Za-z0-9\.]+)"' +$availablePackages = [regex]::Matches($packageListingOutputRaw, $packageRegex) | ForEach { $_.Groups["packageName"].Value } + +add-content $logFile "Android packages available:" +add-content $logFile "$(Format-PackageList $availablePackages)" + +Add-Content $logFile "Requested Packages: $RequestedAndroidPackages" + +$desiredPackages = Get-DesiredPackages $RequestedAndroidPackages $Operation + +$currentApiLevel = $APILevel + +$packagesToInstall = $desiredPackages | Where { $availablePackages -contains $_ } +$packagesNotFound = $desiredPackages | Where { $availablePackages -notcontains $_ } + +if ($packagesToInstall) +{ + add-content $logFile "Installing packages:" + add-content $logFile "$(Format-PackageList $packagesToInstall)" + + $process = Invoke-InteractiveProcess ` + -FilePath "$androidHome\tools\android.bat" ` + -ArgumentList @("update sdk", + "-u", + "-a", + "--filter $($packagesToInstall -join ",")") + + $newLine = '' + while (-not $process.StandardOutput.EndOfStream) + { + # we need to read one char at a time, and when we encounter newline, then we pipe it out as output. + $rawVal = $process.StandardOutput.Read() + + if ($rawVal -eq -1) + { + break; + } + + $oneChar = [char]$rawVal + + # check for new line. + if ($rawVal -eq 10) + { + add-content $logFile "$newLine$([Environment]::NewLine)" + $newLine = '' + } + else + { + $newLine = $newLine + $oneChar + + if ($newLine -match 'Done. \d+ packages installed.') + { + break + } + + # if it match the sentenses + if ($newLine.StartsWith("Do you accept the license", "InvariantCultureIgnoreCase")) + { + $process.StandardInput.WriteLine("y") + + # read the remainder of the line. + $remainder = $process.StandardOutput.ReadLine(); + add-content $logFile "$newLine$remainder" + $newLine = '' + } + if ($newLine.StartsWith("A folder failed to be moved.", "InvariantCultureIgnoreCase")) + { + $process.StandardInput.WriteLine("n") + + # read the remaider of the line. + $remainder = $process.StandardOutput.ReadLine(); + add-content $logFile "$newLine$remainder" + $newLine = '' + + Set-InstallResult -Succeeded $false -Details The process cannot access the file because another process has locked a portion of the file. -ReturnCode 33 + exit + } + } + } + + # needs to kill adb process here because if SecondaryInstaller is launched via ARP, adb + # server will be launched and prevent ARP from installing other things. + # need to have -erroraction silentlycontinue, otherwise we'll get an error when adb doesn't exist + $processAdb = Get-Process adb -erroraction silentlycontinue + if ($processAdb) + { + $processAdb.Kill() + } + if (!$process.HasExited) + { + $process.CloseMainWindow() + } + $process.Dispose() +} + +# If there aren't any AVDs present on the system create one. +if (-not $anyAVDsFound) +{ + $deviceDefinition = Get-PreferredAVDDeviceDefinition + + if ($deviceDefinition -and $currentApiLevel) + { + $defaultAVDName = "AVD_$($deviceDefinition -replace ' ', '')_ToolsForApacheCordova" + + Create-AVD ` + -Name $defaultAVDName ` + -DeviceDefinition $deviceDefinition ` + -ConfigurationOptions @{"hw.keyboard" = "yes"; + "hw.ramSize" = "768"; + "vm.heapSize" = "64"} + } +} + +if ($packagesNotFound) +{ + add-content $logFile "WARNING: The following package(s) were not found:" + add-content $logFile "$(Format-PackageList $packagesNotFound)" + + # return code ERROR_BAD_NETPATH 53 + Set-InstallResult -Succeeded $false -Details "The following package(s) were not downloaded: $packagesNotFound . Please check your internet connection and try again." -ReturnCode 53 + exit +} + +Set-InstalledPackages $packagesToInstall $Operation + +add-content $logFile "Android SDK Install is successful." + +# Get End Time +$endDTM = (Get-Date) +add-content $logFile "Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds" + +Set-InstallResult -Succeeded $true diff --git a/Tools/verify-settings.ps1 b/Tools/verify-settings.ps1 new file mode 100644 index 0000000000..bb419ddeba --- /dev/null +++ b/Tools/verify-settings.ps1 @@ -0,0 +1,279 @@ +<# + This script attempts to find the tools required to build Autorest, and + if necessary sets the required environment variables and PATH settings + (in the current process) + + When finding a tool, it scans the PATH, then can look recursively in folders + for the tools. + + When it finds a tool, it will remember it by sticking an entry into the + registry. + + -reset will nuke the remembered tools. +#> + +param ( + [Switch] $reset # will nuke the remembered tools. + ) + +if( $reset ) { + rmdir -recurse -force -ea 0 "HKCU:\Software\KnownTools" +} + +function exists($file) { + return ($file -and (test-path -PathType Leaf $file )) +} + +function Read-PEHeader ($exe) { + if( exists $exe ) { + try { + [byte[]]$data = New-Object -TypeName System.Byte[] -ArgumentList 4096 + $stream = New-Object -TypeName System.IO.FileStream -ArgumentList ($exe, 'Open', 'Read') + $stream.Read($data, 0, 4096) | Out-Null + } finally { + $stream.Close(); + } + return $data; + } +} + +function Get-Architecture ($exe) { + $data = Read-PEHeader $exe + if( $data -and ([System.BitConverter]::ToInt16($data,0) -eq 23117 )) { + [int32]$MACHINE_OFFSET = 4 + [int32]$PE_POINTER_OFFSET = 60 + [int32]$PE_HEADER_ADDR = [System.BitConverter]::ToInt32($data, $PE_POINTER_OFFSET) + + switch ([System.BitConverter]::ToUInt16($data, $PE_HEADER_ADDR + $MACHINE_OFFSET)) { + 0 { return 'Native' } + 0x014c { return 'x86' } + 0x0200 { return 'Itanium' } + 0x8664 { return 'x64' } + } + } + return 'Unknown' +} + +function Any { + [CmdletBinding()] + param( [Parameter(Mandatory = $True)] $Condition, [Parameter(Mandatory = $True, ValueFromPipeline = $True)] $Item ) + begin { $isMatch = $False } + process { if (& $Condition $Item) { $isMatch = $true } } + end { $isMatch } +} + +function All { + [CmdletBinding()] + param( [Parameter(Mandatory = $True)] $Condition, [Parameter(Mandatory = $True, ValueFromPipeline = $True)] $Item ) + begin { $isMatch = $true } + process { if (-not ($isMatch -and (& $Condition $Item)) ) {$isMatch = $false} } + end { $isMatch } +} + +function Includes { param( [string] $i, [string[]] $all ) $all | All { $i -match $_ } } +function Excludes { param( [string] $i, [string[]] $all ) $all | All { -not ($i -match $_) } } + +function Validate ( + [string] $exe, + [string] $arch, + [string[]] $include, + [string[]] $exclude, + [string] $minimumVersion ) { + + if(exists $exe ) { + $file = dir $exe + + if( -not (Includes $file $include) ) { + return $false + } + + if( -not (Excludes $file $exclude) ) { + return $false + } + + if( $arch -and $arch -ne (Get-Architecture $file) ) { + return $false + } + + if( $minimumVersion -and (([system.version]$minimumVersion) -gt $file.VersionInfo.FileVersion ) ) { + return $false + } + + return $file + } + return $false +} + +function which( + [string]$cmd, + [string]$arch, + [string[]] $include = @(), + [string[]] $exclude= @('arm','_x86','x86_', 'shared'), + [string] $minimumVersion = $null) { + + if( $env:path ) { + foreach( $dir in $env:path.Split(";")) { + foreach( $ext in (";.ps1;"+$env:pathext).split(";")) { + if( $dir -and (resolve-path $dir) ) { + $p = join-path $dir "$cmd$ext" + if( exists $p ) { + if( Validate -exe $p $arch $include $exclude $minimumVersion ) { + return (dir $p) + } + } + } + } + } + } +} + +function find-exe ( + [string] $exe, + [string] $arch, + [string[]] $folders = @("${env:ProgramFiles(x86)}","${env:ProgramFiles}"), + [string[]] $include = @(), + [string[]] $exclude= @('arm','_x86','x86_','shared'), + [string] $minimumVersion = $null + ) { + + # find exe on path + $result = which $exe $arch $include $exclude $minimumVersion + if( $result ) { + return $result + } + + # not in path. check registry + $kt = "HKCU:\Software\KnownTools" + if( $arch ) { + $kt += "\$arch" + } + + if( $minimumVersion ) { + $kt += "\$minimumVersion" + try { $minimumVersion = [system.version]$minimumVersion } catch { + try { + $minimumVersion = [system.version]($minimumVersion + ".0") + } catch { + write-error "Bad Version $minimumVersion" + return; + } + } + } + + if( $result = Validate -exe ((Get-ItemProperty -Path "$kt\$exe" -Name Path -ea 0).Path) $arch $include $exclude $minimumVersion) { + return $result + } + + if( -not $result -or -not (exists $result )) { + write-host -fore yellow "Searching for $exe" + $result = ($folders |% {cmd "/c dir /s/b `"$_\$exe`" 2>nul" | dir }) ` + |% { Validate -exe $_ $arch $include $exclude $minimumVersion } ` + |? { $_ -ne $false } ` + | Sort-Object -Descending { $_.VersionInfo.FileVersion } ` + | Select-Object -first 1 + + if( $result ) { + $result = $result.FullName + $null = mkdir -Path "$kt\$exe" -Force + $null = New-ItemProperty -Path "$kt\$exe" -Name Path -Value $result -force + } + } + if( $result ) { + return (dir $result) + } +} + +$failing = $false + +function Find-OrAdd ( $cmd , $folders = @("${env:ProgramFiles(x86)}","${env:ProgramFiles}"), $hint = $null ) { + if( !($exe = which $cmd) ) { + $exe = find-exe $cmd -folders $folders + if( $exe) { + write-host "Adding '$($exe.Directory)' to PATH". + # $env:PATH="$env:PATH;$($exe.Directory)" + $env:PATH="$($exe.Directory);$env:PATH" + } else { + write-host -fore red "Unable to find '$cmd' in path/search folders" + if( $hint ) { + write-host -fore yellow "HINT: $hint" + } + $script:failing = $true + + } + } +} + +Function Get-AndroidHomeFromRegistry +{ + # if ([Environment]::Is64BitOperatingSystem) + # powershell v1 doesn't have is 64 bit flag. + if ([environment]::GetEnvironmentVariable("ProgramFiles(x86)")) + { + $androidRegistryKey = "HKLM:\SOFTWARE\Wow6432Node\Android SDK Tools" + } + else + { + $androidRegistryKey = "HKLM:\SOFTWARE\Android SDK Tools" + } + + if (Test-Path $androidRegistryKey) + { + $path = (Get-ItemProperty $androidRegistryKey Path).Path + + if (-not (Test-Path $path)) + { + $path = $null + } + } + + return $path +} + +find-orAdd "dotnet.exe" -hint "See: https://www.microsoft.com/net/core#windows" +find-orAdd "msbuild.exe" -hint "Install Visual studio 2015" + +find-orAdd "javac.exe" -hint "Download and install JAVA JDK" + +find-orAdd "node.exe" -hint "See: https://nodejs.org" +find-orAdd "gulp.cmd" -hint "maybe use 'npm install -g gulp'" + +find-orAdd "ruby.exe" (@() + ((dir -ea 0 c:\ruby*).fullname) + @( "${env:ProgramFiles(x86)}","${env:ProgramFiles}","c:\tools")) -hint "see http://rubyinstaller.org/downloads/" + +find-orAdd "gradle.bat" ( @( "${env:ProgramFiles(x86)}","${env:ProgramFiles}","c:\tools")) -hint "see http://gradle.org/gradle-download/" + +find-orAdd "python.exe" (@() + ((dir -ea 0 c:\python*).fullname) + @( "${env:ProgramFiles(x86)}","${env:ProgramFiles}","c:\tools")) -hint "https://www.python.org/downloads/" +find-orAdd "tox.exe" (@() + ((dir -ea 0 c:\python*).fullname) + @( "${env:ProgramFiles(x86)}","${env:ProgramFiles}","c:\tools")) -hint "maybe use 'pip install tox'" + + +# + +# make sure JAVA_HOME is set +if( (!$env:JAVA_HOME) -or (!(test-path -PathType Container $env:JAVA_HOME )) ) { + $javac = which javac.exe + if( $javac ) { + $env:JAVA_HOME = (get-item ("$javac\..\..")) + write-host "Setting JAVA_HOME to $ENV:JAVA_HOME". + } else { + write-host -fore red "Environment variable JAVA_HOME not set correctly." + $failing = $true + } +} + +# use this to add the missing SDK +# .\Install-AndroidSDK.ps1 -RequestedAndroidPackages android-23 -apilevel 23 + +if( (!$env:ANDROID_HOME) -or (!(test-path -PathType Container $env:ANDROID_HOME )) ) { + $android = Get-AndroidHomeFromRegistry + if (! $android ) { + write-host -fore red "Environment variable ANDROID_HOME not set correctly." + $failing = $true + } else { + $env:ANDROID_HOME= $android + } +} + +if( !$failing ) { + write-host -fore green "`n`nTools/Environment are OK" +} else { + write-host -fore red "`n`nTools/Environment are not OK" +}