Merge pull request #20 from zach-klippenstein/cleanup-errors

Moved error definitions to an internal package, deleted the confusing util package.
This commit is contained in:
Zach Klippenstein 2016-05-22 11:16:37 -07:00
commit e87d5c6814
33 changed files with 177 additions and 148 deletions

4
adb.go
View file

@ -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

View file

@ -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()

View file

@ -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 ")

View file

@ -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)

View file

@ -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))
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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) {

View file

@ -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

35
error.go Normal file
View file

@ -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)
}

View file

@ -1,6 +1,6 @@
// Code generated by "stringer -type=ErrCode"; DO NOT EDIT
package util
package errors
import "fmt"

View file

@ -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

View file

@ -1,4 +1,4 @@
package util
package errors
import (
"errors"

View file

@ -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)
},

View file

@ -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++

View file

@ -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{

View file

@ -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)
}

View file

@ -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))
}
}

View file

@ -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")
}

View file

@ -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")
}

10
util.go
View file

@ -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,

View file

@ -1,4 +0,0 @@
/*
Contains code shared between the different sub-packages in this project.
*/
package util

View file

@ -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,
}

View file

@ -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.

View file

@ -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)
}

View file

@ -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{}

View file

@ -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())
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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) {

View file

@ -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
}

View file

@ -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)))
}