Browse Source

install: finish implementation of -user

new default for installing: current user
new default for upgrading: only for those users who have the app installed

related issue: #37
pull/70/head
Linus789 3 years ago
parent
commit
017e11ec7a
  1. 51
      adb/device.go
  2. 46
      install.go

51
adb/device.go

@ -221,17 +221,19 @@ func (d *Device) Uninstall(pkg string) error {
}
type Package struct {
ID string
VersCode int
VersName string
IsSystem bool
ID string
VersCode int
VersName string
IsSystem bool
InstalledForUsers []int
}
var (
packageRegex = regexp.MustCompile(`^ Package \[([^\s]+)\]`)
verCodeRegex = regexp.MustCompile(`^ versionCode=([0-9]+)`)
verNameRegex = regexp.MustCompile(`^ versionName=(.+)`)
systemRegex = regexp.MustCompile(`^ pkgFlags=\[.*\bSYSTEM\b.*\]`)
packageRegex = regexp.MustCompile(`^ Package \[([^\s]+)\]`)
verCodeRegex = regexp.MustCompile(`^ versionCode=([0-9]+)`)
verNameRegex = regexp.MustCompile(`^ versionName=(.+)`)
systemRegex = regexp.MustCompile(`^ pkgFlags=\[.*\bSYSTEM\b.*\]`)
installedUsersRegex = regexp.MustCompile(`^ User (\d+): .*installed=true`)
)
func (d *Device) Installed() (map[string]Package, error) {
@ -256,6 +258,7 @@ func (d *Device) Installed() (map[string]Package, error) {
packages[cur.ID] = cur
cur = Package{}
cur.IsSystem = false
cur.InstalledForUsers = make([]int, 0)
}
cur.ID = m[1]
} else if m := verCodeRegex.FindStringSubmatch(l); m != nil {
@ -268,6 +271,12 @@ func (d *Device) Installed() (map[string]Package, error) {
cur.VersName = m[1]
} else if systemRegex.MatchString(l) {
cur.IsSystem = true
} else if m := installedUsersRegex.FindStringSubmatch(l); m != nil {
n, err := strconv.Atoi(m[1])
if err != nil {
panic(err)
}
cur.InstalledForUsers = append(cur.InstalledForUsers, n)
}
}
if !first {
@ -275,3 +284,29 @@ func (d *Device) Installed() (map[string]Package, error) {
}
return packages, nil
}
var currentUserIdRegex = regexp.MustCompile(`^ *mUserLru: \[.*\b(\d+)\b\]`)
func (d *Device) CurrentUserId() (int, error) {
cmd := d.AdbShell("dumpsys", "activity")
stdout, err := cmd.StdoutPipe()
if err != nil {
return -1, err
}
if err := cmd.Start(); err != nil {
return -1, err
}
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
m := currentUserIdRegex.FindStringSubmatch(scanner.Text())
if m == nil {
continue
}
n, err := strconv.Atoi(m[1])
if err != nil {
panic(err)
}
return n, nil
}
return -1, fmt.Errorf("could not get current user id")
}

46
install.go

@ -8,6 +8,7 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
"mvdan.cc/fdroidcl/adb"
@ -31,7 +32,7 @@ var (
installDryRun = cmdInstall.Fset.Bool("n", false, "Only print the operations that would be done")
installUpdatesExclude = cmdInstall.Fset.String("e", "", "Exclude apps from upgrading (comma-separated list)")
installSkipError = cmdInstall.Fset.Bool("s", false, "Skip to the next application if a download or install error occurs")
installUser = cmdInstall.Fset.String("user", "", "Only install for specified user")
installUser = cmdInstall.Fset.String("user", "", "Install for specified user <USER_ID|current|all> (default: \"current\" for installing, and upgrading only for users who have the app installed)")
)
func init() {
@ -49,6 +50,13 @@ func runInstall(args []string) error {
if err != nil {
return err
}
if *installUser == "current" || (*installUser == "" && !*installUpdates) {
uid, err := device.CurrentUserId()
if err != nil {
return err
}
*installUser = strconv.Itoa(uid)
}
inst, err := device.Installed()
if err != nil {
return err
@ -81,7 +89,7 @@ func runInstall(args []string) error {
if len(apps) == 0 {
fmt.Fprintln(os.Stderr, "All apps up to date.")
}
return downloadAndDo(apps, device)
return downloadAndDo(apps, inst, device)
}
if len(args) == 0 {
@ -131,12 +139,13 @@ func runInstall(args []string) error {
// upgrading an existing app
toInstall = append(toInstall, app)
}
return downloadAndDo(toInstall, device)
return downloadAndDo(toInstall, inst, device)
}
func downloadAndDo(apps []fdroid.App, device *adb.Device) error {
func downloadAndDo(apps []fdroid.App, installed map[string]adb.Package, device *adb.Device) error {
type downloaded struct {
apk *fdroid.Apk
app fdroid.App
path string
}
toInstall := make([]downloaded, 0)
@ -157,13 +166,17 @@ func downloadAndDo(apps []fdroid.App, device *adb.Device) error {
}
return err
}
toInstall = append(toInstall, downloaded{apk: apk, path: path})
toInstall = append(toInstall, downloaded{apk: apk, app: app, path: path})
}
if *installDryRun {
return nil
}
for _, t := range toInstall {
if err := installApk(device, t.apk, t.path); err != nil {
var installedPkg *adb.Package = nil
if p, e := installed[t.app.PackageName]; e {
installedPkg = &p
}
if err := installApk(device, t.apk, installedPkg, t.path); err != nil {
if *installSkipError {
fmt.Printf("Installing %s failed, skipping...\n", t.apk.AppID)
continue
@ -174,14 +187,27 @@ func downloadAndDo(apps []fdroid.App, device *adb.Device) error {
return nil
}
func installApk(device *adb.Device, apk *fdroid.Apk, path string) error {
func installApk(device *adb.Device, apk *fdroid.Apk, devicePkg *adb.Package, path string) error {
fmt.Printf("Installing %s\n", apk.AppID)
if *installUser != "" {
if err := device.InstallUser(path, *installUser); err != nil {
userId := "all"
if *installUser != "all" {
if *installUpdates && *installUser == "" {
if devicePkg == nil {
return fmt.Errorf("failed to get device package although it should be installed (please report this error)")
}
if len((*devicePkg).InstalledForUsers) > 0 {
userId = strconv.Itoa((*devicePkg).InstalledForUsers[0])
}
} else {
userId = *installUser
}
}
if userId == "all" {
if err := device.Install(path); err != nil {
return fmt.Errorf("could not install %s: %v", apk.AppID, err)
}
} else {
if err := device.Install(path); err != nil {
if err := device.InstallUser(path, userId); err != nil {
return fmt.Errorf("could not install %s: %v", apk.AppID, err)
}
}

Loading…
Cancel
Save