-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
send android artifact's module, product flavour and build type (#100)
* send android artifct's module, product flavour and build type * new tests * parse multiple falvours * PR fix * better example for parseAppPath * handle -unsigned suffix in artifact path * parse android artifacts, include split meta * artifact info models * mark bundle of the split * aab support in artifact meta * refactors + dep update * introduce Artifact * always return split meta * pr fix, bundle's universal apk name fix, bundle's universal apk name test, loging updates * wire in renameUniversalAPK func * generating apk from aab mooved to the main package; generate or find universal apk pairs for aabs; android artifact path parsing logic moved to the androidartifact package * improved FindSameArtifact and tests * new tests * pr fixes * pr fixes * BundleTool fixes * PR fixes
- Loading branch information
Showing
16 changed files
with
1,599 additions
and
257 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/bitrise-io/go-utils/command" | ||
"github.com/bitrise-io/go-utils/errorutil" | ||
"github.com/bitrise-io/go-utils/pathutil" | ||
"github.com/bitrise-steplib/steps-deploy-to-bitrise-io/androidartifact" | ||
"github.com/bitrise-steplib/steps-deploy-to-bitrise-io/bundletool" | ||
) | ||
|
||
// handleError creates error with layout: `<cmd> failed (status: <status_code>): <cmd output>`. | ||
func handleError(cmd, out string, err error) error { | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
msg := fmt.Sprintf("%s failed", cmd) | ||
if status, exitCodeErr := errorutil.CmdExitCodeFromError(err); exitCodeErr == nil { | ||
msg += fmt.Sprintf(" (status: %d)", status) | ||
} | ||
if len(out) > 0 { | ||
msg += fmt.Sprintf(": %s", out) | ||
} | ||
return errors.New(msg) | ||
} | ||
|
||
// run executes a given command. | ||
func run(cmd *command.Model) error { | ||
out, err := cmd.RunAndReturnTrimmedCombinedOutput() | ||
return handleError(cmd.PrintableCommandArgs(), out, err) | ||
} | ||
|
||
// generateKeystore creates a debug keystore. | ||
func generateKeystore(tmpPth string) (string, error) { | ||
pth := filepath.Join(tmpPth, "debug.keystore") | ||
return pth, run(command.New("keytool", "-genkey", "-v", | ||
"-keystore", pth, | ||
"-storepass", "android", | ||
"-alias", "androiddebugkey", | ||
"-keypass", "android", | ||
"-keyalg", "RSA", | ||
"-keysize", "2048", | ||
"-validity", "10000", | ||
"-dname", "C=US, O=Android, CN=Android Debug", | ||
)) | ||
} | ||
|
||
// buildApksArchive generates universal apks from an aab file. | ||
func buildApksArchive(bundleTool bundletool.Path, tmpPth, aabPth, keystorePath string) (string, error) { | ||
pth := filepath.Join(tmpPth, "universal.apks") | ||
return pth, run(bundleTool.Command("build-apks", "--mode=universal", | ||
"--bundle", aabPth, | ||
"--output", pth, | ||
"--ks", keystorePath, | ||
"--ks-pass", "pass:android", | ||
"--ks-key-alias", "androiddebugkey", | ||
"--key-pass", "pass:android", | ||
)) | ||
} | ||
|
||
// unzipUniversalAPKsArchive unzips an universal apks archive. | ||
func unzipUniversalAPKsArchive(archive, destDir string) (string, error) { | ||
return filepath.Join(destDir, "universal.apk"), run(command.New("unzip", archive, "-d", destDir)) | ||
} | ||
|
||
// GenerateUniversalAPK generates universal apks from an aab file. | ||
func GenerateUniversalAPK(aabPth string) (string, error) { | ||
r, err := bundletool.New() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
tmpPth, err := pathutil.NormalizedOSTempDirPath("aab-bundle") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
keystorePath, err := generateKeystore(tmpPth) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
apksPth, err := buildApksArchive(r, tmpPth, aabPth, keystorePath) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
universalAPKPath, err := unzipUniversalAPKsArchive(apksPth, tmpPth) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
renamedUniversalAPKPath := filepath.Join(tmpPth, androidartifact.UniversalAPKBase(aabPth)) | ||
return renamedUniversalAPKPath, os.Rename(universalAPKPath, renamedUniversalAPKPath) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package androidartifact | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/bitrise-io/go-android/sdk" | ||
"github.com/bitrise-io/go-utils/command" | ||
) | ||
|
||
// ApkInfo ... | ||
type ApkInfo struct { | ||
AppName string | ||
PackageName string | ||
VersionCode string | ||
VersionName string | ||
MinSDKVersion string | ||
RawPackageContent string | ||
} | ||
|
||
// parseAppName parses the application name from `aapt dump badging` command output. | ||
func parseAppName(aaptOut string) string { | ||
pattern := `application: label=\'(?P<label>.+)\' icon=` | ||
re := regexp.MustCompile(pattern) | ||
if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 { | ||
return matches[1] | ||
} | ||
|
||
pattern = `application-label:\'(?P<label>.*)\'` | ||
re = regexp.MustCompile(pattern) | ||
if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 { | ||
return matches[1] | ||
} | ||
|
||
return "" | ||
} | ||
|
||
// parseMinSDKVersion parses the min sdk version from `aapt dump badging` command output. | ||
func parseMinSDKVersion(aaptOut string) string { | ||
pattern := `sdkVersion:\'(?P<min_sdk_version>.*)\'` | ||
re := regexp.MustCompile(pattern) | ||
if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 { | ||
return matches[1] | ||
} | ||
return "" | ||
} | ||
|
||
// parsePackageField parses fields from `aapt dump badging` command output. | ||
func parsePackageField(aaptOut, key string) string { | ||
pattern := fmt.Sprintf(`%s=['"](.*?)['"]`, key) | ||
|
||
re := regexp.MustCompile(pattern) | ||
if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 { | ||
return matches[1] | ||
} | ||
|
||
return "" | ||
} | ||
|
||
// ParsePackageInfos parses package name, version code and name from `aapt dump badging` command output. | ||
func ParsePackageInfos(aaptOut string) (string, string, string) { | ||
return parsePackageField(aaptOut, "name"), | ||
parsePackageField(aaptOut, "versionCode"), | ||
parsePackageField(aaptOut, "versionName") | ||
} | ||
|
||
// GetAPKInfo returns infos about the APK. | ||
func GetAPKInfo(apkPth string) (ApkInfo, error) { | ||
androidHome := os.Getenv("ANDROID_HOME") | ||
if androidHome == "" { | ||
return ApkInfo{}, errors.New("ANDROID_HOME environment not set") | ||
} | ||
|
||
sdkModel, err := sdk.New(androidHome) | ||
if err != nil { | ||
return ApkInfo{}, fmt.Errorf("failed to create sdk model, error: %s", err) | ||
} | ||
|
||
aaptPth, err := sdkModel.LatestBuildToolPath("aapt") | ||
if err != nil { | ||
return ApkInfo{}, fmt.Errorf("failed to find latest aapt binary, error: %s", err) | ||
} | ||
|
||
aaptOut, err := command.New(aaptPth, "dump", "badging", apkPth).RunAndReturnTrimmedCombinedOutput() | ||
if err != nil { | ||
return ApkInfo{}, fmt.Errorf("failed to get apk infos, output: %s, error: %s", aaptOut, err) | ||
} | ||
|
||
appName := parseAppName(aaptOut) | ||
packageName, versionCode, versionName := ParsePackageInfos(aaptOut) | ||
minSDKVersion := parseMinSDKVersion(aaptOut) | ||
|
||
packageContent := "" | ||
for _, line := range strings.Split(aaptOut, "\n") { | ||
if strings.HasPrefix(line, "package:") { | ||
packageContent = line | ||
} | ||
} | ||
|
||
return ApkInfo{ | ||
AppName: appName, | ||
PackageName: packageName, | ||
VersionCode: versionCode, | ||
VersionName: versionName, | ||
MinSDKVersion: minSDKVersion, | ||
RawPackageContent: packageContent, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.