Files
httprunner/hrp/pkg/gidevice/crashreportmover.go
2022-10-23 22:59:34 +08:00

170 lines
3.8 KiB
Go

package gidevice
import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"howett.net/plist"
"github.com/httprunner/httprunner/v4/hrp/pkg/gidevice/pkg/libimobiledevice"
)
var _ CrashReportMover = (*crashReportMover)(nil)
func newCrashReportMover(client *libimobiledevice.CrashReportMoverClient) *crashReportMover {
return &crashReportMover{
client: client,
}
}
type crashReportMover struct {
client *libimobiledevice.CrashReportMoverClient
afc Afc
}
func (c *crashReportMover) readPing() (err error) {
var data []byte
if data, err = c.client.InnerConn().Read(4); err != nil {
return err
}
if string(data) != "ping" {
return fmt.Errorf("crashReportMover ping: %v", data)
}
return
}
func (c *crashReportMover) Move(hostDir string, opts ...CrashReportMoverOption) (err error) {
opt := defaultCrashReportMoverOption()
for _, fn := range opts {
fn(opt)
}
toExtract := make([]string, 0, 64)
fn := func(cwd string, info *AfcFileInfo) {
if info.IsDir() {
return
}
if cwd == "." {
cwd = ""
}
devFilename := path.Join(cwd, info.Name())
hostElem := strings.Split(devFilename, "/")
hostFilename := filepath.Join(hostDir, filepath.Join(hostElem...))
hostFilename = strings.TrimSuffix(hostFilename, ".synced")
if opt.extract && strings.HasSuffix(hostFilename, ".plist") {
toExtract = append(toExtract, hostFilename)
}
var afcFile *AfcFile
if afcFile, err = c.afc.Open(devFilename, AfcFileModeRdOnly); err != nil {
debugLog(fmt.Sprintf("crashReportMover open %s: %s", devFilename, err))
return
}
defer func() {
if err = afcFile.Close(); err != nil {
debugLog(fmt.Sprintf("crashReportMover device file close: %s", err))
}
}()
if err = os.MkdirAll(filepath.Dir(hostFilename), 0o755); err != nil {
debugLog(fmt.Sprintf("crashReportMover mkdir %s: %s", filepath.Dir(hostFilename), err))
return
}
var hostFile *os.File
if hostFile, err = os.Create(hostFilename); err != nil {
debugLog(fmt.Sprintf("crashReportMover create %s: %s", hostFilename, err))
return
}
defer func() {
if err = hostFile.Close(); err != nil {
debugLog(fmt.Sprintf("crashReportMover host file close: %s", err))
}
}()
if _, err = io.Copy(hostFile, afcFile); err != nil {
debugLog(fmt.Sprintf("crashReportMover copy %s", err))
return
}
opt.whenDone(devFilename)
if opt.keep {
return
}
if err = c.afc.Remove(devFilename); err != nil {
debugLog(fmt.Sprintf("crashReportMover remove %s: %s", devFilename, err))
return
}
}
if err = c.walkDir(".", fn); err != nil {
return err
}
if !opt.extract {
return nil
}
for _, name := range toExtract {
data, err := os.ReadFile(name)
if err != nil {
debugLog(fmt.Sprintf("crashReportMover extract read %s: %s", name, err))
continue
}
m := make(map[string]interface{})
if _, err = plist.Unmarshal(data, &m); err != nil {
debugLog(fmt.Sprintf("crashReportMover extract plist %s: %s", name, err))
continue
}
desc, ok := m["description"]
if !ok {
continue
}
hostExtCrash := strings.TrimSuffix(name, ".plist") + ".crash"
if err = os.WriteFile(hostExtCrash, []byte(fmt.Sprintf("%v", desc)), 0o755); err != nil {
debugLog(fmt.Sprintf("crashReportMover extract save %s: %s", name, err))
continue
}
}
return
}
func (c *crashReportMover) walkDir(dirname string, fn func(path string, info *AfcFileInfo)) (err error) {
var names []string
if names, err = c.afc.ReadDir(dirname); err != nil {
return err
}
cwd := dirname
for _, n := range names {
if n == "." || n == ".." {
continue
}
var info *AfcFileInfo
if info, err = c.afc.Stat(path.Join(cwd, n)); err != nil {
return err
}
if info.IsDir() {
if err = c.walkDir(path.Join(cwd, info.name), fn); err != nil {
return err
}
}
fn(cwd, info)
}
return
}