Import upstream changes up to constabulary/gb@218104db
diff --git a/fetch.go b/fetch.go
index 831d620..dd953a8 100644
--- a/fetch.go
+++ b/fetch.go
@@ -91,14 +91,7 @@
 		return fmt.Errorf("%s is already vendored", path)
 	}
 
-	var wc vendor.WorkingCopy
-
-	// if we are not recursing, then always fetch the HEAD of the master
-	if recurse {
-		wc, err = repo.Checkout(branch, tag, revision)
-	} else {
-		wc, err = repo.Checkout("", "", "")
-	}
+	wc, err := repo.Checkout(branch, tag, revision)
 
 	if err != nil {
 		return err
@@ -145,6 +138,12 @@
 		return nil
 	}
 
+	// if we are recursing, overwrite branch, tag and revision
+	// values so recursive fetching checks out from HEAD.
+	branch = ""
+	tag = ""
+	revision = ""
+
 	for done := false; !done; {
 
 		paths := []struct {
diff --git a/gbvendor/copy.go b/gbvendor/copy.go
index 1d2f599..52d4c98 100644
--- a/gbvendor/copy.go
+++ b/gbvendor/copy.go
@@ -61,6 +61,7 @@
 	if err != nil {
 		return fmt.Errorf("copyfile: create(%q): %v", dst, err)
 	}
+	defer w.Close()
 	if debugCopyfile {
 		fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src)
 	}
diff --git a/gbvendor/imports.go b/gbvendor/imports.go
index d3c34b2..80174af 100644
--- a/gbvendor/imports.go
+++ b/gbvendor/imports.go
@@ -5,7 +5,6 @@
 	"go/parser"
 	"go/token"
 	"io"
-	"log"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -48,36 +47,36 @@
 }
 
 // FetchMetadata fetchs the remote metadata for path.
