From 701ea3a2458c026ef34ec0dfa9c7c6ee90246563 Mon Sep 17 00:00:00 2001 From: Zach Klippenstein Date: Sun, 22 May 2016 10:49:32 -0700 Subject: [PATCH] Moved error definitions to an internal package, deleted the confusing util package. Public API for error querying and formatting lives in top-level package. --- adb.go | 4 +-- cmd/adb/main.go | 5 ++- cmd/demo/demo.go | 4 +-- device.go | 10 +++--- device_info.go | 8 ++--- device_state.go | 4 +-- device_test.go | 18 +++++------ device_watcher.go | 6 ++-- device_watcher_test.go | 14 ++++----- dialer.go | 4 +-- error.go | 35 +++++++++++++++++++++ {util => internal/errors}/errcode_string.go | 2 +- {util => internal/errors}/error.go | 3 +- {util => internal/errors}/error_test.go | 2 +- server.go | 14 ++++----- server_mock_test.go | 4 +-- sync_client.go | 12 +++---- sync_client_test.go | 4 +-- sync_file_reader.go | 6 ++-- sync_file_reader_test.go | 5 ++- sync_file_writer.go | 8 ++--- util.go | 10 +++--- util/doc.go | 4 --- wire/conn.go | 6 ++-- wire/scanner.go | 18 +++++------ wire/scanner_test.go | 12 +++---- wire/sender.go | 6 ++-- wire/sync_conn.go | 4 +-- wire/sync_scanner.go | 16 +++++----- wire/sync_sender.go | 26 +++++++-------- wire/sync_test.go | 4 +-- wire/util.go | 21 ++++++------- wire/util_test.go | 26 +++++++-------- 33 files changed, 177 insertions(+), 148 deletions(-) create mode 100644 error.go rename {util => internal/errors}/errcode_string.go (96%) rename {util => internal/errors}/error.go (98%) rename {util => internal/errors}/error_test.go (98%) delete mode 100644 util/doc.go diff --git a/adb.go b/adb.go index cdbbf40..fafb178 100644 --- a/adb.go +++ b/adb.go @@ -3,7 +3,7 @@ package adb import ( "strconv" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -137,7 +137,7 @@ func (c *Adb) parseServerVersion(versionRaw []byte) (int, error) { versionStr := string(versionRaw) version, err := strconv.ParseInt(versionStr, 16, 32) if err != nil { - return 0, util.WrapErrorf(err, util.ParseError, + return 0, errors.WrapErrorf(err, errors.ParseError, "error parsing server version: %s", versionStr) } return int(version), nil diff --git a/cmd/adb/main.go b/cmd/adb/main.go index d105736..07d5eac 100644 --- a/cmd/adb/main.go +++ b/cmd/adb/main.go @@ -10,7 +10,6 @@ import ( "github.com/cheggaaa/pb" "github.com/zach-klippenstein/goadb" - "github.com/zach-klippenstein/goadb/util" "gopkg.in/alecthomas/kingpin.v2" ) @@ -162,7 +161,7 @@ func pull(showProgress bool, remotePath, localPath string, device adb.DeviceDesc client := client.Device(device) info, err := client.Stat(remotePath) - if util.HasErrCode(err, util.FileNoExistError) { + if adb.HasErrCode(err, adb.ErrCode(adb.FileNoExistError)) { fmt.Fprintln(os.Stderr, "remote file does not exist:", remotePath) return 1 } else if err != nil { @@ -172,7 +171,7 @@ func pull(showProgress bool, remotePath, localPath string, device adb.DeviceDesc remoteFile, err := client.OpenRead(remotePath) if err != nil { - fmt.Fprintf(os.Stderr, "error opening remote file %s: %s\n", remotePath, util.ErrorWithCauseChain(err)) + fmt.Fprintf(os.Stderr, "error opening remote file %s: %s\n", remotePath, adb.ErrorWithCauseChain(err)) return 1 } defer remoteFile.Close() diff --git a/cmd/demo/demo.go b/cmd/demo/demo.go index b561f72..8de3ce5 100644 --- a/cmd/demo/demo.go +++ b/cmd/demo/demo.go @@ -9,7 +9,7 @@ import ( "time" adb "github.com/zach-klippenstein/goadb" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) var ( @@ -74,7 +74,7 @@ func main() { func printErr(err error) { switch err := err.(type) { - case *util.Err: + case *errors.Err: fmt.Println(err.Error()) if err.Cause != nil { fmt.Print("caused by ") diff --git a/device.go b/device.go index 594fcf9..7cfc91e 100644 --- a/device.go +++ b/device.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -72,7 +72,7 @@ func (c *Device) DeviceInfo() (*DeviceInfo, error) { } } - err = util.Errorf(util.DeviceNotFound, "device list doesn't contain serial %s", serial) + err = errors.Errorf(errors.DeviceNotFound, "device list doesn't contain serial %s", serial) return nil, wrapClientError(err, c, "DeviceInfo") } @@ -224,7 +224,7 @@ func (c *Device) dialDevice() (*wire.Conn, error) { req := fmt.Sprintf("host:%s", c.descriptor.getTransportDescriptor()) if err = wire.SendMessageString(conn, req); err != nil { conn.Close() - return nil, util.WrapErrf(err, "error connecting to device '%s'", c.descriptor) + return nil, errors.WrapErrf(err, "error connecting to device '%s'", c.descriptor) } if _, err = conn.ReadStatus(req); err != nil { @@ -239,12 +239,12 @@ func (c *Device) dialDevice() (*wire.Conn, error) { // arguments if required, and joins them into a valid adb command string. func prepareCommandLine(cmd string, args ...string) (string, error) { if isBlank(cmd) { - return "", util.AssertionErrorf("command cannot be empty") + return "", errors.AssertionErrorf("command cannot be empty") } for i, arg := range args { if strings.ContainsRune(arg, '"') { - return "", util.Errorf(util.ParseError, "arg at index %d contains an invalid double quote: %s", i, arg) + return "", errors.Errorf(errors.ParseError, "arg at index %d contains an invalid double quote: %s", i, arg) } if containsWhitespace(arg) { args[i] = fmt.Sprintf("\"%s\"", arg) diff --git a/device_info.go b/device_info.go index efd0242..6de96b2 100644 --- a/device_info.go +++ b/device_info.go @@ -4,7 +4,7 @@ import ( "bufio" "strings" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) type DeviceInfo struct { @@ -27,7 +27,7 @@ func (d *DeviceInfo) IsUsb() bool { func newDevice(serial string, attrs map[string]string) (*DeviceInfo, error) { if serial == "" { - return nil, util.AssertionErrorf("device serial cannot be blank") + return nil, errors.AssertionErrorf("device serial cannot be blank") } return &DeviceInfo{ @@ -57,7 +57,7 @@ func parseDeviceList(list string, lineParseFunc func(string) (*DeviceInfo, error func parseDeviceShort(line string) (*DeviceInfo, error) { fields := strings.Fields(line) if len(fields) != 2 { - return nil, util.Errorf(util.ParseError, + return nil, errors.Errorf(errors.ParseError, "malformed device line, expected 2 fields but found %d", len(fields)) } @@ -67,7 +67,7 @@ func parseDeviceShort(line string) (*DeviceInfo, error) { func parseDeviceLong(line string) (*DeviceInfo, error) { fields := strings.Fields(line) if len(fields) < 5 { - return nil, util.Errorf(util.ParseError, + return nil, errors.Errorf(errors.ParseError, "malformed device line, expected at least 5 fields but found %d", len(fields)) } diff --git a/device_state.go b/device_state.go index 17cb0ed..17e1dfa 100644 --- a/device_state.go +++ b/device_state.go @@ -1,6 +1,6 @@ package adb -import "github.com/zach-klippenstein/goadb/util" +import "github.com/zach-klippenstein/goadb/internal/errors" // DeviceState represents one of the 3 possible states adb will report devices. // A device can be communicated with when it's in StateOnline. @@ -26,7 +26,7 @@ var deviceStateStrings = map[string]DeviceState{ func parseDeviceState(str string) (DeviceState, error) { state, ok := deviceStateStrings[str] if !ok { - return StateInvalid, util.Errorf(util.ParseError, "invalid device state: %q", state) + return StateInvalid, errors.Errorf(errors.ParseError, "invalid device state: %q", state) } return state, nil } diff --git a/device_test.go b/device_test.go index 5df7416..29ec441 100644 --- a/device_test.go +++ b/device_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -47,8 +47,8 @@ func TestGetDeviceInfo(t *testing.T) { client = newDeviceClientWithDeviceLister("serial", deviceLister) device, err = client.DeviceInfo() - assert.True(t, util.HasErrCode(err, util.DeviceNotFound)) - assert.EqualError(t, err.(*util.Err).Cause, + assert.True(t, HasErrCode(err, DeviceNotFound)) + assert.EqualError(t, err.(*errors.Err).Cause, "DeviceNotFound: device list doesn't contain serial serial") assert.Nil(t, device) } @@ -84,13 +84,13 @@ func TestPrepareCommandLineNoArgs(t *testing.T) { func TestPrepareCommandLineEmptyCommand(t *testing.T) { _, err := prepareCommandLine("") - assert.Equal(t, util.AssertionError, code(err)) + assert.Equal(t, errors.AssertionError, code(err)) assert.Equal(t, "command cannot be empty", message(err)) } func TestPrepareCommandLineBlankCommand(t *testing.T) { _, err := prepareCommandLine(" ") - assert.Equal(t, util.AssertionError, code(err)) + assert.Equal(t, errors.AssertionError, code(err)) assert.Equal(t, "command cannot be empty", message(err)) } @@ -108,14 +108,14 @@ func TestPrepareCommandLineArgWithWhitespaceQuotes(t *testing.T) { func TestPrepareCommandLineArgWithDoubleQuoteFails(t *testing.T) { _, err := prepareCommandLine("cmd", "quoted\"arg") - assert.Equal(t, util.ParseError, code(err)) + assert.Equal(t, errors.ParseError, code(err)) assert.Equal(t, "arg at index 0 contains an invalid double quote: quoted\"arg", message(err)) } -func code(err error) util.ErrCode { - return err.(*util.Err).Code +func code(err error) errors.ErrCode { + return err.(*errors.Err).Code } func message(err error) string { - return err.(*util.Err).Message + return err.(*errors.Err).Message } diff --git a/device_watcher.go b/device_watcher.go index 3ae4fc4..1c7e6c8 100644 --- a/device_watcher.go +++ b/device_watcher.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -124,7 +124,7 @@ func publishDevices(watcher *deviceWatcherImpl) { return } - if util.HasErrCode(err, util.ConnectionResetError) { + if HasErrCode(err, ConnectionResetError) { // The server died, restart and reconnect. // Delay by a random [0ms, 500ms) in case multiple DeviceWatchers are trying to @@ -194,7 +194,7 @@ func parseDeviceStates(msg string) (states map[string]DeviceState, err error) { fields := strings.Split(line, "\t") if len(fields) != 2 { - err = util.Errorf(util.ParseError, "invalid device state line %d: %s", lineNum, line) + err = errors.Errorf(errors.ParseError, "invalid device state line %d: %s", lineNum, line) return } diff --git a/device_watcher_test.go b/device_watcher_test.go index ad73383..40acccd 100644 --- a/device_watcher_test.go +++ b/device_watcher_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -33,8 +33,8 @@ func TestParseDeviceStatesMalformed(t *testing.T) { 0x0x0x0x `) - assert.True(t, util.HasErrCode(err, util.ParseError)) - assert.Equal(t, "invalid device state line 1: 0x0x0x0x", err.(*util.Err).Message) + assert.True(t, HasErrCode(err, ParseError)) + assert.Equal(t, "invalid device state line 1: 0x0x0x0x", err.(*errors.Err).Message) } func TestCalculateStateDiffsUnchangedEmpty(t *testing.T) { @@ -210,8 +210,8 @@ func TestPublishDevicesRestartsServer(t *testing.T) { Status: wire.StatusSuccess, Errs: []error{ nil, nil, nil, // Successful dial. - util.Errorf(util.ConnectionResetError, "failed first read"), - util.Errorf(util.ServerNotAvailable, "failed redial"), + errors.Errorf(errors.ConnectionResetError, "failed first read"), + errors.Errorf(errors.ServerNotAvailable, "failed redial"), }, } watcher := deviceWatcherImpl{ @@ -224,8 +224,8 @@ func TestPublishDevicesRestartsServer(t *testing.T) { assert.Empty(t, server.Errs) assert.Equal(t, []string{"host:track-devices"}, server.Requests) assert.Equal(t, []string{"Dial", "SendMessage", "ReadStatus", "ReadMessage", "Start", "Dial"}, server.Trace) - err := watcher.err.Load().(*util.Err) - assert.Equal(t, util.ServerNotAvailable, err.Code) + err := watcher.err.Load().(*errors.Err) + assert.Equal(t, errors.ServerNotAvailable, err.Code) } func assertContainsOnly(t *testing.T, expected, actual []DeviceStateChangedEvent) { diff --git a/dialer.go b/dialer.go index 065fa2e..5b8274e 100644 --- a/dialer.go +++ b/dialer.go @@ -5,7 +5,7 @@ import ( "net" "runtime" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -21,7 +21,7 @@ type tcpDialer struct{} func (tcpDialer) Dial(address string) (*wire.Conn, error) { netConn, err := net.Dial("tcp", address) if err != nil { - return nil, util.WrapErrorf(err, util.ServerNotAvailable, "error dialing %s", address) + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "error dialing %s", address) } // net.Conn can't be closed more than once, but wire.Conn will try to close both sender and scanner diff --git a/error.go b/error.go new file mode 100644 index 0000000..1249472 --- /dev/null +++ b/error.go @@ -0,0 +1,35 @@ +package adb + +import "github.com/zach-klippenstein/goadb/internal/errors" + +type ErrCode errors.ErrCode + +const ( + AssertionError = ErrCode(errors.AssertionError) + ParseError = ErrCode(errors.ParseError) + // The server was not available on the requested port. + ServerNotAvailable = ErrCode(errors.ServerNotAvailable) + // General network error communicating with the server. + NetworkError = ErrCode(errors.NetworkError) + // The connection to the server was reset in the middle of an operation. Server probably died. + ConnectionResetError = ErrCode(errors.ConnectionResetError) + // The server returned an error message, but we couldn't parse it. + AdbError = ErrCode(errors.AdbError) + // The server returned a "device not found" error. + DeviceNotFound = ErrCode(errors.DeviceNotFound) + // Tried to perform an operation on a path that doesn't exist on the device. + FileNoExistError = ErrCode(errors.FileNoExistError) +) + +// HasErrCode returns true if err is an *errors.Err and err.Code == code. +func HasErrCode(err error, code ErrCode) bool { + return errors.HasErrCode(err, errors.ErrCode(code)) +} + +/* +ErrorWithCauseChain formats err and all its causes if it's an *errors.Err, else returns +err.Error(). +*/ +func ErrorWithCauseChain(err error) string { + return errors.ErrorWithCauseChain(err) +} diff --git a/util/errcode_string.go b/internal/errors/errcode_string.go similarity index 96% rename from util/errcode_string.go rename to internal/errors/errcode_string.go index 22f81cc..1eea249 100644 --- a/util/errcode_string.go +++ b/internal/errors/errcode_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=ErrCode"; DO NOT EDIT -package util +package errors import "fmt" diff --git a/util/error.go b/internal/errors/error.go similarity index 98% rename from util/error.go rename to internal/errors/error.go index 684ad50..dba3242 100644 --- a/util/error.go +++ b/internal/errors/error.go @@ -1,4 +1,4 @@ -package util +package errors import ( "bytes" @@ -31,6 +31,7 @@ type Err struct { var _ error = &Err{} +// Keep this in sync with ../error.go. //go:generate stringer -type=ErrCode type ErrCode byte diff --git a/util/error_test.go b/internal/errors/error_test.go similarity index 98% rename from util/error_test.go rename to internal/errors/error_test.go index 375515a..82c9227 100644 --- a/util/error_test.go +++ b/internal/errors/error_test.go @@ -1,4 +1,4 @@ -package util +package errors import ( "errors" diff --git a/server.go b/server.go index 2dc83b1..f5a91e7 100644 --- a/server.go +++ b/server.go @@ -1,13 +1,13 @@ package adb import ( - "errors" + stderrors "errors" "fmt" "os" "os/exec" "strings" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" "golang.org/x/sys/unix" ) @@ -76,12 +76,12 @@ func newServer(config ServerConfig) (server, error) { if config.PathToAdb == "" { path, err := config.fs.LookPath(AdbExecutableName) if err != nil { - return nil, util.WrapErrorf(err, util.ServerNotAvailable, "could not find %s in PATH", AdbExecutableName) + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "could not find %s in PATH", AdbExecutableName) } config.PathToAdb = path } if err := config.fs.IsExecutableFile(config.PathToAdb); err != nil { - return nil, util.WrapErrorf(err, util.ServerNotAvailable, "invalid adb executable: %s", config.PathToAdb) + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "invalid adb executable: %s", config.PathToAdb) } return &realServer{ @@ -97,7 +97,7 @@ func (s *realServer) Dial() (*wire.Conn, error) { if err != nil { // Attempt to start the server and try again. if err = s.Start(); err != nil { - return nil, util.WrapErrorf(err, util.ServerNotAvailable, "error starting server for dial") + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "error starting server for dial") } conn, err = s.config.Dial(s.address) @@ -112,7 +112,7 @@ func (s *realServer) Dial() (*wire.Conn, error) { func (s *realServer) Start() error { output, err := s.config.fs.CmdCombinedOutput(s.config.PathToAdb, "start-server") outputStr := strings.TrimSpace(string(output)) - return util.WrapErrorf(err, util.ServerNotAvailable, "error starting server: %s\noutput:\n%s", err, outputStr) + return errors.WrapErrorf(err, errors.ServerNotAvailable, "error starting server: %s\noutput:\n%s", err, outputStr) } // filesystem abstracts interactions with the local filesystem for testability. @@ -135,7 +135,7 @@ var localFilesystem = &filesystem{ return err } if !info.Mode().IsRegular() { - return errors.New("not a regular file") + return stderrors.New("not a regular file") } return unix.Access(path, unix.X_OK) }, diff --git a/server_mock_test.go b/server_mock_test.go index 0d13a57..fdbb0f8 100644 --- a/server_mock_test.go +++ b/server_mock_test.go @@ -4,7 +4,7 @@ import ( "io" "strings" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -57,7 +57,7 @@ func (s *MockServer) ReadMessage() ([]byte, error) { return nil, err } if s.nextMsgIndex >= len(s.Messages) { - return nil, util.WrapErrorf(io.EOF, util.NetworkError, "") + return nil, errors.WrapErrorf(io.EOF, errors.NetworkError, "") } s.nextMsgIndex++ diff --git a/sync_client.go b/sync_client.go index 2993ca7..09936c6 100644 --- a/sync_client.go +++ b/sync_client.go @@ -5,7 +5,7 @@ import ( "os" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -24,7 +24,7 @@ func stat(conn *wire.SyncConn, path string) (*DirEntry, error) { return nil, err } if id != "STAT" { - return nil, util.Errorf(util.AssertionError, "expected stat ID 'STAT', but got '%s'", id) + return nil, errors.Errorf(errors.AssertionError, "expected stat ID 'STAT', but got '%s'", id) } return readStat(conn) @@ -71,24 +71,24 @@ func sendFile(conn *wire.SyncConn, path string, mode os.FileMode, mtime time.Tim func readStat(s wire.SyncScanner) (entry *DirEntry, err error) { mode, err := s.ReadFileMode() if err != nil { - err = util.WrapErrf(err, "error reading file mode: %v", err) + err = errors.WrapErrf(err, "error reading file mode: %v", err) return } size, err := s.ReadInt32() if err != nil { - err = util.WrapErrf(err, "error reading file size: %v", err) + err = errors.WrapErrf(err, "error reading file size: %v", err) return } mtime, err := s.ReadTime() if err != nil { - err = util.WrapErrf(err, "error reading file time: %v", err) + err = errors.WrapErrf(err, "error reading file time: %v", err) return } // adb doesn't indicate when a file doesn't exist, but will return all zeros. // Theoretically this could be an actual file, but that's very unlikely. if mode == os.FileMode(0) && size == 0 && mtime == zeroTime { - return nil, util.Errorf(util.FileNoExistError, "file doesn't exist") + return nil, errors.Errorf(errors.FileNoExistError, "file doesn't exist") } entry = &DirEntry{ diff --git a/sync_client_test.go b/sync_client_test.go index b5df0f3..0d4d681 100644 --- a/sync_client_test.go +++ b/sync_client_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -57,5 +57,5 @@ func TestStatNoExist(t *testing.T) { entry, err := stat(conn, "/") assert.Nil(t, entry) - assert.Equal(t, util.FileNoExistError, err.(*util.Err).Code) + assert.Equal(t, errors.FileNoExistError, err.(*errors.Err).Code) } diff --git a/sync_file_reader.go b/sync_file_reader.go index efbff70..32a09b3 100644 --- a/sync_file_reader.go +++ b/sync_file_reader.go @@ -3,7 +3,7 @@ package adb import ( "io" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -85,7 +85,7 @@ func readNextChunk(r wire.SyncScanner) (io.Reader, error) { status, err := r.ReadStatus("read-chunk") if err != nil { if wire.IsAdbServerErrorMatching(err, readFileNotFoundPredicate) { - return nil, util.Errorf(util.FileNoExistError, "no such file or directory") + return nil, errors.Errorf(errors.FileNoExistError, "no such file or directory") } return nil, err } @@ -96,7 +96,7 @@ func readNextChunk(r wire.SyncScanner) (io.Reader, error) { case wire.StatusSyncDone: return nil, io.EOF default: - return nil, util.Errorf(util.AssertionError, "expected chunk id '%s' or '%s', but got '%s'", + return nil, errors.Errorf(errors.AssertionError, "expected chunk id '%s' or '%s', but got '%s'", wire.StatusSyncData, wire.StatusSyncDone, []byte(status)) } } diff --git a/sync_file_reader_test.go b/sync_file_reader_test.go index 77f6b2c..09f0464 100644 --- a/sync_file_reader_test.go +++ b/sync_file_reader_test.go @@ -2,13 +2,12 @@ package adb import ( "io" + "io/ioutil" "strings" "testing" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" "github.com/zach-klippenstein/goadb/wire" - "io/ioutil" ) func TestReadNextChunk(t *testing.T) { @@ -110,6 +109,6 @@ func TestReadErrorNotFound(t *testing.T) { s := wire.NewSyncScanner(strings.NewReader( "FAIL\031\000\000\000No such file or directory")) _, err := newSyncFileReader(s) - assert.True(t, util.HasErrCode(err, util.FileNoExistError)) + assert.True(t, HasErrCode(err, FileNoExistError)) assert.EqualError(t, err, "FileNoExistError: no such file or directory") } diff --git a/sync_file_writer.go b/sync_file_writer.go index 0ee8a02..d2da8f6 100644 --- a/sync_file_writer.go +++ b/sync_file_writer.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" "github.com/zach-klippenstein/goadb/wire" ) @@ -76,11 +76,11 @@ func (w *syncFileWriter) Close() error { } if err := w.sender.SendOctetString(wire.StatusSyncDone); err != nil { - return util.WrapErrf(err, "error sending done chunk to close stream") + return errors.WrapErrf(err, "error sending done chunk to close stream") } if err := w.sender.SendTime(w.mtime); err != nil { - return util.WrapErrf(err, "error writing file modification time") + return errors.WrapErrf(err, "error writing file modification time") } - return util.WrapErrf(w.sender.Close(), "error closing FileWriter") + return errors.WrapErrf(w.sender.Close(), "error closing FileWriter") } diff --git a/util.go b/util.go index 8a14f00..6d87e6d 100644 --- a/util.go +++ b/util.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) var ( @@ -25,14 +25,14 @@ func wrapClientError(err error, client interface{}, operation string, args ...in if err == nil { return nil } - if _, ok := err.(*util.Err); !ok { - panic("err is not a *util.Err: " + err.Error()) + if _, ok := err.(*errors.Err); !ok { + panic("err is not a *Err: " + err.Error()) } clientType := reflect.TypeOf(client) - return &util.Err{ - Code: err.(*util.Err).Code, + return &errors.Err{ + Code: err.(*errors.Err).Code, Cause: err, Message: fmt.Sprintf("error performing %s on %s", fmt.Sprintf(operation, args...), clientType), Details: client, diff --git a/util/doc.go b/util/doc.go deleted file mode 100644 index cf6a582..0000000 --- a/util/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Contains code shared between the different sub-packages in this project. -*/ -package util diff --git a/wire/conn.go b/wire/conn.go index 43a4db4..2940bdb 100644 --- a/wire/conn.go +++ b/wire/conn.go @@ -1,6 +1,6 @@ package wire -import "github.com/zach-klippenstein/goadb/util" +import "github.com/zach-klippenstein/goadb/internal/errors" const ( // The official implementation of adb imposes an undocumented 255-byte limit @@ -72,8 +72,8 @@ func (conn *Conn) Close() error { } if errs.ScannerErr != nil || errs.SenderErr != nil { - return &util.Err{ - Code: util.NetworkError, + return &errors.Err{ + Code: errors.NetworkError, Message: "error closing connection", Details: errs, } diff --git a/wire/scanner.go b/wire/scanner.go index e6919cd..58f6066 100644 --- a/wire/scanner.go +++ b/wire/scanner.go @@ -6,7 +6,7 @@ import ( "io/ioutil" "strconv" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) // TODO(zach): All EOF errors returned from networoking calls should use ConnectionResetError. @@ -28,7 +28,7 @@ func isFailureStatus(status string) bool { type StatusReader interface { // Reads a 4-byte status string and returns it. // If the status string is StatusFailure, reads the error message from the server - // and returns it as an util.AdbError. + // and returns it as an AdbError. ReadStatus(req string) (string, error) } @@ -72,7 +72,7 @@ func (s *realScanner) ReadMessage() ([]byte, error) { func (s *realScanner) ReadUntilEof() ([]byte, error) { data, err := ioutil.ReadAll(s.reader) if err != nil { - return nil, util.WrapErrorf(err, util.NetworkError, "error reading until EOF") + return nil, errors.WrapErrorf(err, errors.NetworkError, "error reading until EOF") } return data, nil } @@ -82,7 +82,7 @@ func (s *realScanner) NewSyncScanner() SyncScanner { } func (s *realScanner) Close() error { - return util.WrapErrorf(s.reader.Close(), util.NetworkError, "error closing scanner") + return errors.WrapErrorf(s.reader.Close(), errors.NetworkError, "error closing scanner") } var _ Scanner = &realScanner{} @@ -98,13 +98,13 @@ type lengthReader func(io.Reader) (int, error) func readStatusFailureAsError(r io.Reader, req string, messageLengthReader lengthReader) (string, error) { status, err := readOctetString(req, r) if err != nil { - return "", util.WrapErrorf(err, util.NetworkError, "error reading status for %s", req) + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading status for %s", req) } if isFailureStatus(status) { msg, err := readMessage(r, messageLengthReader) if err != nil { - return "", util.WrapErrorf(err, util.NetworkError, + return "", errors.WrapErrorf(err, errors.NetworkError, "server returned error for %s, but couldn't read the error message", req) } @@ -121,7 +121,7 @@ func readOctetString(description string, r io.Reader) (string, error) { if err == io.ErrUnexpectedEOF { return "", errIncompleteMessage(description, n, 4) } else if err != nil { - return "", util.WrapErrorf(err, util.NetworkError, "error reading "+description) + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading "+description) } return string(octet), nil @@ -143,7 +143,7 @@ func readMessage(r io.Reader, lengthReader lengthReader) ([]byte, error) { n, err := io.ReadFull(r, data) if err != nil && err != io.ErrUnexpectedEOF { - return data, util.WrapErrorf(err, util.NetworkError, "error reading message data") + return data, errors.WrapErrorf(err, errors.NetworkError, "error reading message data") } else if err == io.ErrUnexpectedEOF { return data, errIncompleteMessage("message data", n, length) } @@ -160,7 +160,7 @@ func readHexLength(r io.Reader) (int, error) { length, err := strconv.ParseInt(string(lengthHex), 16, 64) if err != nil { - return 0, util.WrapErrorf(err, util.NetworkError, "could not parse hex length %v", lengthHex) + return 0, errors.WrapErrorf(err, errors.NetworkError, "could not parse hex length %v", lengthHex) } // Clip the length to 255, as per the Google implementation. diff --git a/wire/scanner_test.go b/wire/scanner_test.go index cde6499..3cc696f 100644 --- a/wire/scanner_test.go +++ b/wire/scanner_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) func TestReadStatusOkay(t *testing.T) { @@ -23,7 +23,7 @@ func TestReadIncompleteStatus(t *testing.T) { s := newEofReader("oka") _, err := readStatusFailureAsError(s, "", readHexLength) assert.EqualError(t, err, "NetworkError: error reading status for ") - assert.Equal(t, errIncompleteMessage("", 3, 4), err.(*util.Err).Cause) + assert.Equal(t, errIncompleteMessage("", 3, 4), err.(*errors.Err).Cause) assertEof(t, s) } @@ -31,7 +31,7 @@ func TestReadFailureIncompleteStatus(t *testing.T) { s := newEofReader("FAIL") _, err := readStatusFailureAsError(s, "req", readHexLength) assert.EqualError(t, err, "NetworkError: server returned error for req, but couldn't read the error message") - assert.Error(t, err.(*util.Err).Cause) + assert.Error(t, err.(*errors.Err).Cause) assertEof(t, s) } @@ -39,7 +39,7 @@ func TestReadFailureEmptyStatus(t *testing.T) { s := newEofReader("FAIL0000") _, err := readStatusFailureAsError(s, "", readHexLength) assert.EqualError(t, err, "AdbError: server error: ({Request: ServerMsg:})") - assert.NoError(t, err.(*util.Err).Cause) + assert.NoError(t, err.(*errors.Err).Cause) assertEof(t, s) } @@ -47,7 +47,7 @@ func TestReadFailureStatus(t *testing.T) { s := newEofReader("FAIL0004fail") _, err := readStatusFailureAsError(s, "", readHexLength) assert.EqualError(t, err, "AdbError: server error: fail ({Request: ServerMsg:fail})") - assert.NoError(t, err.(*util.Err).Cause) + assert.NoError(t, err.(*errors.Err).Cause) assertEof(t, s) } @@ -112,7 +112,7 @@ func TestReadLengthIncompleteLength(t *testing.T) { func assertEof(t *testing.T, r io.Reader) { msg, err := readMessage(r, readHexLength) - assert.True(t, util.HasErrCode(err, util.ConnectionResetError)) + assert.True(t, errors.HasErrCode(err, errors.ConnectionResetError)) assert.Nil(t, msg) } diff --git a/wire/sender.go b/wire/sender.go index c333e11..cb40634 100644 --- a/wire/sender.go +++ b/wire/sender.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) // Sender sends messages to the server. @@ -30,7 +30,7 @@ func SendMessageString(s Sender, msg string) error { func (s *realSender) SendMessage(msg []byte) error { if len(msg) > MaxMessageLength { - return util.AssertionErrorf("message length exceeds maximum: %d", len(msg)) + return errors.AssertionErrorf("message length exceeds maximum: %d", len(msg)) } lengthAndMsg := fmt.Sprintf("%04x%s", len(msg), msg) @@ -42,7 +42,7 @@ func (s *realSender) NewSyncSender() SyncSender { } func (s *realSender) Close() error { - return util.WrapErrorf(s.writer.Close(), util.NetworkError, "error closing sender") + return errors.WrapErrorf(s.writer.Close(), errors.NetworkError, "error closing sender") } var _ Sender = &realSender{} diff --git a/wire/sync_conn.go b/wire/sync_conn.go index 1752a09..61740d1 100644 --- a/wire/sync_conn.go +++ b/wire/sync_conn.go @@ -1,6 +1,6 @@ package wire -import "github.com/zach-klippenstein/goadb/util" +import "github.com/zach-klippenstein/goadb/internal/errors" const ( // Chunks cannot be longer than 64k. @@ -32,6 +32,6 @@ type SyncConn struct { // Close closes both the sender and the scanner, and returns any errors. func (c SyncConn) Close() error { - return util.CombineErrs("error closing SyncConn", util.NetworkError, + return errors.CombineErrs("error closing SyncConn", errors.NetworkError, c.SyncScanner.Close(), c.SyncSender.Close()) } diff --git a/wire/sync_scanner.go b/wire/sync_scanner.go index dce14c8..d18c9de 100644 --- a/wire/sync_scanner.go +++ b/wire/sync_scanner.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) type SyncScanner interface { @@ -39,13 +39,13 @@ func (s *realSyncScanner) ReadStatus(req string) (string, error) { func (s *realSyncScanner) ReadInt32() (int32, error) { value, err := readInt32(s.Reader) - return int32(value), util.WrapErrorf(err, util.NetworkError, "error reading int from sync scanner") + return int32(value), errors.WrapErrorf(err, errors.NetworkError, "error reading int from sync scanner") } func (s *realSyncScanner) ReadFileMode() (os.FileMode, error) { var value uint32 err := binary.Read(s.Reader, binary.LittleEndian, &value) if err != nil { - return 0, util.WrapErrorf(err, util.NetworkError, "error reading filemode from sync scanner") + return 0, errors.WrapErrorf(err, errors.NetworkError, "error reading filemode from sync scanner") } return ParseFileModeFromAdb(value), nil @@ -53,7 +53,7 @@ func (s *realSyncScanner) ReadFileMode() (os.FileMode, error) { func (s *realSyncScanner) ReadTime() (time.Time, error) { seconds, err := s.ReadInt32() if err != nil { - return time.Time{}, util.WrapErrorf(err, util.NetworkError, "error reading time from sync scanner") + return time.Time{}, errors.WrapErrorf(err, errors.NetworkError, "error reading time from sync scanner") } return time.Unix(int64(seconds), 0).UTC(), nil @@ -62,13 +62,13 @@ func (s *realSyncScanner) ReadTime() (time.Time, error) { func (s *realSyncScanner) ReadString() (string, error) { length, err := s.ReadInt32() if err != nil { - return "", util.WrapErrorf(err, util.NetworkError, "error reading length from sync scanner") + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading length from sync scanner") } bytes := make([]byte, length) n, rawErr := io.ReadFull(s.Reader, bytes) if rawErr != nil && rawErr != io.ErrUnexpectedEOF { - return "", util.WrapErrorf(rawErr, util.NetworkError, "error reading string from sync scanner") + return "", errors.WrapErrorf(rawErr, errors.NetworkError, "error reading string from sync scanner") } else if rawErr == io.ErrUnexpectedEOF { return "", errIncompleteMessage("bytes", n, int(length)) } @@ -78,7 +78,7 @@ func (s *realSyncScanner) ReadString() (string, error) { func (s *realSyncScanner) ReadBytes() (io.Reader, error) { length, err := s.ReadInt32() if err != nil { - return nil, util.WrapErrorf(err, util.NetworkError, "error reading bytes from sync scanner") + return nil, errors.WrapErrorf(err, errors.NetworkError, "error reading bytes from sync scanner") } return io.LimitReader(s.Reader, int64(length)), nil @@ -86,7 +86,7 @@ func (s *realSyncScanner) ReadBytes() (io.Reader, error) { func (s *realSyncScanner) Close() error { if closer, ok := s.Reader.(io.Closer); ok { - return util.WrapErrorf(closer.Close(), util.NetworkError, "error closing sync scanner") + return errors.WrapErrorf(closer.Close(), errors.NetworkError, "error closing sync scanner") } return nil } diff --git a/wire/sync_sender.go b/wire/sync_sender.go index 182678a..f6dae86 100644 --- a/wire/sync_sender.go +++ b/wire/sync_sender.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) type SyncSender interface { @@ -33,28 +33,28 @@ func NewSyncSender(w io.Writer) SyncSender { func (s *realSyncSender) SendOctetString(str string) error { if len(str) != 4 { - return util.AssertionErrorf("octet string must be exactly 4 bytes: '%s'", str) + return errors.AssertionErrorf("octet string must be exactly 4 bytes: '%s'", str) } - wrappedErr := util.WrapErrorf(writeFully(s.Writer, []byte(str)), - util.NetworkError, "error sending octet string on sync sender") + wrappedErr := errors.WrapErrorf(writeFully(s.Writer, []byte(str)), + errors.NetworkError, "error sending octet string on sync sender") return wrappedErr } func (s *realSyncSender) SendInt32(val int32) error { - return util.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, val), - util.NetworkError, "error sending int on sync sender") + return errors.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, val), + errors.NetworkError, "error sending int on sync sender") } func (s *realSyncSender) SendFileMode(mode os.FileMode) error { - return util.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, mode), - util.NetworkError, "error sending filemode on sync sender") + return errors.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, mode), + errors.NetworkError, "error sending filemode on sync sender") } func (s *realSyncSender) SendTime(t time.Time) error { - return util.WrapErrorf(s.SendInt32(int32(t.Unix())), - util.NetworkError, "error sending time on sync sender") + return errors.WrapErrorf(s.SendInt32(int32(t.Unix())), + errors.NetworkError, "error sending time on sync sender") } func (s *realSyncSender) SendBytes(data []byte) error { @@ -62,18 +62,18 @@ func (s *realSyncSender) SendBytes(data []byte) error { if length > SyncMaxChunkSize { // This limit might not apply to filenames, but it's big enough // that I don't think it will be a problem. - return util.AssertionErrorf("data must be <= %d in length", SyncMaxChunkSize) + return errors.AssertionErrorf("data must be <= %d in length", SyncMaxChunkSize) } if err := s.SendInt32(int32(length)); err != nil { - return util.WrapErrorf(err, util.NetworkError, "error sending data length on sync sender") + return errors.WrapErrorf(err, errors.NetworkError, "error sending data length on sync sender") } return writeFully(s.Writer, data) } func (s *realSyncSender) Close() error { if closer, ok := s.Writer.(io.Closer); ok { - return util.WrapErrorf(closer.Close(), util.NetworkError, "error closing sync sender") + return errors.WrapErrorf(closer.Close(), errors.NetworkError, "error closing sync sender") } return nil } diff --git a/wire/sync_test.go b/wire/sync_test.go index 5321639..03386bf 100644 --- a/wire/sync_test.go +++ b/wire/sync_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) var ( @@ -29,7 +29,7 @@ func TestSyncSendOctetStringTooLong(t *testing.T) { var buf bytes.Buffer s := NewSyncSender(&buf) err := s.SendOctetString("hello") - assert.Equal(t, util.AssertionErrorf("octet string must be exactly 4 bytes: 'hello'"), err) + assert.Equal(t, errors.AssertionErrorf("octet string must be exactly 4 bytes: 'hello'"), err) } func TestSyncReadTime(t *testing.T) { diff --git a/wire/util.go b/wire/util.go index 63bb7fc..66bd7b8 100644 --- a/wire/util.go +++ b/wire/util.go @@ -4,10 +4,9 @@ import ( "fmt" "io" "regexp" - "sync" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) // ErrorResponseDetails is an error message returned by the server for a particular request. @@ -17,7 +16,7 @@ type ErrorResponseDetails struct { } // deviceNotFoundMessagePattern matches all possible error messages returned by adb servers to -// report that a matching device was not found. Used to set the util.DeviceNotFound error code on +// report that a matching device was not found. Used to set the DeviceNotFound error code on // error values. // // Old servers send "device not found", and newer ones "device 'serial' not found". @@ -31,12 +30,12 @@ func adbServerError(request string, serverMsg string) error { msg = fmt.Sprintf("server error for %s request: %s", request, serverMsg) } - errCode := util.AdbError + errCode := errors.AdbError if deviceNotFoundMessagePattern.MatchString(serverMsg) { - errCode = util.DeviceNotFound + errCode = errors.DeviceNotFound } - return &util.Err{ + return &errors.Err{ Code: errCode, Message: msg, Details: ErrorResponseDetails{ @@ -46,18 +45,18 @@ func adbServerError(request string, serverMsg string) error { } } -// IsAdbServerErrorMatching returns true if err is an *util.Err with code AdbError and for which +// IsAdbServerErrorMatching returns true if err is an *Err with code AdbError and for which // predicate returns true when passed Details.ServerMsg. func IsAdbServerErrorMatching(err error, predicate func(string) bool) bool { - if err, ok := err.(*util.Err); ok && err.Code == util.AdbError { + if err, ok := err.(*errors.Err); ok && err.Code == errors.AdbError { return predicate(err.Details.(ErrorResponseDetails).ServerMsg) } return false } func errIncompleteMessage(description string, actual int, expected int) error { - return &util.Err{ - Code: util.ConnectionResetError, + return &errors.Err{ + Code: errors.ConnectionResetError, Message: fmt.Sprintf("incomplete %s: read %d bytes, expecting %d", description, actual, expected), Details: struct { ActualReadBytes int @@ -76,7 +75,7 @@ func writeFully(w io.Writer, data []byte) error { for offset < len(data) { n, err := w.Write(data[offset:]) if err != nil { - return util.WrapErrorf(err, util.NetworkError, "error writing %d bytes at offset %d", len(data), offset) + return errors.WrapErrorf(err, errors.NetworkError, "error writing %d bytes at offset %d", len(data), offset) } offset += n } diff --git a/wire/util_test.go b/wire/util_test.go index 9e4fdb4..5bf57ee 100644 --- a/wire/util_test.go +++ b/wire/util_test.go @@ -4,53 +4,53 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/zach-klippenstein/goadb/util" + "github.com/zach-klippenstein/goadb/internal/errors" ) func TestAdbServerError_NoRequest(t *testing.T) { err := adbServerError("", "fail") - assert.Equal(t, util.Err{ - Code: util.AdbError, + assert.Equal(t, errors.Err{ + Code: errors.AdbError, Message: "server error: fail", Details: ErrorResponseDetails{ Request: "", ServerMsg: "fail", }, - }, *(err.(*util.Err))) + }, *(err.(*errors.Err))) } func TestAdbServerError_WithRequest(t *testing.T) { err := adbServerError("polite", "fail") - assert.Equal(t, util.Err{ - Code: util.AdbError, + assert.Equal(t, errors.Err{ + Code: errors.AdbError, Message: "server error for polite request: fail", Details: ErrorResponseDetails{ Request: "polite", ServerMsg: "fail", }, - }, *(err.(*util.Err))) + }, *(err.(*errors.Err))) } func TestAdbServerError_DeviceNotFound(t *testing.T) { err := adbServerError("", "device not found") - assert.Equal(t, util.Err{ - Code: util.DeviceNotFound, + assert.Equal(t, errors.Err{ + Code: errors.DeviceNotFound, Message: "server error: device not found", Details: ErrorResponseDetails{ Request: "", ServerMsg: "device not found", }, - }, *(err.(*util.Err))) + }, *(err.(*errors.Err))) } func TestAdbServerError_DeviceSerialNotFound(t *testing.T) { err := adbServerError("", "device 'LGV4801c74eccd' not found") - assert.Equal(t, util.Err{ - Code: util.DeviceNotFound, + assert.Equal(t, errors.Err{ + Code: errors.DeviceNotFound, Message: "server error: device 'LGV4801c74eccd' not found", Details: ErrorResponseDetails{ Request: "", ServerMsg: "device 'LGV4801c74eccd' not found", }, - }, *(err.(*util.Err))) + }, *(err.(*errors.Err))) }