Merge pull request #531 from aaron-prindle/pkg-errors

Changed minikube code to use pkg/errors, this is to improve error
pull/511/head
Aaron Prindle 2016-09-08 15:40:07 -07:00 committed by GitHub
commit cca3ff3271
23 changed files with 728 additions and 146 deletions

5
Godeps/Godeps.json generated
View File

@ -1382,6 +1382,11 @@
"ImportPath": "github.com/pkg/browser",
"Rev": "9302be274faad99162b9d48ec97b24306872ebb0"
},
{
"ImportPath": "github.com/pkg/errors",
"Comment": "v0.7.1",
"Rev": "17b591df37844cde689f4d5813e5cea0927d8dd2"
},
{
"ImportPath": "github.com/pmezard/go-difflib/difflib",
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"

View File

@ -28,6 +28,7 @@ import (
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/shell"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
@ -104,12 +105,12 @@ func shellCfgSet(api libmachine.API) (*ShellConfig, error) {
host, err := api.Load(constants.MachineName)
if err != nil {
return nil, fmt.Errorf("Error getting IP: %s", err)
return nil, errors.Wrap(err, "Error getting IP: ")
}
ip, err := host.Driver.GetIP()
if err != nil {
return nil, fmt.Errorf("Error getting host IP: %s", err)
return nil, errors.Wrap(err, "Error getting host IP: %s")
}
noProxyVar, noProxyValue := findNoProxyFromEnv()

View File

@ -24,6 +24,7 @@ import (
"github.com/docker/machine/libmachine"
"github.com/pkg/browser"
"github.com/pkg/errors"
"github.com/spf13/cobra"
kubeApi "k8s.io/kubernetes/pkg/api"
"k8s.io/minikube/pkg/minikube/cluster"
@ -100,13 +101,13 @@ func CheckService(namespace string, service string) error {
func CheckEndpointReady(endpoint *kubeApi.Endpoints) error {
if len(endpoint.Subsets) == 0 {
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...\n")
return fmt.Errorf("Endpoint for service is not ready yet\n")
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...")
return errors.New("Endpoint for service is not ready yet")
}
for _, subset := range endpoint.Subsets {
if len(subset.NotReadyAddresses) != 0 {
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...\n")
return fmt.Errorf("Endpoint for service is not ready yet\n")
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...")
return errors.New("Endpoint for service is not ready yet")
}
}
return nil

View File

@ -21,7 +21,6 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
@ -41,6 +40,7 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
kubeApi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
@ -66,7 +66,7 @@ func init() {
func StartHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
exists, err := api.Exists(constants.MachineName)
if err != nil {
return nil, fmt.Errorf("Error checking if host exists: %s", err)
return nil, errors.Wrapf(err, "Error checking if host exists: %s", constants.MachineName)
}
if !exists {
return createHost(api, config)
@ -75,27 +75,26 @@ func StartHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
glog.Infoln("Machine exists!")
h, err := api.Load(constants.MachineName)
if err != nil {
return nil, fmt.Errorf(
"Error loading existing host: %s. Please try running [minikube delete], then run [minikube start] again.", err)
return nil, errors.Wrap(err, "Error loading existing host. Please try running [minikube delete], then run [minikube start] again.")
}
s, err := h.Driver.GetState()
glog.Infoln("Machine state: ", s)
if err != nil {
return nil, fmt.Errorf("Error getting state for host: %s", err)
return nil, errors.Wrap(err, "Error getting state for host")
}
if s != state.Running {
if err := h.Driver.Start(); err != nil {
return nil, fmt.Errorf("Error starting stopped host: %s", err)
return nil, errors.Wrapf(err, "Error starting stopped host")
}
if err := api.Save(h); err != nil {
return nil, fmt.Errorf("Error saving started host: %s", err)
return nil, errors.Wrapf(err, "Error saving started host")
}
}
if err := h.ConfigureAuth(); err != nil {
return nil, fmt.Errorf("Error configuring auth on host: %s", err)
return nil, errors.Wrap(err, "Error configuring auth on host: %s")
}
return h, nil
}
@ -104,10 +103,10 @@ func StartHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
func StopHost(api libmachine.API) error {
host, err := api.Load(constants.MachineName)
if err != nil {
return err
return errors.Wrapf(err, "Error loading host: %s", constants.MachineName)
}
if err := host.Stop(); err != nil {
return err
return errors.Wrapf(err, "Error stopping host: %s", constants.MachineName)
}
return nil
}
@ -116,7 +115,7 @@ func StopHost(api libmachine.API) error {
func DeleteHost(api libmachine.API) error {
host, err := api.Load(constants.MachineName)
if err != nil {
return err
return errors.Wrapf(err, "Error deleting host: %s", constants.MachineName)
}
m := util.MultiError{}
m.Collect(host.Driver.Remove())
@ -129,7 +128,7 @@ func GetHostStatus(api libmachine.API) (string, error) {
dne := "Does Not Exist"
exists, err := api.Exists(constants.MachineName)
if err != nil {
return "", err
return "", errors.Wrapf(err, "Error checking that api exists for: ", constants.MachineName)
}
if !exists {
return dne, nil
@ -137,14 +136,17 @@ func GetHostStatus(api libmachine.API) (string, error) {
host, err := api.Load(constants.MachineName)
if err != nil {
return "", err
return "", errors.Wrapf(err, "Error loading api for: ", constants.MachineName)
}
s, err := host.Driver.GetState()
if s.String() == "" {
return dne, err
return dne, nil
}
return s.String(), err
if err != nil {
return "", errors.Wrap(err, "Error getting host state")
}
return s.String(), nil
}
// GetLocalkubeStatus gets the status of localkube from the host VM.
@ -199,7 +201,7 @@ func StartCluster(h sshAble, kubernetesConfig KubernetesConfig) error {
output, err := h.RunSSHCommand(cmd)
glog.Infoln(output)
if err != nil {
return err
return errors.Wrapf(err, "Error running ssh command: %s", cmd)
}
}
@ -256,7 +258,7 @@ func NewFileAsset(assetName, targetDir, targetName, permissions string) (*FileAs
}
file, err := os.Open(f.AssetName)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error opening file asset: %s", f.AssetName)
}
f.reader = file
return f, nil
@ -339,18 +341,18 @@ var memoryAssets = []CopyableFile{
func UpdateCluster(h sshAble, d drivers.Driver, config KubernetesConfig) error {
client, err := sshutil.NewSSHClient(d)
if err != nil {
return err
return errors.Wrap(err, "Error creating new ssh client")
}
// transfer localkube from cache/asset to vm
if localkubeURIWasSpecified(config) {
lCacher := localkubeCacher{config}
if err = lCacher.updateLocalkubeFromURI(client); err != nil {
return err
return errors.Wrap(err, "Error updating localkube from uri")
}
} else {
if err = updateLocalkubeFromAsset(client); err != nil {
return err
return errors.Wrap(err, "Error updating localkube from asset")
}
}
fileAssets := []CopyableFile{}
@ -380,7 +382,7 @@ func SetupCerts(d drivers.Driver) error {
localPath := constants.Minipath
ipStr, err := d.GetIP()
if err != nil {
return err
return errors.Wrap(err, "Error getting ip from driver")
}
glog.Infoln("Setting up certificates for IP: %s", ipStr)
@ -390,26 +392,26 @@ func SetupCerts(d drivers.Driver) error {
publicPath := filepath.Join(localPath, "apiserver.crt")
privatePath := filepath.Join(localPath, "apiserver.key")
if err := GenerateCerts(caCert, caKey, publicPath, privatePath, ip); err != nil {
return err
return errors.Wrap(err, "Error generating certs")
}
client, err := sshutil.NewSSHClient(d)
if err != nil {
return err
return errors.Wrap(err, "Error creating new ssh client")
}
for _, cert := range certs {
p := filepath.Join(localPath, cert)
data, err := ioutil.ReadFile(p)
if err != nil {
return err
return errors.Wrapf(err, "Error reading file: %s", p)
}
perms := "0644"
if strings.HasSuffix(cert, ".key") {
perms = "0600"
}
if err := sshutil.Transfer(bytes.NewReader(data), len(data), util.DefaultCertPath, cert, perms, client); err != nil {
return err
return errors.Wrapf(err, "Error transferring data: %s", string(data))
}
}
return nil
@ -467,34 +469,34 @@ func (m *MachineConfig) CacheMinikubeISOFromURL() error {
// store the miniube-iso inside the .minikube dir
response, err := http.Get(m.MinikubeISO)
if err != nil {
return err
return errors.Wrapf(err, "Error getting minikube iso at %s via http", m.MinikubeISO)
}
defer response.Body.Close()
isoData, err := ioutil.ReadAll(response.Body)
if err != nil {
return err
return errors.Wrap(err, "Error reading minikubeISO url response")
}
// Validate the ISO if it was the default URL, before writing it to disk.
if m.MinikubeISO == constants.DefaultIsoUrl {
if !isIsoChecksumValid(&isoData, constants.DefaultIsoShaUrl) {
return fmt.Errorf("Error validating ISO checksum.")
return errors.New("Error validating ISO checksum.")
}
}
if response.StatusCode != http.StatusOK {
return fmt.Errorf("Received %d response from %s while trying to download minikube.iso", response.StatusCode, m.MinikubeISO)
return errors.Errorf("Received %d response from %s while trying to download minikube.iso", response.StatusCode, m.MinikubeISO)
}
out, err := os.Create(m.GetISOCacheFilepath())
if err != nil {
return err
return errors.Wrap(err, "Error creating minikube iso cache filepath")
}
defer out.Close()
if _, err = out.Write(isoData); err != nil {
return err
return errors.Wrap(err, "Error writing iso data to file")
}
return nil
}
@ -544,7 +546,7 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
if config.ShouldCacheMinikubeISO() {
if err := config.CacheMinikubeISOFromURL(); err != nil {
return nil, err
return nil, errors.Wrap(err, "Error attempting to cache minikube iso from url")
}
}
@ -565,12 +567,12 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
data, err := json.Marshal(driver)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error marshalling json")
}
h, err := api.NewHost(config.VMDriver, data)
if err != nil {
return nil, fmt.Errorf("Error creating new host: %s", err)
return nil, errors.Wrap(err, "Error creating new host: %s")
}
h.HostOptions.AuthOptions.CertDir = constants.Minipath
@ -580,11 +582,11 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
if err := api.Create(h); err != nil {
// Wait for all the logs to reach the client
time.Sleep(2 * time.Second)
return nil, fmt.Errorf("Error creating. %s", err)
return nil, errors.Wrap(err, "Error creating host")
}
if err := api.Save(h); err != nil {
return nil, fmt.Errorf("Error attempting to save store: %s", err)
return nil, errors.Wrap(err, "Error attempting to save")
}
return h, nil
}
@ -593,11 +595,11 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
host, err := checkIfApiExistsAndLoad(api)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error checking that api exists and loading it")
}
ip, err := host.Driver.GetIP()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error getting ip from host")
}
tcpPrefix := "tcp://"
@ -616,27 +618,27 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
func GetHostLogs(api libmachine.API) (string, error) {
host, err := checkIfApiExistsAndLoad(api)
if err != nil {
return "", err
return "", errors.Wrap(err, "Error checking that api exists and loading it")
}
s, err := host.RunSSHCommand(logsCommand)
if err != nil {
return "", err
}
return s, err
return s, nil
}
func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
exists, err := api.Exists(constants.MachineName)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error checking that api exists for: ", constants.MachineName)
}
if !exists {
return nil, fmt.Errorf("Machine does not exist for api.Exists(%s)", constants.MachineName)
return nil, errors.Errorf("Machine does not exist for api.Exists(%s)", constants.MachineName)
}
host, err := api.Load(constants.MachineName)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error loading api for: ", constants.MachineName)
}
return host, nil
}
@ -644,21 +646,21 @@ func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
func CreateSSHShell(api libmachine.API, args []string) error {
host, err := checkIfApiExistsAndLoad(api)
if err != nil {
return err
return errors.Wrap(err, "Error checking if api exist and loading it")
}
currentState, err := host.Driver.GetState()
if err != nil {
return err
return errors.Wrap(err, "Error getting state of host")
}
if currentState != state.Running {
return fmt.Errorf("Error: Cannot run ssh command: Host %q is not running", constants.MachineName)
return errors.Errorf("Error: Cannot run ssh command: Host %q is not running", constants.MachineName)
}
client, err := host.CreateSSHClient()
if err != nil {
return err
return errors.Wrap(err, "Error creating ssh client")
}
return client.Shell(strings.Join(args, " "))
}
@ -666,17 +668,17 @@ func CreateSSHShell(api libmachine.API, args []string) error {
func GetServiceURL(api libmachine.API, namespace, service string) (string, error) {
host, err := checkIfApiExistsAndLoad(api)
if err != nil {
return "", err
return "", errors.Wrap(err, "Error checking if api exist and loading it")
}
ip, err := host.Driver.GetIP()
if err != nil {
return "", err
return "", errors.Wrap(err, "Error getting ip from host")
}
port, err := getServicePort(namespace, service)
if err != nil {
return "", err
return "", errors.Wrapf(err, "Error getting service port from %s, %s", namespace, service)
}
return fmt.Sprintf("http://%s:%d", ip, port), nil
@ -693,7 +695,7 @@ type endpointGetter interface {
func getServicePort(namespace, service string) (int, error) {
services, err := GetKubernetesServicesWithNamespace(namespace)
if err != nil {
return 0, err
return 0, errors.Wrapf(err, "Error getting kubernetes service with namespace", namespace)
}
return getServicePortFromServiceGetter(services, service)
}
@ -701,14 +703,14 @@ func getServicePort(namespace, service string) (int, error) {
func getServicePortFromServiceGetter(services serviceGetter, service string) (int, error) {
svc, err := services.Get(service)
if err != nil {
return 0, fmt.Errorf("Error getting %s service: %s", service, err)
return 0, errors.Wrapf(err, "Error getting %s service: %s", service)
}
nodePort := 0
if len(svc.Spec.Ports) > 0 {
nodePort = int(svc.Spec.Ports[0].NodePort)
}
if nodePort == 0 {
return 0, fmt.Errorf("Service %s does not have a node port. To have one assigned automatically, the service type must be NodePort or LoadBalancer, but this service is of type %s.", service, svc.Spec.Type)
return 0, errors.Errorf("Service %s does not have a node port. To have one assigned automatically, the service type must be NodePort or LoadBalancer, but this service is of type %s.", service, svc.Spec.Type)
}
return nodePort, nil
}
@ -719,11 +721,11 @@ func GetKubernetesClient() (*unversioned.Client, error) {
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
config, err := kubeConfig.ClientConfig()
if err != nil {
return nil, fmt.Errorf("Error creating kubeConfig: %s", err)
return nil, errors.Wrap(err, "Error creating kubeConfig: %s")
}
client, err := unversioned.New(config)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()")
}
return client, nil
}
@ -731,7 +733,7 @@ func GetKubernetesClient() (*unversioned.Client, error) {
func GetKubernetesServicesWithNamespace(namespace string) (serviceGetter, error) {
client, err := GetKubernetesClient()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error getting kubernetes client")
}
services := client.Services(namespace)
return services, nil
@ -740,7 +742,7 @@ func GetKubernetesServicesWithNamespace(namespace string) (serviceGetter, error)
func GetKubernetesEndpointsWithNamespace(namespace string) (endpointGetter, error) {
client, err := GetKubernetesClient()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error getting kubernetes client")
}
endpoints := client.Endpoints(namespace)
return endpoints, nil

View File

@ -20,7 +20,6 @@ import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
@ -34,6 +33,7 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/provision"
"github.com/docker/machine/libmachine/state"
"github.com/pkg/errors"
"k8s.io/kubernetes/pkg/api"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/tests"
@ -498,7 +498,7 @@ func NewMockServiceGetter() *MockServiceGetter {
func (mockServiceGetter *MockServiceGetter) Get(name string) (*api.Service, error) {
service, ok := mockServiceGetter.services[name]
if !ok {
return nil, fmt.Errorf("Error getting %s service from mockServiceGetter", name)
return nil, errors.Errorf("Error getting %s service from mockServiceGetter", name)
}
return &service, nil
}

View File

@ -19,6 +19,7 @@ package cluster
import (
"net"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/util"
)
@ -30,13 +31,13 @@ var (
func GenerateCerts(caCert, caKey, pub, priv string, ip net.IP) error {
if !(util.CanReadFile(caCert) && util.CanReadFile(caKey)) {
if err := util.GenerateCACert(caCert, caKey); err != nil {
return err
return errors.Wrap(err, "Error generating certificate")
}
}
ips := []net.IP{ip, internalIP}
if err := util.GenerateSignedCert(pub, priv, ips, util.GetAlternateDNS(util.DefaultDNSDomain), caCert, caKey); err != nil {
return err
return errors.Wrap(err, "Error generating signed cert")
}
return nil
}

View File

@ -18,7 +18,6 @@ package cluster
import (
"bytes"
"errors"
"io"
"io/ioutil"
"net/http"
@ -27,7 +26,7 @@ import (
"path/filepath"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/sshutil"
@ -37,12 +36,11 @@ import (
func updateLocalkubeFromAsset(client *ssh.Client) error {
contents, err := Asset("out/localkube")
if err != nil {
glog.Infof("Error loading asset out/localkube: %s", err)
return err
return errors.Wrap(err, "Error loading asset out/localkube")
}
if err := sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin",
"localkube", "0777", client); err != nil {
return err
return errors.Wrap(err, "Error transferring localkube via ssh")
}
return nil
}
@ -68,12 +66,12 @@ func (l *localkubeCacher) cacheLocalkube(body io.ReadCloser) error {
// store localkube inside the .minikube dir
out, err := os.Create(l.getLocalkubeCacheFilepath())
if err != nil {
return err
return errors.Wrap(err, "Error creating localkube local file")
}
defer out.Close()
defer body.Close()
if _, err = io.Copy(out, body); err != nil {
return err
return errors.Wrap(err, "Error writing localkube to file")
}
return nil
}
@ -85,17 +83,19 @@ func (l *localkubeCacher) downloadAndCacheLocalkube() error {
url, err := util.GetLocalkubeDownloadURL(l.k8sConf.KubernetesVersion,
constants.LocalkubeLinuxFilename)
if err != nil {
return err
return errors.Wrap(err, "Error getting localkube download url")
}
resp, err = http.Get(url)
return err
if err != nil {
return errors.Wrap(err, "Error downloading localkube via http")
}
return nil
}
if err = util.Retry(5, downloader); err != nil {
return err
return errors.Wrap(err, "Max error attempts retrying localkube downloader")
}
if err = l.cacheLocalkube(resp.Body); err != nil {
return err
return errors.Wrap(err, "Error caching localkube to local directory")
}
return nil
}
@ -103,7 +103,7 @@ func (l *localkubeCacher) downloadAndCacheLocalkube() error {
func (l *localkubeCacher) updateLocalkubeFromURI(client *ssh.Client) error {
urlObj, err := url.Parse(l.k8sConf.KubernetesVersion)
if err != nil {
return err
return errors.Wrap(err, "Error parsing --kubernetes-version url")
}
if urlObj.Scheme == fileScheme {
return l.updateLocalkubeFromFile(client)
@ -115,11 +115,11 @@ func (l *localkubeCacher) updateLocalkubeFromURI(client *ssh.Client) error {
func (l *localkubeCacher) updateLocalkubeFromURL(client *ssh.Client) error {
if !l.isLocalkubeCached() {
if err := l.downloadAndCacheLocalkube(); err != nil {
return err
return errors.Wrap(err, "Error attempting to download and cache localkube")
}
}
if err := l.transferCachedLocalkubeToVM(client); err != nil {
return err
return errors.Wrap(err, "Error transferring cached localkube to VM")
}
return nil
}
@ -127,13 +127,12 @@ func (l *localkubeCacher) updateLocalkubeFromURL(client *ssh.Client) error {
func (l *localkubeCacher) transferCachedLocalkubeToVM(client *ssh.Client) error {
contents, err := ioutil.ReadFile(l.getLocalkubeCacheFilepath())
if err != nil {
glog.Infof("Error loading asset out/localkube: %s", err)
return err
return errors.Wrap(err, "Error reading file: localkube cache filepath")
}
if err = sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin",
"localkube", "0777", client); err != nil {
return err
return errors.Wrap(err, "Error transferring cached localkube to VM via ssh")
}
return nil
}
@ -143,12 +142,11 @@ func (l *localkubeCacher) updateLocalkubeFromFile(client *ssh.Client) error {
path = filepath.FromSlash(path)
contents, err := ioutil.ReadFile(path)
if err != nil {
glog.Infof("Error loading file %s: %s", path, err)
return err
return errors.Wrapf(err, "Error reading localkube file at %s", path)
}
if err := sshutil.Transfer(bytes.NewReader(contents), len(contents), "/usr/local/bin",
"localkube", "0777", client); err != nil {
return err
return errors.Wrapf(err, "Error transferring specified localkube file at %s to VM via ssh", path)
}
return nil
}

View File

@ -17,12 +17,12 @@ limitations under the License.
package kubeconfig
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest"
"k8s.io/kubernetes/pkg/runtime"
@ -35,13 +35,13 @@ func ReadConfigOrNew(filename string) (*api.Config, error) {
if os.IsNotExist(err) {
return api.NewConfig(), nil
} else if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error reading file", filename)
}
// decode config, empty if no bytes
config, err := decode(data)
if err != nil {
return nil, fmt.Errorf("could not read config: %v", err)
return nil, errors.Errorf("could not read config: %v", err)
}
// initialize nil maps
@ -68,20 +68,20 @@ func WriteConfig(config *api.Config, filename string) error {
// encode config to YAML
data, err := runtime.Encode(latest.Codec, config)
if err != nil {
return fmt.Errorf("could not write to '%s': failed to encode config: %v", filename, err)
return errors.Errorf("could not write to '%s': failed to encode config: %v", filename, err)
}
// create parent dir if doesn't exist
dir := filepath.Dir(filename)
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err = os.MkdirAll(dir, 0755); err != nil {
return err
return errors.Wrapf(err, "Error creating directory: %s", dir)
}
}
// write with restricted permissions
if err := ioutil.WriteFile(filename, data, 0600); err != nil {
return err
return errors.Wrapf(err, "Error writing file %s", filename)
}
return nil
}
@ -96,7 +96,7 @@ func decode(data []byte) (*api.Config, error) {
config, _, err := latest.Codec.Decode(data, nil, nil)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error decoding config from data: %s", string(data))
}
return config.(*api.Config), nil

View File

@ -23,6 +23,7 @@ import (
"net/http"
"github.com/golang/glog"
"github.com/pkg/errors"
)
const kubernetesVersionGCSURL = "https://storage.googleapis.com/minikube/k8s_releases.json"
@ -53,7 +54,7 @@ type k8sReleases []k8sRelease
func getJson(url string, target *k8sReleases) error {
r, err := http.Get(url)
if err != nil {
return err
return errors.Wrapf(err, "Error getting json from url: %s via http", url)
}
defer r.Body.Close()
@ -63,10 +64,10 @@ func getJson(url string, target *k8sReleases) error {
func getK8sVersionsFromURL(url string) (k8sReleases, error) {
var k8sVersions k8sReleases
if err := getJson(url, &k8sVersions); err != nil {
return k8sReleases{}, err
return k8sReleases{}, errors.Wrapf(err, "Error getting json via http with url: %s", url)
}
if len(k8sVersions) == 0 {
return k8sReleases{}, fmt.Errorf("There were no json k8s Releases at the url specified: %s", url)
return k8sReleases{}, errors.Errorf("There were no json k8s Releases at the url specified: %s", url)
}
return k8sVersions, nil
}

View File

@ -27,6 +27,7 @@ import (
"github.com/blang/semver"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
@ -90,7 +91,7 @@ type releases []release
func getJson(url string, target *releases) error {
r, err := http.Get(url)
if err != nil {
return err
return errors.Wrap(err, "Error getting minikube version url via http")
}
defer r.Body.Close()
@ -101,10 +102,10 @@ func getLatestVersionFromURL(url string) (semver.Version, error) {
var releases releases
glog.Infof("Checking for updates...")
if err := getJson(url, &releases); err != nil {
return semver.Version{}, err
return semver.Version{}, errors.Wrap(err, "Error getting json from minikube version url")
}
if len(releases) == 0 {
return semver.Version{}, fmt.Errorf("There were no json releases at the url specified: %s", url)
return semver.Version{}, errors.Errorf("There were no json releases at the url specified: %s", url)
}
latestVersionString := releases[0].Name
return semver.Make(strings.TrimPrefix(latestVersionString, version.VersionPrefix))
@ -113,7 +114,7 @@ func getLatestVersionFromURL(url string) (semver.Version, error) {
func writeTimeToFile(path string, inputTime time.Time) error {
err := ioutil.WriteFile(path, []byte(inputTime.Format(timeLayout)), 0644)
if err != nil {
return fmt.Errorf("Error writing current update time to file: %s", err)
return errors.Wrap(err, "Error writing current update time to file: ")
}
return nil
}

View File

@ -24,6 +24,7 @@ import (
"github.com/docker/machine/libmachine/drivers"
machinessh "github.com/docker/machine/libmachine/ssh"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
@ -39,7 +40,7 @@ type SSHSession interface {
func NewSSHClient(d drivers.Driver) (*ssh.Client, error) {
h, err := newSSHHost(d)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error creating new ssh host from driver")
}
auth := &machinessh.Auth{}
@ -48,12 +49,12 @@ func NewSSHClient(d drivers.Driver) (*ssh.Client, error) {
}
config, err := machinessh.NewNativeConfig(h.Username, auth)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "Error creating new native config from ssh using: %s, %s", h.Username, auth)
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", h.IP, h.Port), &config)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error dialing tcp via ssh client")
}
return client, nil
}
@ -65,18 +66,18 @@ func Transfer(reader io.Reader, readerLen int, remotedir, filename string, perm
mkdirCmd := fmt.Sprintf("sudo mkdir -p %s", remotedir)
for _, cmd := range []string{deleteCmd, mkdirCmd} {
if err := RunCommand(c, cmd); err != nil {
return err
return errors.Wrapf(err, "Error running command: %s", cmd)
}
}
s, err := c.NewSession()
if err != nil {
return err
return errors.Wrap(err, "Error creating new session via ssh client")
}
w, err := s.StdinPipe()
if err != nil {
return err
return errors.Wrap(err, "Error accessing StdinPipe via ssh session")
}
// The scpcmd below *should not* return until all data is copied and the
// StdinPipe is closed. But let's use a WaitGroup to make it expicit.
@ -92,7 +93,7 @@ func Transfer(reader io.Reader, readerLen int, remotedir, filename string, perm
}()
scpcmd := fmt.Sprintf("sudo /usr/local/bin/scp -t %s", remotedir)
if err := s.Run(scpcmd); err != nil {
return err
return errors.Wrap(err, "Error running scp command")
}
wg.Wait()
@ -103,7 +104,7 @@ func RunCommand(c *ssh.Client, cmd string) error {
s, err := c.NewSession()
defer s.Close()
if err != nil {
return err
return errors.Wrap(err, "Error creating new session for ssh client")
}
return s.Run(cmd)
@ -120,11 +121,11 @@ func newSSHHost(d drivers.Driver) (*sshHost, error) {
ip, err := d.GetSSHHostname()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error getting ssh host name for driver")
}
port, err := d.GetSSHPort()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error getting ssh port for driver")
}
return &sshHost{
IP: ip,

View File

@ -25,6 +25,7 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/mcnerror"
"github.com/docker/machine/libmachine/state"
"github.com/pkg/errors"
)
// MockAPI is a struct used to mock out libmachine.API
@ -51,7 +52,7 @@ func (api *MockAPI) Close() error {
func (api *MockAPI) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
var driver MockDriver
if err := json.Unmarshal(rawDriver, &driver); err != nil {
return nil, err
return nil, errors.Wrap(err, "Error unmarshalling json")
}
h := &host.Host{
DriverName: driverName,

View File

@ -25,6 +25,7 @@ import (
"strconv"
"github.com/golang/glog"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
@ -50,11 +51,11 @@ func NewSSHServer() (*SSHServer, error) {
private, err := rsa.GenerateKey(rand.Reader, 2014)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error generating RSA key")
}
signer, err := ssh.NewSignerFromKey(private)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error creating signer from key")
}
s.Config.AddHostKey(signer)
return s, nil
@ -68,7 +69,7 @@ type execRequest struct {
func (s *SSHServer) Start() (int, error) {
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return 0, err
return 0, errors.Wrap(err, "Error creating tcp listener for ssh server")
}
// Main loop, listen for connections and store the commands.
@ -126,11 +127,11 @@ func (s *SSHServer) Start() (int, error) {
// Parse and return the port.
_, p, err := net.SplitHostPort(listener.Addr().String())
if err != nil {
return 0, err
return 0, errors.Wrap(err, "Error splitting host port")
}
port, err := strconv.Atoi(p)
if err != nil {
return 0, err
return 0, errors.Wrap(err, "Error converting port string to integer")
}
return port, nil
}

View File

@ -23,19 +23,20 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"net"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
)
func GenerateCACert(certPath, keyPath string) error {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
return errors.Wrap(err, "Error generating rsa key")
}
template := x509.Certificate{
@ -62,27 +63,27 @@ func GenerateCACert(certPath, keyPath string) error {
func GenerateSignedCert(certPath, keyPath string, ips []net.IP, alternateDNS []string, signerCertPath, signerKeyPath string) error {
signerCertBytes, err := ioutil.ReadFile(signerCertPath)
if err != nil {
return err
return errors.Wrap(err, "Error reading file: signerCertPath")
}
decodedSignerCert, _ := pem.Decode(signerCertBytes)
if decodedSignerCert == nil {
return fmt.Errorf("Unable to decode certificate.")
return errors.New("Unable to decode certificate.")
}
signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)
if err != nil {
return err
return errors.Wrap(err, "Error parsing certificate: decodedSignerCert.Bytes")
}
signerKeyBytes, err := ioutil.ReadFile(signerKeyPath)
if err != nil {
return err
return errors.Wrap(err, "Error reading file: signerKeyPath")
}
decodedSignerKey, _ := pem.Decode(signerKeyBytes)
if decodedSignerKey == nil {
return fmt.Errorf("Unable to decode key.")
return errors.New("Unable to decode key.")
}
signerKey, err := x509.ParsePKCS1PrivateKey(decodedSignerKey.Bytes)
if err != nil {
return err
return errors.Wrap(err, "Error parsing prive key: decodedSignerKey.Bytes")
}
template := x509.Certificate{
@ -103,7 +104,7 @@ func GenerateSignedCert(certPath, keyPath string, ips []net.IP, alternateDNS []s
priv, err := loadOrGeneratePrivateKey(keyPath)
if err != nil {
return err
return errors.Wrap(err, "Error loading or generating private key: keyPath")
}
return writeCertsAndKeys(&template, certPath, priv, keyPath, signerCert, signerKey)
@ -122,7 +123,7 @@ func loadOrGeneratePrivateKey(keyPath string) (*rsa.PrivateKey, error) {
}
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error generating RSA key")
}
return priv, nil
}
@ -130,31 +131,31 @@ func loadOrGeneratePrivateKey(keyPath string) (*rsa.PrivateKey, error) {
func writeCertsAndKeys(template *x509.Certificate, certPath string, signeeKey *rsa.PrivateKey, keyPath string, parent *x509.Certificate, signingKey *rsa.PrivateKey) error {
derBytes, err := x509.CreateCertificate(rand.Reader, template, parent, &signeeKey.PublicKey, signingKey)
if err != nil {
return err
return errors.Wrap(err, "Error creating certificate")
}
certBuffer := bytes.Buffer{}
if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return err
return errors.Wrap(err, "Error encoding certificate")
}
keyBuffer := bytes.Buffer{}
if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(signeeKey)}); err != nil {
return err
return errors.Wrap(err, "Error encoding key")
}
if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil {
return err
return errors.Wrap(err, "Error creating certificate directory")
}
if err := ioutil.WriteFile(certPath, certBuffer.Bytes(), os.FileMode(0644)); err != nil {
return err
return errors.Wrap(err, "Error writing certificate to cert path")
}
if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
return err
return errors.Wrap(err, "Error creating key directory")
}
if err := ioutil.WriteFile(keyPath, keyBuffer.Bytes(), os.FileMode(0600)); err != nil {
return err
return errors.Wrap(err, "Error writing key file")
}
return nil

View File

@ -25,6 +25,7 @@ import (
"time"
"github.com/blang/semver"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/version"
)
@ -88,7 +89,7 @@ func RetryAfter(attempts int, callback func() error, d time.Duration) (err error
func GetLocalkubeDownloadURL(versionOrURL string, filename string) (string, error) {
urlObj, err := url.Parse(versionOrURL)
if err != nil {
return "", err
return "", errors.Wrap(err, "Error parsing localkube download url")
}
if urlObj.IsAbs() {
// scheme was specified in input, is a valid URI.
@ -100,7 +101,7 @@ func GetLocalkubeDownloadURL(versionOrURL string, filename string) (string, erro
versionOrURL = "v" + versionOrURL
}
if _, err = semver.Make(strings.TrimPrefix(versionOrURL, version.VersionPrefix)); err != nil {
return "", err
return "", errors.Wrap(err, "Error creating semver version from localkube version input string")
}
return fmt.Sprintf("%s%s/%s", constants.LocalkubeDownloadURLPrefix, versionOrURL, filename), nil
}
@ -124,13 +125,23 @@ func (m MultiError) ToError() error {
for _, err := range m.Errors {
errStrings = append(errStrings, err.Error())
}
return fmt.Errorf(strings.Join(errStrings, "\n"))
return errors.New(strings.Join(errStrings, "\n"))
}
type ServiceContext struct {
Service string `json:"service"`
Version string `json:"version"`
}
type Message struct {
Message string `json:"message"`
ServiceContext `json:"serviceContext"`
}
func IsDirectory(path string) (bool, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return false, err
return false, errors.Wrapf(err, "Error calling os.Stat on file %s", path)
}
return fileInfo.IsDir(), nil
}

View File

@ -17,19 +17,19 @@ limitations under the License.
package util
import (
"fmt"
"testing"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
)
// Returns a function that will return n errors, then return successfully forever.
func errorGenerator(n int) func() error {
errors := 0
errorCount := 0
return func() (err error) {
if errors < n {
errors += 1
return fmt.Errorf("Error!")
if errorCount < n {
errorCount += 1
return errors.New("Error!")
}
return nil
}
@ -93,8 +93,8 @@ func TestGetLocalkubeDownloadURL(t *testing.T) {
func TestMultiError(t *testing.T) {
m := MultiError{}
m.Collect(fmt.Errorf("Error 1"))
m.Collect(fmt.Errorf("Error 2"))
m.Collect(errors.New("Error 1"))
m.Collect(errors.New("Error 2"))
err := m.ToError()
expected := `Error 1

24
vendor/github.com/pkg/errors/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

10
vendor/github.com/pkg/errors/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,10 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.3
- 1.5.4
- 1.6.2
- tip
script:
- go test -v ./...

23
vendor/github.com/pkg/errors/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

52
vendor/github.com/pkg/errors/README.md generated vendored Normal file
View File

@ -0,0 +1,52 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## Licence
BSD-2-Clause

32
vendor/github.com/pkg/errors/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,32 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

238
vendor/github.com/pkg/errors/errors.go generated vendored Normal file
View File

@ -0,0 +1,238 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

178
vendor/github.com/pkg/errors/stack.go generated vendored Normal file
View File

@ -0,0 +1,178 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s path of source file relative to the compile time GOPATH
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}
func trimGOPATH(name, file string) string {
// Here we want to get the source file path relative to the compile time
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
// GOPATH at runtime, but we can infer the number of path segments in the
// GOPATH. We note that fn.Name() returns the function name qualified by
// the import path, which does not include the GOPATH. Thus we can trim
// segments from the beginning of the file path until the number of path
// separators remaining is one more than the number of path separators in
// the function name. For example, given:
//
// GOPATH /home/user
// file /home/user/src/pkg/sub/file.go
// fn.Name() pkg/sub.Type.Method
//
// We want to produce:
//
// pkg/sub/file.go
//
// From this we can easily see that fn.Name() has one less path separator
// than our desired output. We count separators from the end of the file
// path until it finds two more than in the function name and then move
// one character forward to preserve the initial path segment without a
// leading separator.
const sep = "/"
goal := strings.Count(name, sep) + 2
i := len(file)
for n := 0; n < goal; n++ {
i = strings.LastIndex(file[:i], sep)
if i == -1 {
// not enough separators found, set i so that the slice expression
// below leaves file unmodified
i = -len(sep)
break
}
}
// get back to 0 or trim the leading separator
file = file[i+len(sep):]
return file
}