-func FetchMetadata(path string, insecure bool) (io.ReadCloser, error) {
-	schemes := []string{"https", "http"}
-	for _, s := range schemes {
-		if r, err := fetchMetadata(s, path, insecure); err == nil {
-			return r, nil
+func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) {
+	defer func() {
+		if err != nil {
+			err = fmt.Errorf("unable to determine remote metadata protocol: %s", err)
 		}
+	}()
+	// try https first
+	rc, err = fetchMetadata("https", path)
+	if err == nil {
+		return
 	}
-	return nil, fmt.Errorf("unable to determine remote metadata protocol")
+	// try http if supported
+	if insecure {
+		rc, err = fetchMetadata("http", path)
+	}
+	return
 }
 
-func fetchMetadata(scheme, path string, insecure bool) (io.ReadCloser, error) {
+func fetchMetadata(scheme, path string) (io.ReadCloser, error) {
 	url := fmt.Sprintf("%s://%s?go-get=1", scheme, path)
 	switch scheme {
-	case "https":
+	case "https", "http":
 		resp, err := http.Get(url)
-		if err == nil {
-			return resp.Body, nil
+		if err != nil {
+			return nil, fmt.Errorf("failed to access url %q", url)
 		}
-	case "http":
-		if !insecure {
-			log.Printf("skipping insecure protocol: %v", url)
-		} else {
-			resp, err := http.Get(url)
-			if err == nil {
-				return resp.Body, nil
-			}
-		}
+		return resp.Body, nil
+	default:
+		return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme)
 	}
-
-	return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme)
 }
 
 // ParseMetadata fetchs and decodes remote metadata for path.
diff --git a/gbvendor/imports_test.go b/gbvendor/imports_test.go
index 2794292..37d029d 100644
--- a/gbvendor/imports_test.go
+++ b/gbvendor/imports_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"bytes"
-	"fmt"
 	"io"
 	"os"
 	"path/filepath"
@@ -28,11 +27,12 @@
 	if testing.Short() {
 		t.Skipf("skipping network tests in -short mode")
 	}
-	tests := []struct {
+	type testParams struct {
 		path     string
 		want     string
 		insecure bool
-	}{{
+	}
+	tests := []testParams{{
 		path: "golang.org/x/tools/cmd/godoc",
 		want: `<!DOCTYPE html>
 <html>
@@ -80,6 +80,32 @@
 			t.Errorf("FetchMetadata(%q): want %q, got %q", tt.path, tt.want, got)
 		}
 	}
+
+	// Test for error catch.
+	errTests := []testParams{{
+		path:     "any.inaccessible.server/the.project",
+		want:     `unable to determine remote metadata protocol: failed to access url "http://any.inaccessible.server/the.project?go-get=1"`,
+		insecure: true,
+	}, {
+		path:     "any.inaccessible.server/the.project",
+		want:     `unable to determine remote metadata protocol: failed to access url "https://any.inaccessible.server/the.project?go-get=1"`,
+		insecure: false,
+	}}
+
+	for _, ett := range errTests {
+		r, err := FetchMetadata(ett.path, ett.insecure)
+		if err == nil {
+			t.Errorf("Access to url %q without any error, but the error should be happen.", ett.path)
+			if r != nil {
+				r.Close()
+			}
+			continue
+		}
+		got := err.Error()
+		if got != ett.want {
+			t.Errorf("FetchMetadata(%q): want %q, got %q", ett.path, ett.want, got)
+		}
+	}
 }
 
 func TestParseMetadata(t *testing.T) {
@@ -108,9 +134,10 @@
 		importpath: "gopkg.in/mgo.v2",
 		vcs:        "git",
 		reporoot:   "https://gopkg.in/mgo.v2",
-	}, {
-		path: "speter.net/go/exp",
-		err:  fmt.Errorf("go-import metadata not found"),
+		//	disabled: certificate has expired
+		//	}, {
+		//		path: "speter.net/go/exp",
+		//		err:  fmt.Errorf("go-import metadata not found"),
 	}}
 
 	for _, tt := range tests {
diff --git a/gbvendor/remove.go b/gbvendor/path.go
similarity index 70%
rename from gbvendor/remove.go
rename to gbvendor/path.go
index fdc155b..bb8334d 100644
--- a/gbvendor/remove.go
+++ b/gbvendor/path.go
@@ -10,8 +10,17 @@
 // deletes read only files on Windows.
 func RemoveAll(path string) error {
 	if runtime.GOOS == "windows" {
+		// Simple case: if Remove works, we're done.
+		err := os.Remove(path)
+		if err == nil || os.IsNotExist(err) {
+			return nil
+		}
 		// make sure all files are writable so we can delete them
 		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+			if err != nil {
+				// walk gave us some error, give it back.
+				return err
+			}
 			mode := info.Mode()
 			if mode|0200 == mode {
 				return nil
diff --git a/gbvendor/path_test.go b/gbvendor/path_test.go
new file mode 100644
index 0000000..2bba91b
--- /dev/null
+++ b/gbvendor/path_test.go
@@ -0,0 +1,106 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package vendor
+
+import (
+	"os"
+	"runtime"
+	"testing"
+)
+
+var isReadonlyError = func(error) bool { return false }
+
+func TestRemoveAll(t *testing.T) {
+	tmpDir := os.TempDir()
+	// Work directory.
+	path := tmpDir + "/_TestRemoveAll_"
+	fpath := path + "/file"
+	dpath := path + "/dir"
+
+	// Make directory with 1 file and remove.
+	if err := os.MkdirAll(path, 0777); err != nil {
+		t.Fatalf("MkdirAll %q: %s", path, err)
+	}
+	fd, err := os.Create(fpath)
+	if err != nil {
+		t.Fatalf("create %q: %s", fpath, err)
+	}
+	fd.Close()
+	if err = RemoveAll(path); err != nil {
+		t.Fatalf("RemoveAll %q (first): %s", path, err)
+	}
+	if _, err = os.Lstat(path); err == nil {
+		t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
+	}
+
+	// Make directory with file and subdirectory and remove.
+	if err = os.MkdirAll(dpath, 0777); err != nil {
+		t.Fatalf("MkdirAll %q: %s", dpath, err)
+	}
+	fd, err = os.Create(fpath)
+	if err != nil {
+		t.Fatalf("create %q: %s", fpath, err)
+	}
+	fd.Close()
+	fd, err = os.Create(dpath + "/file")
+	if err != nil {
+		t.Fatalf("create %q: %s", fpath, err)
+	}
+	fd.Close()
+	if err = RemoveAll(path); err != nil {
+		t.Fatalf("RemoveAll %q (second): %s", path, err)
+	}
+	if _, err := os.Lstat(path); err == nil {
+		t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
+	}
+
+	// Determine if we should run the following test.
+	testit := true
+	if runtime.GOOS == "windows" {
+		// Chmod is not supported under windows.
+		testit = false
+	} else {
+		// Test fails as root.
+		testit = os.Getuid() != 0
+	}
+	if testit {
+		// Make directory with file and subdirectory and trigger error.
+		if err = os.MkdirAll(dpath, 0777); err != nil {
+			t.Fatalf("MkdirAll %q: %s", dpath, err)
+		}
+
+		for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
+			fd, err = os.Create(s)
+			if err != nil {
+				t.Fatalf("create %q: %s", s, err)
+			}
+			fd.Close()
+		}
+		if err = os.Chmod(dpath, 0); err != nil {
+			t.Fatalf("Chmod %q 0: %s", dpath, err)
+		}
+
+		// No error checking here: either RemoveAll
+		// will or won't be able to remove dpath;
+		// either way we want to see if it removes fpath
+		// and path/zzz.  Reasons why RemoveAll might
+		// succeed in removing dpath as well include:
+		//	* running as root
+		//	* running on a file system without permissions (FAT)
+		RemoveAll(path)
+		os.Chmod(dpath, 0777)
+
+		for _, s := range []string{fpath, path + "/zzz"} {
+			if _, err = os.Lstat(s); err == nil {
+				t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
+			}
+		}
+	}
+	if err = RemoveAll(path); err != nil {
+		t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
+	}
+	if _, err = os.Lstat(path); err == nil {
+		t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
+	}
+}