From 017e11ec7a9559648152711a43f91b53c7bf8b55 Mon Sep 17 00:00:00 2001 From: Linus789 Date: Wed, 22 Feb 2023 07:27:03 +0100 Subject: [PATCH] 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 --- adb/device.go | 51 +++++++++++++++++++++++++++++++++++++++++++-------- install.go | 46 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/adb/device.go b/adb/device.go index 9d0d19b..d43895b 100644 --- a/adb/device.go +++ b/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") +} diff --git a/install.go b/install.go index 07c7905..60c652e 100644 --- a/install.go +++ b/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 (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) } }