90 lines
2.7 KiB
Go
90 lines
2.7 KiB
Go
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// Package sdkpath provides functions for locating the Android SDK.
|
||
|
// These functions respect the ANDROID_HOME environment variable, and
|
||
|
// otherwise use the default SDK location.
|
||
|
package sdkpath
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// AndroidHome returns the absolute path of the selected Android SDK,
|
||
|
// if one can be found.
|
||
|
func AndroidHome() (string, error) {
|
||
|
androidHome := os.Getenv("ANDROID_HOME")
|
||
|
if androidHome == "" {
|
||
|
home, err := os.UserHomeDir()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
switch runtime.GOOS {
|
||
|
case "windows":
|
||
|
// See https://android.googlesource.com/platform/tools/adt/idea/+/85b4bfb7a10ad858a30ffa4003085b54f9424087/native/installer/win/setup_android_studio.nsi#100
|
||
|
androidHome = filepath.Join(home, "AppData", "Local", "Android", "sdk")
|
||
|
case "darwin":
|
||
|
// See https://android.googlesource.com/platform/tools/asuite/+/67e0cd9604379e9663df57f16a318d76423c0aa8/aidegen/lib/ide_util.py#88
|
||
|
androidHome = filepath.Join(home, "Library", "Android", "sdk")
|
||
|
default: // Linux, BSDs, etc.
|
||
|
// See LINUX_ANDROID_SDK_PATH in ide_util.py above.
|
||
|
androidHome = filepath.Join(home, "Android", "Sdk")
|
||
|
}
|
||
|
}
|
||
|
if info, err := os.Stat(androidHome); err != nil {
|
||
|
return "", fmt.Errorf("%w; Android SDK was not found at %s", err, androidHome)
|
||
|
} else if !info.IsDir() {
|
||
|
return "", fmt.Errorf("%s is not a directory", androidHome)
|
||
|
}
|
||
|
return androidHome, nil
|
||
|
}
|
||
|
|
||
|
// AndroidAPIPath returns an android SDK platform directory within the configured SDK.
|
||
|
// If there are multiple platforms that satisfy the minimum version requirement,
|
||
|
// AndroidAPIPath returns the latest one among them.
|
||
|
func AndroidAPIPath(api int) (string, error) {
|
||
|
sdk, err := AndroidHome()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
sdkDir, err := os.Open(filepath.Join(sdk, "platforms"))
|
||
|
if err != nil {
|
||
|
return "", fmt.Errorf("failed to find android SDK platform: %w", err)
|
||
|
}
|
||
|
defer sdkDir.Close()
|
||
|
fis, err := sdkDir.Readdir(-1)
|
||
|
if err != nil {
|
||
|
return "", fmt.Errorf("failed to find android SDK platform (API level: %d): %w", api, err)
|
||
|
}
|
||
|
|
||
|
var apiPath string
|
||
|
var apiVer int
|
||
|
for _, fi := range fis {
|
||
|
name := fi.Name()
|
||
|
if !strings.HasPrefix(name, "android-") {
|
||
|
continue
|
||
|
}
|
||
|
n, err := strconv.Atoi(name[len("android-"):])
|
||
|
if err != nil || n < api {
|
||
|
continue
|
||
|
}
|
||
|
p := filepath.Join(sdkDir.Name(), name)
|
||
|
_, err = os.Stat(filepath.Join(p, "android.jar"))
|
||
|
if err == nil && apiVer < n {
|
||
|
apiPath = p
|
||
|
apiVer = n
|
||
|
}
|
||
|
}
|
||
|
if apiVer == 0 {
|
||
|
return "", fmt.Errorf("failed to find android SDK platform (API level: %d) in %s",
|
||
|
api, sdkDir.Name())
|
||
|
}
|
||
|
return apiPath, nil
|
||
|
}
|