Explorar o código

Added GCS support #8370

Konstantin Chukhlomin %!s(int64=8) %!d(string=hai) anos
pai
achega
72d7c4d620
Modificáronse 34 ficheiros con 4429 adicións e 8 borrados
  1. 4 0
      conf/defaults.ini
  2. 5 1
      conf/sample.ini
  3. 11 1
      docs/sources/installation/configuration.md
  4. 56 0
      pkg/components/imguploader/gcpuploader.go
  5. 23 0
      pkg/components/imguploader/gcpuploader_test.go
  6. 10 0
      pkg/components/imguploader/imguploader.go
  7. 23 0
      pkg/components/imguploader/imguploader_test.go
  8. 202 0
      vendor/cloud.google.com/go/LICENSE
  9. 256 0
      vendor/cloud.google.com/go/iam/iam.go
  10. 94 0
      vendor/cloud.google.com/go/internal/optional/optional.go
  11. 56 0
      vendor/cloud.google.com/go/internal/retry.go
  12. 6 0
      vendor/cloud.google.com/go/internal/version/update_version.sh
  13. 71 0
      vendor/cloud.google.com/go/internal/version/version.go
  14. 252 0
      vendor/cloud.google.com/go/storage/acl.go
  15. 590 0
      vendor/cloud.google.com/go/storage/bucket.go
  16. 201 0
      vendor/cloud.google.com/go/storage/copy.go
  17. 161 0
      vendor/cloud.google.com/go/storage/doc.go
  18. 26 0
      vendor/cloud.google.com/go/storage/go17.go
  19. 108 0
      vendor/cloud.google.com/go/storage/iam.go
  20. 43 0
      vendor/cloud.google.com/go/storage/invoke.go
  21. 26 0
      vendor/cloud.google.com/go/storage/not_go17.go
  22. 74 0
      vendor/cloud.google.com/go/storage/reader.go
  23. 1117 0
      vendor/cloud.google.com/go/storage/storage.go
  24. 192 0
      vendor/cloud.google.com/go/storage/writer.go
  25. 27 0
      vendor/github.com/googleapis/gax-go/CONTRIBUTING.md
  26. 27 0
      vendor/github.com/googleapis/gax-go/LICENSE
  27. 24 0
      vendor/github.com/googleapis/gax-go/README.md
  28. 157 0
      vendor/github.com/googleapis/gax-go/call_option.go
  29. 40 0
      vendor/github.com/googleapis/gax-go/gax.go
  30. 24 0
      vendor/github.com/googleapis/gax-go/header.go
  31. 90 0
      vendor/github.com/googleapis/gax-go/invoke.go
  32. 176 0
      vendor/github.com/googleapis/gax-go/path_template.go
  33. 227 0
      vendor/github.com/googleapis/gax-go/path_template_parser.go
  34. 30 6
      vendor/vendor.json

+ 4 - 0
conf/defaults.ini

@@ -467,3 +467,7 @@ url =
 username =
 password =
 public_url =
+
+[external_image_storage.gcp]
+key_file =
+bucket =

+ 5 - 1
conf/sample.ini

@@ -399,7 +399,7 @@
 #################################### External image storage ##########################
 [external_image_storage]
 # Used for uploading images to public servers so they can be included in slack/email messages.
-# you can choose between (s3, webdav)
+# you can choose between (s3, webdav, gcp)
 ;provider =
 
 [external_image_storage.s3]
@@ -412,3 +412,7 @@
 ;public_url =
 ;username =
 ;password =
+
+[external_image_storage.gcp]
+;key_file =
+;bucket =

+ 11 - 1
docs/sources/installation/configuration.md

@@ -645,7 +645,7 @@ Time to live for snapshots.
 These options control how images should be made public so they can be shared on services like slack.
 
 ### provider
-You can choose between (s3, webdav). If left empty Grafana will ignore the upload action.
+You can choose between (s3, webdav, gcp). If left empty Grafana will ignore the upload action.
 
 ## [external_image_storage.s3]
 
@@ -677,6 +677,16 @@ basic auth username
 ### password
 basic auth password
 
+## [external_image_storage.gcp]
+
+### key_file
+Path to JSON key file associated with a Google service account to authenticate and authorize.
+Service Account keys can be created and downloaded from https://console.developers.google.com/permissions/serviceaccounts.
+
+### bucket name
+
+Bucket Name on Google Cloud Storage. 
+
 ## [alerting]
 
 ### enabled

+ 56 - 0
pkg/components/imguploader/gcpuploader.go

@@ -0,0 +1,56 @@
+package imguploader
+
+import (
+  "github.com/grafana/grafana/pkg/log"
+  "github.com/grafana/grafana/pkg/util"
+  "google.golang.org/api/option"
+  "cloud.google.com/go/storage"
+  "golang.org/x/net/context"
+  "io/ioutil"
+  "fmt"
+)
+
+type GCPUploader struct {
+  keyFile string
+  bucket  string
+  log     log.Logger
+}
+
+func NewGCPUploader(keyFile, bucket string) *GCPUploader {
+  return &GCPUploader{
+    keyFile: keyFile,
+    bucket:  bucket,
+    log:     log.New("gcpuploader"),
+  }
+}
+
+func (u *GCPUploader) Upload(imageDiskPath string) (string, error) {
+  ctx := context.Background()
+
+  client, err := storage.NewClient(ctx, option.WithServiceAccountFile(u.keyFile))
+  if err != nil {
+    return "", err
+  }
+
+  key := util.GetRandomString(20) + ".png"
+  log.Debug("Uploading image to GCP bucket = %s key = %s", u.bucket, key)
+
+  file, err := ioutil.ReadFile(imageDiskPath)
+  if err != nil {
+    return "", err
+  }
+
+  wc := client.Bucket(u.bucket).Object(key).NewWriter(ctx)
+  wc.ContentType = "image/png"
+  wc.ACL = []storage.ACLRule{{Entity: storage.AllUsers, Role: storage.RoleReader}}
+
+  if _, err := wc.Write(file); err != nil {
+    return "", err
+  }
+
+  if err := wc.Close(); err != nil {
+    return "", err
+  }
+
+  return fmt.Sprintf("https://storage.googleapis.com/%s/%s", u.bucket, key), nil
+}

+ 23 - 0
pkg/components/imguploader/gcpuploader_test.go

@@ -0,0 +1,23 @@
+package imguploader
+
+import (
+	"testing"
+
+	"github.com/grafana/grafana/pkg/setting"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestUploadToGCP(t *testing.T) {
+	SkipConvey("[Integration test] for external_image_store.gcp", t, func() {
+		setting.NewConfigContext(&setting.CommandLineArgs{
+			HomePath: "../../../",
+		})
+
+		gcpUploader, _ := NewImageUploader()
+
+		path, err := gcpUploader.Upload("../../../public/img/logo_transparent_400x.png")
+
+		So(err, ShouldBeNil)
+		So(path, ShouldNotEqual, "")
+	})
+}

+ 10 - 0
pkg/components/imguploader/imguploader.go

@@ -52,6 +52,16 @@ func NewImageUploader() (ImageUploader, error) {
 		password := webdavSec.Key("password").String()
 
 		return NewWebdavImageUploader(url, username, password, public_url)
+  case "gcp":
+    gcpsec, err := setting.Cfg.GetSection("external_image_storage.gcp")
+    if err != nil {
+      return nil, err
+    }
+
+    keyFile := gcpsec.Key("key_file").MustString("")
+    bucketName := gcpsec.Key("bucket").MustString("")
+
+    return NewGCPUploader(keyFile, bucketName), nil
 	}
 
 	return NopImageUploader{}, nil

+ 23 - 0
pkg/components/imguploader/imguploader_test.go

@@ -96,5 +96,28 @@ func TestImageUploaderFactory(t *testing.T) {
 			So(original.username, ShouldEqual, "username")
 			So(original.password, ShouldEqual, "password")
 		})
+
+    Convey("GCP uploader", func() {
+			var err error
+
+			setting.NewConfigContext(&setting.CommandLineArgs{
+				HomePath: "../../../",
+			})
+
+			setting.ImageUploadProvider = "gcp"
+
+			gcpSec, err := setting.Cfg.GetSection("external_image_storage.gcp")
+			gcpSec.NewKey("key_file", "/etc/secrets/project-79a52befa3f6.json")
+			gcpSec.NewKey("bucket", "project-grafana-east")
+
+			uploader, err := NewImageUploader()
+
+			So(err, ShouldBeNil)
+			original, ok := uploader.(*GCPUploader)
+
+			So(ok, ShouldBeTrue)
+			So(original.keyFile, ShouldEqual, "/etc/secrets/project-79a52befa3f6.json")
+			So(original.bucket, ShouldEqual, "project-grafana-east")
+		})
 	})
 }

+ 202 - 0
vendor/cloud.google.com/go/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2014 Google Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 256 - 0
vendor/cloud.google.com/go/iam/iam.go

@@ -0,0 +1,256 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package iam supports the resource-specific operations of Google Cloud
+// IAM (Identity and Access Management) for the Google Cloud Libraries.
+// See https://cloud.google.com/iam for more about IAM.
+//
+// Users of the Google Cloud Libraries will typically not use this package
+// directly. Instead they will begin with some resource that supports IAM, like
+// a pubsub topic, and call its IAM method to get a Handle for that resource.
+package iam
+
+import (
+	"golang.org/x/net/context"
+	pb "google.golang.org/genproto/googleapis/iam/v1"
+	"google.golang.org/grpc"
+)
+
+// client abstracts the IAMPolicy API to allow multiple implementations.
+type client interface {
+	Get(ctx context.Context, resource string) (*pb.Policy, error)
+	Set(ctx context.Context, resource string, p *pb.Policy) error
+	Test(ctx context.Context, resource string, perms []string) ([]string, error)
+}
+
+// grpcClient implements client for the standard gRPC-based IAMPolicy service.
+type grpcClient struct {
+	c pb.IAMPolicyClient
+}
+
+func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) {
+	proto, err := g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource})
+	if err != nil {
+		return nil, err
+	}
+	return proto, nil
+}
+func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error {
+	_, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{
+		Resource: resource,
+		Policy:   p,
+	})
+	return err
+}
+
+func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
+	res, err := g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{
+		Resource:    resource,
+		Permissions: perms,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return res.Permissions, nil
+}
+
+// A Handle provides IAM operations for a resource.
+type Handle struct {
+	c        client
+	resource string
+}
+
+// InternalNewHandle is for use by the Google Cloud Libraries only.
+//
+// InternalNewHandle returns a Handle for resource.
+// The conn parameter refers to a server that must support the IAMPolicy service.
+func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle {
+	return InternalNewHandleClient(&grpcClient{c: pb.NewIAMPolicyClient(conn)}, resource)
+}
+
+// InternalNewHandleClient is for use by the Google Cloud Libraries only.
+//
+// InternalNewHandleClient returns a Handle for resource using the given
+// client implementation.
+func InternalNewHandleClient(c client, resource string) *Handle {
+	return &Handle{
+		c:        c,
+		resource: resource,
+	}
+}
+
+// Policy retrieves the IAM policy for the resource.
+func (h *Handle) Policy(ctx context.Context) (*Policy, error) {
+	proto, err := h.c.Get(ctx, h.resource)
+	if err != nil {
+		return nil, err
+	}
+	return &Policy{InternalProto: proto}, nil
+}
+
+// SetPolicy replaces the resource's current policy with the supplied Policy.
+//
+// If policy was created from a prior call to Get, then the modification will
+// only succeed if the policy has not changed since the Get.
+func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error {
+	return h.c.Set(ctx, h.resource, policy.InternalProto)
+}
+
+// TestPermissions returns the subset of permissions that the caller has on the resource.
+func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) {
+	return h.c.Test(ctx, h.resource, permissions)
+}
+
+// A RoleName is a name representing a collection of permissions.
+type RoleName string
+
+// Common role names.
+const (
+	Owner  RoleName = "roles/owner"
+	Editor RoleName = "roles/editor"
+	Viewer RoleName = "roles/viewer"
+)
+
+const (
+	// AllUsers is a special member that denotes all users, even unauthenticated ones.
+	AllUsers = "allUsers"
+
+	// AllAuthenticatedUsers is a special member that denotes all authenticated users.
+	AllAuthenticatedUsers = "allAuthenticatedUsers"
+)
+
+// A Policy is a list of Bindings representing roles
+// granted to members.
+//
+// The zero Policy is a valid policy with no bindings.
+type Policy struct {
+	// TODO(jba): when type aliases are available, put Policy into an internal package
+	// and provide an exported alias here.
+
+	// This field is exported for use by the Google Cloud Libraries only.
+	// It may become unexported in a future release.
+	InternalProto *pb.Policy
+}
+
+// Members returns the list of members with the supplied role.
+// The return value should not be modified. Use Add and Remove
+// to modify the members of a role.
+func (p *Policy) Members(r RoleName) []string {
+	b := p.binding(r)
+	if b == nil {
+		return nil
+	}
+	return b.Members
+}
+
+// HasRole reports whether member has role r.
+func (p *Policy) HasRole(member string, r RoleName) bool {
+	return memberIndex(member, p.binding(r)) >= 0
+}
+
+// Add adds member member to role r if it is not already present.
+// A new binding is created if there is no binding for the role.
+func (p *Policy) Add(member string, r RoleName) {
+	b := p.binding(r)
+	if b == nil {
+		if p.InternalProto == nil {
+			p.InternalProto = &pb.Policy{}
+		}
+		p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{
+			Role:    string(r),
+			Members: []string{member},
+		})
+		return
+	}
+	if memberIndex(member, b) < 0 {
+		b.Members = append(b.Members, member)
+		return
+	}
+}
+
+// Remove removes member from role r if it is present.
+func (p *Policy) Remove(member string, r RoleName) {
+	bi := p.bindingIndex(r)
+	if bi < 0 {
+		return
+	}
+	bindings := p.InternalProto.Bindings
+	b := bindings[bi]
+	mi := memberIndex(member, b)
+	if mi < 0 {
+		return
+	}
+	// Order doesn't matter for bindings or members, so to remove, move the last item
+	// into the removed spot and shrink the slice.
+	if len(b.Members) == 1 {
+		// Remove binding.
+		last := len(bindings) - 1
+		bindings[bi] = bindings[last]
+		bindings[last] = nil
+		p.InternalProto.Bindings = bindings[:last]
+		return
+	}
+	// Remove member.
+	// TODO(jba): worry about multiple copies of m?
+	last := len(b.Members) - 1
+	b.Members[mi] = b.Members[last]
+	b.Members[last] = ""
+	b.Members = b.Members[:last]
+}
+
+// Roles returns the names of all the roles that appear in the Policy.
+func (p *Policy) Roles() []RoleName {
+	if p.InternalProto == nil {
+		return nil
+	}
+	var rns []RoleName
+	for _, b := range p.InternalProto.Bindings {
+		rns = append(rns, RoleName(b.Role))
+	}
+	return rns
+}
+
+// binding returns the Binding for the suppied role, or nil if there isn't one.
+func (p *Policy) binding(r RoleName) *pb.Binding {
+	i := p.bindingIndex(r)
+	if i < 0 {
+		return nil
+	}
+	return p.InternalProto.Bindings[i]
+}
+
+func (p *Policy) bindingIndex(r RoleName) int {
+	if p.InternalProto == nil {
+		return -1
+	}
+	for i, b := range p.InternalProto.Bindings {
+		if b.Role == string(r) {
+			return i
+		}
+	}
+	return -1
+}
+
+// memberIndex returns the index of m in b's Members, or -1 if not found.
+func memberIndex(m string, b *pb.Binding) int {
+	if b == nil {
+		return -1
+	}
+	for i, mm := range b.Members {
+		if mm == m {
+			return i
+		}
+	}
+	return -1
+}

+ 94 - 0
vendor/cloud.google.com/go/internal/optional/optional.go

@@ -0,0 +1,94 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package optional provides versions of primitive types that can
+// be nil. These are useful in methods that update some of an API object's
+// fields.
+package optional
+
+import (
+	"fmt"
+	"strings"
+)
+
+type (
+	// Bool is either a bool or nil.
+	Bool interface{}
+
+	// String is either a string or nil.
+	String interface{}
+
+	// Int is either an int or nil.
+	Int interface{}
+
+	// Uint is either a uint or nil.
+	Uint interface{}
+
+	// Float64 is either a float64 or nil.
+	Float64 interface{}
+)
+
+// ToBool returns its argument as a bool.
+// It panics if its argument is nil or not a bool.
+func ToBool(v Bool) bool {
+	x, ok := v.(bool)
+	if !ok {
+		doPanic("Bool", v)
+	}
+	return x
+}
+
+// ToString returns its argument as a string.
+// It panics if its argument is nil or not a string.
+func ToString(v String) string {
+	x, ok := v.(string)
+	if !ok {
+		doPanic("String", v)
+	}
+	return x
+}
+
+// ToInt returns its argument as an int.
+// It panics if its argument is nil or not an int.
+func ToInt(v Int) int {
+	x, ok := v.(int)
+	if !ok {
+		doPanic("Int", v)
+	}
+	return x
+}
+
+// ToUint returns its argument as a uint.
+// It panics if its argument is nil or not a uint.
+func ToUint(v Uint) uint {
+	x, ok := v.(uint)
+	if !ok {
+		doPanic("Uint", v)
+	}
+	return x
+}
+
+// ToFloat64 returns its argument as a float64.
+// It panics if its argument is nil or not a float64.
+func ToFloat64(v Float64) float64 {
+	x, ok := v.(float64)
+	if !ok {
+		doPanic("Float64", v)
+	}
+	return x
+}
+
+func doPanic(capType string, v interface{}) {
+	panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v))
+}

+ 56 - 0
vendor/cloud.google.com/go/internal/retry.go

@@ -0,0 +1,56 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+	"fmt"
+	"time"
+
+	gax "github.com/googleapis/gax-go"
+
+	"golang.org/x/net/context"
+)
+
+// Retry calls the supplied function f repeatedly according to the provided
+// backoff parameters. It returns when one of the following occurs:
+// When f's first return value is true, Retry immediately returns with f's second
+// return value.
+// When the provided context is done, Retry returns with an error that
+// includes both ctx.Error() and the last error returned by f.
+func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
+	return retry(ctx, bo, f, gax.Sleep)
+}
+
+func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
+	sleep func(context.Context, time.Duration) error) error {
+	var lastErr error
+	for {
+		stop, err := f()
+		if stop {
+			return err
+		}
+		// Remember the last "real" error from f.
+		if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
+			lastErr = err
+		}
+		p := bo.Pause()
+		if cerr := sleep(ctx, p); cerr != nil {
+			if lastErr != nil {
+				return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
+			}
+			return cerr
+		}
+	}
+}

+ 6 - 0
vendor/cloud.google.com/go/internal/version/update_version.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+today=$(date +%Y%m%d)
+
+sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE
+

+ 71 - 0
vendor/cloud.google.com/go/internal/version/version.go

@@ -0,0 +1,71 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:generate ./update_version.sh
+
+// Package version contains version information for Google Cloud Client
+// Libraries for Go, as reported in request headers.
+package version
+
+import (
+	"runtime"
+	"strings"
+	"unicode"
+)
+
+// Repo is the current version of the client libraries in this
+// repo. It should be a date in YYYYMMDD format.
+const Repo = "20170621"
+
+// Go returns the Go runtime version. The returned string
+// has no whitespace.
+func Go() string {
+	return goVersion
+}
+
+var goVersion = goVer(runtime.Version())
+
+const develPrefix = "devel +"
+
+func goVer(s string) string {
+	if strings.HasPrefix(s, develPrefix) {
+		s = s[len(develPrefix):]
+		if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
+			s = s[:p]
+		}
+		return s
+	}
+
+	if strings.HasPrefix(s, "go1") {
+		s = s[2:]
+		var prerelease string
+		if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
+			s, prerelease = s[:p], s[p:]
+		}
+		if strings.HasSuffix(s, ".") {
+			s += "0"
+		} else if strings.Count(s, ".") < 2 {
+			s += ".0"
+		}
+		if prerelease != "" {
+			s += "-" + prerelease
+		}
+		return s
+	}
+	return ""
+}
+
+func notSemverRune(r rune) bool {
+	return strings.IndexRune("0123456789.", r) < 0
+}

+ 252 - 0
vendor/cloud.google.com/go/storage/acl.go

@@ -0,0 +1,252 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+
+	"golang.org/x/net/context"
+	"google.golang.org/api/googleapi"
+	raw "google.golang.org/api/storage/v1"
+)
+
+// ACLRole is the level of access to grant.
+type ACLRole string
+
+const (
+	RoleOwner  ACLRole = "OWNER"
+	RoleReader ACLRole = "READER"
+	RoleWriter ACLRole = "WRITER"
+)
+
+// ACLEntity refers to a user or group.
+// They are sometimes referred to as grantees.
+//
+// It could be in the form of:
+// "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>",
+// "domain-<domain>" and "project-team-<projectId>".
+//
+// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers.
+type ACLEntity string
+
+const (
+	AllUsers              ACLEntity = "allUsers"
+	AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers"
+)
+
+// ACLRule represents a grant for a role to an entity (user, group or team) for a Google Cloud Storage object or bucket.
+type ACLRule struct {
+	Entity ACLEntity
+	Role   ACLRole
+}
+
+// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
+type ACLHandle struct {
+	c           *Client
+	bucket      string
+	object      string
+	isDefault   bool
+	userProject string // for requester-pays buckets
+}
+
+// Delete permanently deletes the ACL entry for the given entity.
+func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) error {
+	if a.object != "" {
+		return a.objectDelete(ctx, entity)
+	}
+	if a.isDefault {
+		return a.bucketDefaultDelete(ctx, entity)
+	}
+	return a.bucketDelete(ctx, entity)
+}
+
+// Set sets the permission level for the given entity.
+func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) error {
+	if a.object != "" {
+		return a.objectSet(ctx, entity, role, false)
+	}
+	if a.isDefault {
+		return a.objectSet(ctx, entity, role, true)
+	}
+	return a.bucketSet(ctx, entity, role)
+}
+
+// List retrieves ACL entries.
+func (a *ACLHandle) List(ctx context.Context) ([]ACLRule, error) {
+	if a.object != "" {
+		return a.objectList(ctx)
+	}
+	if a.isDefault {
+		return a.bucketDefaultList(ctx)
+	}
+	return a.bucketList(ctx)
+}
+
+func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
+	var acls *raw.ObjectAccessControls
+	var err error
+	err = runWithRetry(ctx, func() error {
+		req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
+		a.configureCall(req, ctx)
+		acls, err = req.Do()
+		return err
+	})
+	if err != nil {
+		return nil, fmt.Errorf("storage: error listing default object ACL for bucket %q: %v", a.bucket, err)
+	}
+	return toACLRules(acls.Items), nil
+}
+
+func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
+	err := runWithRetry(ctx, func() error {
+		req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
+		a.configureCall(req, ctx)
+		return req.Do()
+	})
+	if err != nil {
+		return fmt.Errorf("storage: error deleting default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
+	}
+	return nil
+}
+
+func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
+	var acls *raw.BucketAccessControls
+	var err error
+	err = runWithRetry(ctx, func() error {
+		req := a.c.raw.BucketAccessControls.List(a.bucket)
+		a.configureCall(req, ctx)
+		acls, err = req.Do()
+		return err
+	})
+	if err != nil {
+		return nil, fmt.Errorf("storage: error listing bucket ACL for bucket %q: %v", a.bucket, err)
+	}
+	r := make([]ACLRule, len(acls.Items))
+	for i, v := range acls.Items {
+		r[i].Entity = ACLEntity(v.Entity)
+		r[i].Role = ACLRole(v.Role)
+	}
+	return r, nil
+}
+
+func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error {
+	acl := &raw.BucketAccessControl{
+		Bucket: a.bucket,
+		Entity: string(entity),
+		Role:   string(role),
+	}
+	err := runWithRetry(ctx, func() error {
+		req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
+		a.configureCall(req, ctx)
+		_, err := req.Do()
+		return err
+	})
+	if err != nil {
+		return fmt.Errorf("storage: error updating bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
+	}
+	return nil
+}
+
+func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
+	err := runWithRetry(ctx, func() error {
+		req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
+		a.configureCall(req, ctx)
+		return req.Do()
+	})
+	if err != nil {
+		return fmt.Errorf("storage: error deleting bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
+	}
+	return nil
+}
+
+func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
+	var acls *raw.ObjectAccessControls
+	var err error
+	err = runWithRetry(ctx, func() error {
+		req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
+		a.configureCall(req, ctx)
+		acls, err = req.Do()
+		return err
+	})
+	if err != nil {
+		return nil, fmt.Errorf("storage: error listing object ACL for bucket %q, file %q: %v", a.bucket, a.object, err)
+	}
+	return toACLRules(acls.Items), nil
+}
+
+func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error {
+	type setRequest interface {
+		Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error)
+		Header() http.Header
+	}
+
+	acl := &raw.ObjectAccessControl{
+		Bucket: a.bucket,
+		Entity: string(entity),
+		Role:   string(role),
+	}
+	var req setRequest
+	if isBucketDefault {
+		req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl)
+	} else {
+		req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
+	}
+	a.configureCall(req, ctx)
+	err := runWithRetry(ctx, func() error {
+		_, err := req.Do()
+		return err
+	})
+	if err != nil {
+		if isBucketDefault {
+			return fmt.Errorf("storage: error updating default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
+		} else {
+			return fmt.Errorf("storage: error updating object ACL entry for bucket %q, object %q, entity %q: %v", a.bucket, a.object, entity, err)
+		}
+	}
+	return nil
+}
+
+func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
+	err := runWithRetry(ctx, func() error {
+		req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
+		a.configureCall(req, ctx)
+		return req.Do()
+	})
+	if err != nil {
+		return fmt.Errorf("storage: error deleting object ACL entry for bucket %q, file %q, entity %q: %v", a.bucket, a.object, entity, err)
+	}
+	return nil
+}
+
+func (a *ACLHandle) configureCall(call interface {
+	Header() http.Header
+}, ctx context.Context) {
+	vc := reflect.ValueOf(call)
+	vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
+	if a.userProject != "" {
+		vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)})
+	}
+	setClientHeader(call.Header())
+}
+
+func toACLRules(items []*raw.ObjectAccessControl) []ACLRule {
+	r := make([]ACLRule, 0, len(items))
+	for _, item := range items {
+		r = append(r, ACLRule{Entity: ACLEntity(item.Entity), Role: ACLRole(item.Role)})
+	}
+	return r
+}

+ 590 - 0
vendor/cloud.google.com/go/storage/bucket.go

@@ -0,0 +1,590 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"time"
+
+	"cloud.google.com/go/internal/optional"
+	"golang.org/x/net/context"
+	"google.golang.org/api/googleapi"
+	"google.golang.org/api/iterator"
+	raw "google.golang.org/api/storage/v1"
+)
+
+// BucketHandle provides operations on a Google Cloud Storage bucket.
+// Use Client.Bucket to get a handle.
+type BucketHandle struct {
+	c                *Client
+	name             string
+	acl              ACLHandle
+	defaultObjectACL ACLHandle
+	conds            *BucketConditions
+	userProject      string // project for requester-pays buckets
+}
+
+// Bucket returns a BucketHandle, which provides operations on the named bucket.
+// This call does not perform any network operations.
+//
+// The supplied name must contain only lowercase letters, numbers, dashes,
+// underscores, and dots. The full specification for valid bucket names can be
+// found at:
+//   https://cloud.google.com/storage/docs/bucket-naming
+func (c *Client) Bucket(name string) *BucketHandle {
+	return &BucketHandle{
+		c:    c,
+		name: name,
+		acl: ACLHandle{
+			c:      c,
+			bucket: name,
+		},
+		defaultObjectACL: ACLHandle{
+			c:         c,
+			bucket:    name,
+			isDefault: true,
+		},
+	}
+}
+
+// Create creates the Bucket in the project.
+// If attrs is nil the API defaults will be used.
+func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) error {
+	var bkt *raw.Bucket
+	if attrs != nil {
+		bkt = attrs.toRawBucket()
+	} else {
+		bkt = &raw.Bucket{}
+	}
+	bkt.Name = b.name
+	req := b.c.raw.Buckets.Insert(projectID, bkt)
+	setClientHeader(req.Header())
+	return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
+}
+
+// Delete deletes the Bucket.
+func (b *BucketHandle) Delete(ctx context.Context) error {
+	req, err := b.newDeleteCall()
+	if err != nil {
+		return err
+	}
+	return runWithRetry(ctx, func() error { return req.Context(ctx).Do() })
+}
+
+func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) {
+	req := b.c.raw.Buckets.Delete(b.name)
+	setClientHeader(req.Header())
+	if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil {
+		return nil, err
+	}
+	if b.userProject != "" {
+		req.UserProject(b.userProject)
+	}
+	return req, nil
+}
+
+// ACL returns an ACLHandle, which provides access to the bucket's access control list.
+// This controls who can list, create or overwrite the objects in a bucket.
+// This call does not perform any network operations.
+func (b *BucketHandle) ACL() *ACLHandle {
+	return &b.acl
+}
+
+// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
+// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
+// This call does not perform any network operations.
+func (b *BucketHandle) DefaultObjectACL() *ACLHandle {
+	return &b.defaultObjectACL
+}
+
+// Object returns an ObjectHandle, which provides operations on the named object.
+// This call does not perform any network operations.
+//
+// name must consist entirely of valid UTF-8-encoded runes. The full specification
+// for valid object names can be found at:
+//   https://cloud.google.com/storage/docs/bucket-naming
+func (b *BucketHandle) Object(name string) *ObjectHandle {
+	return &ObjectHandle{
+		c:      b.c,
+		bucket: b.name,
+		object: name,
+		acl: ACLHandle{
+			c:           b.c,
+			bucket:      b.name,
+			object:      name,
+			userProject: b.userProject,
+		},
+		gen:         -1,
+		userProject: b.userProject,
+	}
+}
+
+// Attrs returns the metadata for the bucket.
+func (b *BucketHandle) Attrs(ctx context.Context) (*BucketAttrs, error) {
+	req, err := b.newGetCall()
+	if err != nil {
+		return nil, err
+	}
+	var resp *raw.Bucket
+	err = runWithRetry(ctx, func() error {
+		resp, err = req.Context(ctx).Do()
+		return err
+	})
+	if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+		return nil, ErrBucketNotExist
+	}
+	if err != nil {
+		return nil, err
+	}
+	return newBucket(resp), nil
+}
+
+func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
+	req := b.c.raw.Buckets.Get(b.name).Projection("full")
+	setClientHeader(req.Header())
+	if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil {
+		return nil, err
+	}
+	if b.userProject != "" {
+		req.UserProject(b.userProject)
+	}
+	return req, nil
+}
+
+func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (*BucketAttrs, error) {
+	req, err := b.newPatchCall(&uattrs)
+	if err != nil {
+		return nil, err
+	}
+	// TODO(jba): retry iff metagen is set?
+	rb, err := req.Context(ctx).Do()
+	if err != nil {
+		return nil, err
+	}
+	return newBucket(rb), nil
+}
+
+func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
+	rb := uattrs.toRawBucket()
+	req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full")
+	setClientHeader(req.Header())
+	if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil {
+		return nil, err
+	}
+	if b.userProject != "" {
+		req.UserProject(b.userProject)
+	}
+	return req, nil
+}
+
+// BucketAttrs represents the metadata for a Google Cloud Storage bucket.
+type BucketAttrs struct {
+	// Name is the name of the bucket.
+	Name string
+
+	// ACL is the list of access control rules on the bucket.
+	ACL []ACLRule
+
+	// DefaultObjectACL is the list of access controls to
+	// apply to new objects when no object ACL is provided.
+	DefaultObjectACL []ACLRule
+
+	// Location is the location of the bucket. It defaults to "US".
+	Location string
+
+	// MetaGeneration is the metadata generation of the bucket.
+	MetaGeneration int64
+
+	// StorageClass is the default storage class of the bucket. This defines
+	// how objects in the bucket are stored and determines the SLA
+	// and the cost of storage. Typical values are "MULTI_REGIONAL",
+	// "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and
+	// "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which
+	// is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on
+	// the bucket's location settings.
+	StorageClass string
+
+	// Created is the creation time of the bucket.
+	Created time.Time
+
+	// VersioningEnabled reports whether this bucket has versioning enabled.
+	// This field is read-only.
+	VersioningEnabled bool
+
+	// Labels are the bucket's labels.
+	Labels map[string]string
+
+	// RequesterPays reports whether the bucket is a Requester Pays bucket.
+	RequesterPays bool
+}
+
+func newBucket(b *raw.Bucket) *BucketAttrs {
+	if b == nil {
+		return nil
+	}
+	bucket := &BucketAttrs{
+		Name:              b.Name,
+		Location:          b.Location,
+		MetaGeneration:    b.Metageneration,
+		StorageClass:      b.StorageClass,
+		Created:           convertTime(b.TimeCreated),
+		VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
+		Labels:            b.Labels,
+		RequesterPays:     b.Billing != nil && b.Billing.RequesterPays,
+	}
+	acl := make([]ACLRule, len(b.Acl))
+	for i, rule := range b.Acl {
+		acl[i] = ACLRule{
+			Entity: ACLEntity(rule.Entity),
+			Role:   ACLRole(rule.Role),
+		}
+	}
+	bucket.ACL = acl
+	objACL := make([]ACLRule, len(b.DefaultObjectAcl))
+	for i, rule := range b.DefaultObjectAcl {
+		objACL[i] = ACLRule{
+			Entity: ACLEntity(rule.Entity),
+			Role:   ACLRole(rule.Role),
+		}
+	}
+	bucket.DefaultObjectACL = objACL
+	return bucket
+}
+
+// toRawBucket copies the editable attribute from b to the raw library's Bucket type.
+func (b *BucketAttrs) toRawBucket() *raw.Bucket {
+	var acl []*raw.BucketAccessControl
+	if len(b.ACL) > 0 {
+		acl = make([]*raw.BucketAccessControl, len(b.ACL))
+		for i, rule := range b.ACL {
+			acl[i] = &raw.BucketAccessControl{
+				Entity: string(rule.Entity),
+				Role:   string(rule.Role),
+			}
+		}
+	}
+	dACL := toRawObjectACL(b.DefaultObjectACL)
+	// Copy label map.
+	var labels map[string]string
+	if len(b.Labels) > 0 {
+		labels = make(map[string]string, len(b.Labels))
+		for k, v := range b.Labels {
+			labels[k] = v
+		}
+	}
+	// Ignore VersioningEnabled if it is false. This is OK because
+	// we only call this method when creating a bucket, and by default
+	// new buckets have versioning off.
+	var v *raw.BucketVersioning
+	if b.VersioningEnabled {
+		v = &raw.BucketVersioning{Enabled: true}
+	}
+	var bb *raw.BucketBilling
+	if b.RequesterPays {
+		bb = &raw.BucketBilling{RequesterPays: true}
+	}
+	return &raw.Bucket{
+		Name:             b.Name,
+		DefaultObjectAcl: dACL,
+		Location:         b.Location,
+		StorageClass:     b.StorageClass,
+		Acl:              acl,
+		Versioning:       v,
+		Labels:           labels,
+		Billing:          bb,
+	}
+}
+
+type BucketAttrsToUpdate struct {
+	// VersioningEnabled, if set, updates whether the bucket uses versioning.
+	VersioningEnabled optional.Bool
+
+	// RequesterPays, if set, updates whether the bucket is a Requester Pays bucket.
+	RequesterPays optional.Bool
+
+	setLabels    map[string]string
+	deleteLabels map[string]bool
+}
+
+// SetLabel causes a label to be added or modified when ua is used
+// in a call to Bucket.Update.
+func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
+	if ua.setLabels == nil {
+		ua.setLabels = map[string]string{}
+	}
+	ua.setLabels[name] = value
+}
+
+// DeleteLabel causes a label to be deleted when ua is used in a
+// call to Bucket.Update.
+func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
+	if ua.deleteLabels == nil {
+		ua.deleteLabels = map[string]bool{}
+	}
+	ua.deleteLabels[name] = true
+}
+
+func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
+	rb := &raw.Bucket{}
+	if ua.VersioningEnabled != nil {
+		rb.Versioning = &raw.BucketVersioning{
+			Enabled:         optional.ToBool(ua.VersioningEnabled),
+			ForceSendFields: []string{"Enabled"},
+		}
+	}
+	if ua.RequesterPays != nil {
+		rb.Billing = &raw.BucketBilling{
+			RequesterPays:   optional.ToBool(ua.RequesterPays),
+			ForceSendFields: []string{"RequesterPays"},
+		}
+	}
+	if ua.setLabels != nil || ua.deleteLabels != nil {
+		rb.Labels = map[string]string{}
+		for k, v := range ua.setLabels {
+			rb.Labels[k] = v
+		}
+		if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
+			rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
+		}
+		for l := range ua.deleteLabels {
+			rb.NullFields = append(rb.NullFields, "Labels."+l)
+		}
+	}
+	return rb
+}
+
+// If returns a new BucketHandle that applies a set of preconditions.
+// Preconditions already set on the BucketHandle are ignored.
+// Operations on the new handle will only occur if the preconditions are
+// satisfied. The only valid preconditions for buckets are MetagenerationMatch
+// and MetagenerationNotMatch.
+func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
+	b2 := *b
+	b2.conds = &conds
+	return &b2
+}
+
+// BucketConditions constrain bucket methods to act on specific metagenerations.
+//
+// The zero value is an empty set of constraints.
+type BucketConditions struct {
+	// MetagenerationMatch specifies that the bucket must have the given
+	// metageneration for the operation to occur.
+	// If MetagenerationMatch is zero, it has no effect.
+	MetagenerationMatch int64
+
+	// MetagenerationNotMatch specifies that the bucket must not have the given
+	// metageneration for the operation to occur.
+	// If MetagenerationNotMatch is zero, it has no effect.
+	MetagenerationNotMatch int64
+}
+
+func (c *BucketConditions) validate(method string) error {
+	if *c == (BucketConditions{}) {
+		return fmt.Errorf("storage: %s: empty conditions", method)
+	}
+	if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
+		return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
+	}
+	return nil
+}
+
+// UserProject returns a new BucketHandle that passes the project ID as the user
+// project for all subsequent calls. A user project is required for all operations
+// on requester-pays buckets.
+func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
+	b2 := *b
+	b2.userProject = projectID
+	b2.acl.userProject = projectID
+	b2.defaultObjectACL.userProject = projectID
+	return &b2
+}
+
+// applyBucketConds modifies the provided call using the conditions in conds.
+// call is something that quacks like a *raw.WhateverCall.
+func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
+	if conds == nil {
+		return nil
+	}
+	if err := conds.validate(method); err != nil {
+		return err
+	}
+	cval := reflect.ValueOf(call)
+	switch {
+	case conds.MetagenerationMatch != 0:
+		if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
+			return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
+		}
+	case conds.MetagenerationNotMatch != 0:
+		if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
+			return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
+		}
+	}
+	return nil
+}
+
+// Objects returns an iterator over the objects in the bucket that match the Query q.
+// If q is nil, no filtering is done.
+func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
+	it := &ObjectIterator{
+		ctx:    ctx,
+		bucket: b,
+	}
+	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+		it.fetch,
+		func() int { return len(it.items) },
+		func() interface{} { b := it.items; it.items = nil; return b })
+	if q != nil {
+		it.query = *q
+	}
+	return it
+}
+
+// An ObjectIterator is an iterator over ObjectAttrs.
+type ObjectIterator struct {
+	ctx      context.Context
+	bucket   *BucketHandle
+	query    Query
+	pageInfo *iterator.PageInfo
+	nextFunc func() error
+	items    []*ObjectAttrs
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is iterator.Done if
+// there are no more results. Once Next returns iterator.Done, all subsequent
+// calls will return iterator.Done.
+//
+// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
+// have a non-empty Prefix field, and a zero value for all other fields. These
+// represent prefixes.
+func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
+	if err := it.nextFunc(); err != nil {
+		return nil, err
+	}
+	item := it.items[0]
+	it.items = it.items[1:]
+	return item, nil
+}
+
+func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
+	req := it.bucket.c.raw.Objects.List(it.bucket.name)
+	setClientHeader(req.Header())
+	req.Projection("full")
+	req.Delimiter(it.query.Delimiter)
+	req.Prefix(it.query.Prefix)
+	req.Versions(it.query.Versions)
+	req.PageToken(pageToken)
+	if it.bucket.userProject != "" {
+		req.UserProject(it.bucket.userProject)
+	}
+	if pageSize > 0 {
+		req.MaxResults(int64(pageSize))
+	}
+	var resp *raw.Objects
+	var err error
+	err = runWithRetry(it.ctx, func() error {
+		resp, err = req.Context(it.ctx).Do()
+		return err
+	})
+	if err != nil {
+		if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+			err = ErrBucketNotExist
+		}
+		return "", err
+	}
+	for _, item := range resp.Items {
+		it.items = append(it.items, newObject(item))
+	}
+	for _, prefix := range resp.Prefixes {
+		it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
+	}
+	return resp.NextPageToken, nil
+}
+
+// TODO(jbd): Add storage.buckets.update.
+
+// Buckets returns an iterator over the buckets in the project. You may
+// optionally set the iterator's Prefix field to restrict the list to buckets
+// whose names begin with the prefix. By default, all buckets in the project
+// are returned.
+func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
+	it := &BucketIterator{
+		ctx:       ctx,
+		client:    c,
+		projectID: projectID,
+	}
+	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+		it.fetch,
+		func() int { return len(it.buckets) },
+		func() interface{} { b := it.buckets; it.buckets = nil; return b })
+	return it
+}
+
+// A BucketIterator is an iterator over BucketAttrs.
+type BucketIterator struct {
+	// Prefix restricts the iterator to buckets whose names begin with it.
+	Prefix string
+
+	ctx       context.Context
+	client    *Client
+	projectID string
+	buckets   []*BucketAttrs
+	pageInfo  *iterator.PageInfo
+	nextFunc  func() error
+}
+
+// Next returns the next result. Its second return value is iterator.Done if
+// there are no more results. Once Next returns iterator.Done, all subsequent
+// calls will return iterator.Done.
+func (it *BucketIterator) Next() (*BucketAttrs, error) {
+	if err := it.nextFunc(); err != nil {
+		return nil, err
+	}
+	b := it.buckets[0]
+	it.buckets = it.buckets[1:]
+	return b, nil
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+func (it *BucketIterator) fetch(pageSize int, pageToken string) (string, error) {
+	req := it.client.raw.Buckets.List(it.projectID)
+	setClientHeader(req.Header())
+	req.Projection("full")
+	req.Prefix(it.Prefix)
+	req.PageToken(pageToken)
+	if pageSize > 0 {
+		req.MaxResults(int64(pageSize))
+	}
+	var resp *raw.Buckets
+	var err error
+	err = runWithRetry(it.ctx, func() error {
+		resp, err = req.Context(it.ctx).Do()
+		return err
+	})
+	if err != nil {
+		return "", err
+	}
+	for _, item := range resp.Items {
+		it.buckets = append(it.buckets, newBucket(item))
+	}
+	return resp.NextPageToken, nil
+}

+ 201 - 0
vendor/cloud.google.com/go/storage/copy.go

@@ -0,0 +1,201 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"errors"
+	"fmt"
+
+	"golang.org/x/net/context"
+	raw "google.golang.org/api/storage/v1"
+)
+
+// CopierFrom creates a Copier that can copy src to dst.
+// You can immediately call Run on the returned Copier, or
+// you can configure it first.
+//
+// For Requester Pays buckets, the user project of dst is billed, unless it is empty,
+// in which case the user project of src is billed.
+func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier {
+	return &Copier{dst: dst, src: src}
+}
+
+// A Copier copies a source object to a destination.
+type Copier struct {
+	// ObjectAttrs are optional attributes to set on the destination object.
+	// Any attributes must be initialized before any calls on the Copier. Nil
+	// or zero-valued attributes are ignored.
+	ObjectAttrs
+
+	// RewriteToken can be set before calling Run to resume a copy
+	// operation. After Run returns a non-nil error, RewriteToken will
+	// have been updated to contain the value needed to resume the copy.
+	RewriteToken string
+
+	// ProgressFunc can be used to monitor the progress of a multi-RPC copy
+	// operation. If ProgressFunc is not nil and copying requires multiple
+	// calls to the underlying service (see
+	// https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then
+	// ProgressFunc will be invoked after each call with the number of bytes of
+	// content copied so far and the total size in bytes of the source object.
+	//
+	// ProgressFunc is intended to make upload progress available to the
+	// application. For example, the implementation of ProgressFunc may update
+	// a progress bar in the application's UI, or log the result of
+	// float64(copiedBytes)/float64(totalBytes).
+	//
+	// ProgressFunc should return quickly without blocking.
+	ProgressFunc func(copiedBytes, totalBytes uint64)
+
+	dst, src *ObjectHandle
+}
+
+// Run performs the copy.
+func (c *Copier) Run(ctx context.Context) (*ObjectAttrs, error) {
+	if err := c.src.validate(); err != nil {
+		return nil, err
+	}
+	if err := c.dst.validate(); err != nil {
+		return nil, err
+	}
+	// Convert destination attributes to raw form, omitting the bucket.
+	// If the bucket is included but name or content-type aren't, the service
+	// returns a 400 with "Required" as the only message. Omitting the bucket
+	// does not cause any problems.
+	rawObject := c.ObjectAttrs.toRawObject("")
+	for {
+		res, err := c.callRewrite(ctx, rawObject)
+		if err != nil {
+			return nil, err
+		}
+		if c.ProgressFunc != nil {
+			c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize))
+		}
+		if res.Done { // Finished successfully.
+			return newObject(res.Resource), nil
+		}
+	}
+}
+
+func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) {
+	call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj)
+
+	call.Context(ctx).Projection("full")
+	if c.RewriteToken != "" {
+		call.RewriteToken(c.RewriteToken)
+	}
+	if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil {
+		return nil, err
+	}
+	if c.dst.userProject != "" {
+		call.UserProject(c.dst.userProject)
+	} else if c.src.userProject != "" {
+		call.UserProject(c.src.userProject)
+	}
+	if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil {
+		return nil, err
+	}
+	if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil {
+		return nil, err
+	}
+	if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil {
+		return nil, err
+	}
+	var res *raw.RewriteResponse
+	var err error
+	setClientHeader(call.Header())
+	err = runWithRetry(ctx, func() error { res, err = call.Do(); return err })
+	if err != nil {
+		return nil, err
+	}
+	c.RewriteToken = res.RewriteToken
+	return res, nil
+}
+
+// ComposerFrom creates a Composer that can compose srcs into dst.
+// You can immediately call Run on the returned Composer, or you can
+// configure it first.
+//
+// The encryption key for the destination object will be used to decrypt all
+// source objects and encrypt the destination object. It is an error
+// to specify an encryption key for any of the source objects.
+func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer {
+	return &Composer{dst: dst, srcs: srcs}
+}
+
+// A Composer composes source objects into a destination object.
+//
+// For Requester Pays buckets, the user project of dst is billed.
+type Composer struct {
+	// ObjectAttrs are optional attributes to set on the destination object.
+	// Any attributes must be initialized before any calls on the Composer. Nil
+	// or zero-valued attributes are ignored.
+	ObjectAttrs
+
+	dst  *ObjectHandle
+	srcs []*ObjectHandle
+}
+
+// Run performs the compose operation.
+func (c *Composer) Run(ctx context.Context) (*ObjectAttrs, error) {
+	if err := c.dst.validate(); err != nil {
+		return nil, err
+	}
+	if len(c.srcs) == 0 {
+		return nil, errors.New("storage: at least one source object must be specified")
+	}
+
+	req := &raw.ComposeRequest{}
+	// Compose requires a non-empty Destination, so we always set it,
+	// even if the caller-provided ObjectAttrs is the zero value.
+	req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket)
+	for _, src := range c.srcs {
+		if err := src.validate(); err != nil {
+			return nil, err
+		}
+		if src.bucket != c.dst.bucket {
+			return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket)
+		}
+		if src.encryptionKey != nil {
+			return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object)
+		}
+		srcObj := &raw.ComposeRequestSourceObjects{
+			Name: src.object,
+		}
+		if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil {
+			return nil, err
+		}
+		req.SourceObjects = append(req.SourceObjects, srcObj)
+	}
+
+	call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx)
+	if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil {
+		return nil, err
+	}
+	if c.dst.userProject != "" {
+		call.UserProject(c.dst.userProject)
+	}
+	if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil {
+		return nil, err
+	}
+	var obj *raw.Object
+	var err error
+	setClientHeader(call.Header())
+	err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
+	if err != nil {
+		return nil, err
+	}
+	return newObject(obj), nil
+}

+ 161 - 0
vendor/cloud.google.com/go/storage/doc.go

@@ -0,0 +1,161 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+Package storage provides an easy way to work with Google Cloud Storage.
+Google Cloud Storage stores data in named objects, which are grouped into buckets.
+
+More information about Google Cloud Storage is available at
+https://cloud.google.com/storage/docs.
+
+All of the methods of this package use exponential backoff to retry calls
+that fail with certain errors, as described in
+https://cloud.google.com/storage/docs/exponential-backoff.
+
+Note: This package is in beta.  Some backwards-incompatible changes may occur.
+
+
+Creating a Client
+
+To start working with this package, create a client:
+
+    ctx := context.Background()
+    client, err := storage.NewClient(ctx)
+    if err != nil {
+        // TODO: Handle error.
+    }
+
+Buckets
+
+A Google Cloud Storage bucket is a collection of objects. To work with a
+bucket, make a bucket handle:
+
+    bkt := client.Bucket(bucketName)
+
+A handle is a reference to a bucket. You can have a handle even if the
+bucket doesn't exist yet. To create a bucket in Google Cloud Storage,
+call Create on the handle:
+
+    if err := bkt.Create(ctx, projectID, nil); err != nil {
+        // TODO: Handle error.
+    }
+
+Note that although buckets are associated with projects, bucket names are
+global across all projects.
+
+Each bucket has associated metadata, represented in this package by
+BucketAttrs. The third argument to BucketHandle.Create allows you to set
+the intial BucketAttrs of a bucket. To retrieve a bucket's attributes, use
+Attrs:
+
+    attrs, err := bkt.Attrs(ctx)
+    if err != nil {
+        // TODO: Handle error.
+    }
+    fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n",
+        attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass)
+
+Objects
+
+An object holds arbitrary data as a sequence of bytes, like a file. You
+refer to objects using a handle, just as with buckets. You can use the
+standard Go io.Reader and io.Writer interfaces to read and write
+object data:
+
+    obj := bkt.Object("data")
+    // Write something to obj.
+    // w implements io.Writer.
+    w := obj.NewWriter(ctx)
+    // Write some text to obj. This will overwrite whatever is there.
+    if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil {
+        // TODO: Handle error.
+    }
+    // Close, just like writing a file.
+    if err := w.Close(); err != nil {
+        // TODO: Handle error.
+    }
+
+    // Read it back.
+    r, err := obj.NewReader(ctx)
+    if err != nil {
+        // TODO: Handle error.
+    }
+    defer r.Close()
+    if _, err := io.Copy(os.Stdout, r); err != nil {
+        // TODO: Handle error.
+    }
+    // Prints "This object contains text."
+
+Objects also have attributes, which you can fetch with Attrs:
+
+    objAttrs, err := obj.Attrs(ctx)
+    if err != nil {
+        // TODO: Handle error.
+    }
+    fmt.Printf("object %s has size %d and can be read using %s\n",
+        objAttrs.Name, objAttrs.Size, objAttrs.MediaLink)
+
+ACLs
+
+Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of
+ACLRules, each of which specifies the role of a user, group or project. ACLs
+are suitable for fine-grained control, but you may prefer using IAM to control
+access at the project level (see
+https://cloud.google.com/storage/docs/access-control/iam).
+
+To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method:
+
+    acls, err := obj.ACL().List(ctx)
+    if err != nil {
+        // TODO: Handle error.
+    }
+    for _, rule := range acls {
+        fmt.Printf("%s has role %s\n", rule.Entity, rule.Role)
+    }
+
+You can also set and delete ACLs.
+
+Conditions
+
+Every object has a generation and a metageneration. The generation changes
+whenever the content changes, and the metageneration changes whenever the
+metadata changes. Conditions let you check these values before an operation;
+the operation only executes if the conditions match. You can use conditions to
+prevent race conditions in read-modify-write operations.
+
+For example, say you've read an object's metadata into objAttrs. Now
+you want to write to that object, but only if its contents haven't changed
+since you read it. Here is how to express that:
+
+    w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx)
+    // Proceed with writing as above.
+
+Signed URLs
+
+You can obtain a URL that lets anyone read or write an object for a limited time.
+You don't need to create a client to do this. See the documentation of
+SignedURL for details.
+
+    url, err := storage.SignedURL(bucketName, "shared-object", opts)
+    if err != nil {
+        // TODO: Handle error.
+    }
+    fmt.Println(url)
+
+Authentication
+
+See examples of authorization and authentication at
+https://godoc.org/cloud.google.com/go#pkg-examples.
+*/
+package storage // import "cloud.google.com/go/storage"

+ 26 - 0
vendor/cloud.google.com/go/storage/go17.go

@@ -0,0 +1,26 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build go1.7
+
+package storage
+
+import (
+	"context"
+	"net/http"
+)
+
+func withContext(r *http.Request, ctx context.Context) *http.Request {
+	return r.WithContext(ctx)
+}

+ 108 - 0
vendor/cloud.google.com/go/storage/iam.go

@@ -0,0 +1,108 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"cloud.google.com/go/iam"
+	"golang.org/x/net/context"
+	raw "google.golang.org/api/storage/v1"
+	iampb "google.golang.org/genproto/googleapis/iam/v1"
+)
+
+// IAM provides access to IAM access control for the bucket.
+func (b *BucketHandle) IAM() *iam.Handle {
+	return iam.InternalNewHandleClient(&iamClient{raw: b.c.raw}, b.name)
+}
+
+// iamClient implements the iam.client interface.
+type iamClient struct {
+	raw *raw.Service
+}
+
+func (c *iamClient) Get(ctx context.Context, resource string) (*iampb.Policy, error) {
+	req := c.raw.Buckets.GetIamPolicy(resource)
+	setClientHeader(req.Header())
+	var rp *raw.Policy
+	var err error
+	err = runWithRetry(ctx, func() error {
+		rp, err = req.Context(ctx).Do()
+		return err
+	})
+	if err != nil {
+		return nil, err
+	}
+	return iamFromStoragePolicy(rp), nil
+}
+
+func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) error {
+	rp := iamToStoragePolicy(p)
+	req := c.raw.Buckets.SetIamPolicy(resource, rp)
+	setClientHeader(req.Header())
+	return runWithRetry(ctx, func() error {
+		_, err := req.Context(ctx).Do()
+		return err
+	})
+}
+
+func (c *iamClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
+	req := c.raw.Buckets.TestIamPermissions(resource, perms)
+	setClientHeader(req.Header())
+	var res *raw.TestIamPermissionsResponse
+	var err error
+	err = runWithRetry(ctx, func() error {
+		res, err = req.Context(ctx).Do()
+		return err
+	})
+	if err != nil {
+		return nil, err
+	}
+	return res.Permissions, nil
+}
+
+func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy {
+	return &raw.Policy{
+		Bindings: iamToStorageBindings(ip.Bindings),
+		Etag:     string(ip.Etag),
+	}
+}
+
+func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings {
+	var rbs []*raw.PolicyBindings
+	for _, ib := range ibs {
+		rbs = append(rbs, &raw.PolicyBindings{
+			Role:    ib.Role,
+			Members: ib.Members,
+		})
+	}
+	return rbs
+}
+
+func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy {
+	return &iampb.Policy{
+		Bindings: iamFromStorageBindings(rp.Bindings),
+		Etag:     []byte(rp.Etag),
+	}
+}
+
+func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding {
+	var ibs []*iampb.Binding
+	for _, rb := range rbs {
+		ibs = append(ibs, &iampb.Binding{
+			Role:    rb.Role,
+			Members: rb.Members,
+		})
+	}
+	return ibs
+}

+ 43 - 0
vendor/cloud.google.com/go/storage/invoke.go

@@ -0,0 +1,43 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"cloud.google.com/go/internal"
+	gax "github.com/googleapis/gax-go"
+	"golang.org/x/net/context"
+	"google.golang.org/api/googleapi"
+)
+
+// runWithRetry calls the function until it returns nil or a non-retryable error, or
+// the context is done.
+func runWithRetry(ctx context.Context, call func() error) error {
+	return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) {
+		err = call()
+		if err == nil {
+			return true, nil
+		}
+		e, ok := err.(*googleapi.Error)
+		if !ok {
+			return true, err
+		}
+		// Retry on 429 and 5xx, according to
+		// https://cloud.google.com/storage/docs/exponential-backoff.
+		if e.Code == 429 || (e.Code >= 500 && e.Code < 600) {
+			return false, nil
+		}
+		return true, err
+	})
+}

+ 26 - 0
vendor/cloud.google.com/go/storage/not_go17.go

@@ -0,0 +1,26 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !go1.7
+
+package storage
+
+import (
+	"net/http"
+)
+
+func withContext(r *http.Request, _ interface{}) *http.Request {
+	// In Go 1.6 and below, ignore the context.
+	return r
+}

+ 74 - 0
vendor/cloud.google.com/go/storage/reader.go

@@ -0,0 +1,74 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"fmt"
+	"hash/crc32"
+	"io"
+)
+
+var crc32cTable = crc32.MakeTable(crc32.Castagnoli)
+
+// Reader reads a Cloud Storage object.
+// It implements io.Reader.
+type Reader struct {
+	body         io.ReadCloser
+	remain, size int64
+	contentType  string
+	checkCRC     bool   // should we check the CRC?
+	wantCRC      uint32 // the CRC32c value the server sent in the header
+	gotCRC       uint32 // running crc
+}
+
+// Close closes the Reader. It must be called when done reading.
+func (r *Reader) Close() error {
+	return r.body.Close()
+}
+
+func (r *Reader) Read(p []byte) (int, error) {
+	n, err := r.body.Read(p)
+	if r.remain != -1 {
+		r.remain -= int64(n)
+	}
+	if r.checkCRC {
+		r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n])
+		// Check CRC here. It would be natural to check it in Close, but
+		// everybody defers Close on the assumption that it doesn't return
+		// anything worth looking at.
+		if r.remain == 0 && r.gotCRC != r.wantCRC {
+			return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d",
+				r.gotCRC, r.wantCRC)
+		}
+	}
+	return n, err
+}
+
+// Size returns the size of the object in bytes.
+// The returned value is always the same and is not affected by
+// calls to Read or Close.
+func (r *Reader) Size() int64 {
+	return r.size
+}
+
+// Remain returns the number of bytes left to read, or -1 if unknown.
+func (r *Reader) Remain() int64 {
+	return r.remain
+}
+
+// ContentType returns the content type of the object.
+func (r *Reader) ContentType() string {
+	return r.contentType
+}

+ 1117 - 0
vendor/cloud.google.com/go/storage/storage.go

@@ -0,0 +1,1117 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+	"unicode/utf8"
+
+	"google.golang.org/api/option"
+	htransport "google.golang.org/api/transport/http"
+
+	"cloud.google.com/go/internal/optional"
+	"cloud.google.com/go/internal/version"
+	"golang.org/x/net/context"
+	"google.golang.org/api/googleapi"
+	raw "google.golang.org/api/storage/v1"
+)
+
+var (
+	ErrBucketNotExist = errors.New("storage: bucket doesn't exist")
+	ErrObjectNotExist = errors.New("storage: object doesn't exist")
+)
+
+const userAgent = "gcloud-golang-storage/20151204"
+
+const (
+	// ScopeFullControl grants permissions to manage your
+	// data and permissions in Google Cloud Storage.
+	ScopeFullControl = raw.DevstorageFullControlScope
+
+	// ScopeReadOnly grants permissions to
+	// view your data in Google Cloud Storage.
+	ScopeReadOnly = raw.DevstorageReadOnlyScope
+
+	// ScopeReadWrite grants permissions to manage your
+	// data in Google Cloud Storage.
+	ScopeReadWrite = raw.DevstorageReadWriteScope
+)
+
+var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo)
+
+func setClientHeader(headers http.Header) {
+	headers.Set("x-goog-api-client", xGoogHeader)
+}
+
+// Client is a client for interacting with Google Cloud Storage.
+//
+// Clients should be reused instead of created as needed.
+// The methods of Client are safe for concurrent use by multiple goroutines.
+type Client struct {
+	hc  *http.Client
+	raw *raw.Service
+}
+
+// NewClient creates a new Google Cloud Storage client.
+// The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use option.WithScopes.
+func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
+	o := []option.ClientOption{
+		option.WithScopes(ScopeFullControl),
+		option.WithUserAgent(userAgent),
+	}
+	opts = append(o, opts...)
+	hc, ep, err := htransport.NewClient(ctx, opts...)
+	if err != nil {
+		return nil, fmt.Errorf("dialing: %v", err)
+	}
+	rawService, err := raw.New(hc)
+	if err != nil {
+		return nil, fmt.Errorf("storage client: %v", err)
+	}
+	if ep != "" {
+		rawService.BasePath = ep
+	}
+	return &Client{
+		hc:  hc,
+		raw: rawService,
+	}, nil
+}
+
+// Close closes the Client.
+//
+// Close need not be called at program exit.
+func (c *Client) Close() error {
+	c.hc = nil
+	return nil
+}
+
+// SignedURLOptions allows you to restrict the access to the signed URL.
+type SignedURLOptions struct {
+	// GoogleAccessID represents the authorizer of the signed URL generation.
+	// It is typically the Google service account client email address from
+	// the Google Developers Console in the form of "xxx@developer.gserviceaccount.com".
+	// Required.
+	GoogleAccessID string
+
+	// PrivateKey is the Google service account private key. It is obtainable
+	// from the Google Developers Console.
+	// At https://console.developers.google.com/project/<your-project-id>/apiui/credential,
+	// create a service account client ID or reuse one of your existing service account
+	// credentials. Click on the "Generate new P12 key" to generate and download
+	// a new private key. Once you download the P12 file, use the following command
+	// to convert it into a PEM file.
+	//
+	//    $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
+	//
+	// Provide the contents of the PEM file as a byte slice.
+	// Exactly one of PrivateKey or SignBytes must be non-nil.
+	PrivateKey []byte
+
+	// SignBytes is a function for implementing custom signing.
+	// If your application is running on Google App Engine, you can use appengine's internal signing function:
+	//     ctx := appengine.NewContext(request)
+	//     acc, _ := appengine.ServiceAccount(ctx)
+	//     url, err := SignedURL("bucket", "object", &SignedURLOptions{
+	//     	GoogleAccessID: acc,
+	//     	SignBytes: func(b []byte) ([]byte, error) {
+	//     		_, signedBytes, err := appengine.SignBytes(ctx, b)
+	//     		return signedBytes, err
+	//     	},
+	//     	// etc.
+	//     })
+	//
+	// Exactly one of PrivateKey or SignBytes must be non-nil.
+	SignBytes func([]byte) ([]byte, error)
+
+	// Method is the HTTP method to be used with the signed URL.
+	// Signed URLs can be used with GET, HEAD, PUT, and DELETE requests.
+	// Required.
+	Method string
+
+	// Expires is the expiration time on the signed URL. It must be
+	// a datetime in the future.
+	// Required.
+	Expires time.Time
+
+	// ContentType is the content type header the client must provide
+	// to use the generated signed URL.
+	// Optional.
+	ContentType string
+
+	// Headers is a list of extention headers the client must provide
+	// in order to use the generated signed URL.
+	// Optional.
+	Headers []string
+
+	// MD5 is the base64 encoded MD5 checksum of the file.
+	// If provided, the client should provide the exact value on the request
+	// header in order to use the signed URL.
+	// Optional.
+	MD5 string
+}
+
+// SignedURL returns a URL for the specified object. Signed URLs allow
+// the users access to a restricted resource for a limited time without having a
+// Google account or signing in. For more information about the signed
+// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs.
+func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
+	if opts == nil {
+		return "", errors.New("storage: missing required SignedURLOptions")
+	}
+	if opts.GoogleAccessID == "" {
+		return "", errors.New("storage: missing required GoogleAccessID")
+	}
+	if (opts.PrivateKey == nil) == (opts.SignBytes == nil) {
+		return "", errors.New("storage: exactly one of PrivateKey or SignedBytes must be set")
+	}
+	if opts.Method == "" {
+		return "", errors.New("storage: missing required method option")
+	}
+	if opts.Expires.IsZero() {
+		return "", errors.New("storage: missing required expires option")
+	}
+	if opts.MD5 != "" {
+		md5, err := base64.StdEncoding.DecodeString(opts.MD5)
+		if err != nil || len(md5) != 16 {
+			return "", errors.New("storage: invalid MD5 checksum")
+		}
+	}
+
+	signBytes := opts.SignBytes
+	if opts.PrivateKey != nil {
+		key, err := parseKey(opts.PrivateKey)
+		if err != nil {
+			return "", err
+		}
+		signBytes = func(b []byte) ([]byte, error) {
+			sum := sha256.Sum256(b)
+			return rsa.SignPKCS1v15(
+				rand.Reader,
+				key,
+				crypto.SHA256,
+				sum[:],
+			)
+		}
+	}
+
+	u := &url.URL{
+		Path: fmt.Sprintf("/%s/%s", bucket, name),
+	}
+
+	buf := &bytes.Buffer{}
+	fmt.Fprintf(buf, "%s\n", opts.Method)
+	fmt.Fprintf(buf, "%s\n", opts.MD5)
+	fmt.Fprintf(buf, "%s\n", opts.ContentType)
+	fmt.Fprintf(buf, "%d\n", opts.Expires.Unix())
+	if len(opts.Headers) > 0 {
+		fmt.Fprintf(buf, "%s\n", strings.Join(opts.Headers, "\n"))
+	}
+	fmt.Fprintf(buf, "%s", u.String())
+
+	b, err := signBytes(buf.Bytes())
+	if err != nil {
+		return "", err
+	}
+	encoded := base64.StdEncoding.EncodeToString(b)
+	u.Scheme = "https"
+	u.Host = "storage.googleapis.com"
+	q := u.Query()
+	q.Set("GoogleAccessId", opts.GoogleAccessID)
+	q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix()))
+	q.Set("Signature", string(encoded))
+	u.RawQuery = q.Encode()
+	return u.String(), nil
+}
+
+// ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
+// Use BucketHandle.Object to get a handle.
+type ObjectHandle struct {
+	c             *Client
+	bucket        string
+	object        string
+	acl           ACLHandle
+	gen           int64 // a negative value indicates latest
+	conds         *Conditions
+	encryptionKey []byte // AES-256 key
+	userProject   string // for requester-pays buckets
+}
+
+// ACL provides access to the object's access control list.
+// This controls who can read and write this object.
+// This call does not perform any network operations.
+func (o *ObjectHandle) ACL() *ACLHandle {
+	return &o.acl
+}
+
+// Generation returns a new ObjectHandle that operates on a specific generation
+// of the object.
+// By default, the handle operates on the latest generation. Not
+// all operations work when given a specific generation; check the API
+// endpoints at https://cloud.google.com/storage/docs/json_api/ for details.
+func (o *ObjectHandle) Generation(gen int64) *ObjectHandle {
+	o2 := *o
+	o2.gen = gen
+	return &o2
+}
+
+// If returns a new ObjectHandle that applies a set of preconditions.
+// Preconditions already set on the ObjectHandle are ignored.
+// Operations on the new handle will only occur if the preconditions are
+// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions
+// for more details.
+func (o *ObjectHandle) If(conds Conditions) *ObjectHandle {
+	o2 := *o
+	o2.conds = &conds
+	return &o2
+}
+
+// Key returns a new ObjectHandle that uses the supplied encryption
+// key to encrypt and decrypt the object's contents.
+//
+// Encryption key must be a 32-byte AES-256 key.
+// See https://cloud.google.com/storage/docs/encryption for details.
+func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle {
+	o2 := *o
+	o2.encryptionKey = encryptionKey
+	return &o2
+}
+
+// Attrs returns meta information about the object.
+// ErrObjectNotExist will be returned if the object is not found.
+func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) {
+	if err := o.validate(); err != nil {
+		return nil, err
+	}
+	call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx)
+	if err := applyConds("Attrs", o.gen, o.conds, call); err != nil {
+		return nil, err
+	}
+	if o.userProject != "" {
+		call.UserProject(o.userProject)
+	}
+	if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil {
+		return nil, err
+	}
+	var obj *raw.Object
+	var err error
+	setClientHeader(call.Header())
+	err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
+	if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+		return nil, ErrObjectNotExist
+	}
+	if err != nil {
+		return nil, err
+	}
+	return newObject(obj), nil
+}
+
+// Update updates an object with the provided attributes.
+// All zero-value attributes are ignored.
+// ErrObjectNotExist will be returned if the object is not found.
+func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (*ObjectAttrs, error) {
+	if err := o.validate(); err != nil {
+		return nil, err
+	}
+	var attrs ObjectAttrs
+	// Lists of fields to send, and set to null, in the JSON.
+	var forceSendFields, nullFields []string
+	if uattrs.ContentType != nil {
+		attrs.ContentType = optional.ToString(uattrs.ContentType)
+		forceSendFields = append(forceSendFields, "ContentType")
+	}
+	if uattrs.ContentLanguage != nil {
+		attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage)
+		// For ContentLanguage It's an error to send the empty string.
+		// Instead we send a null.
+		if attrs.ContentLanguage == "" {
+			nullFields = append(nullFields, "ContentLanguage")
+		} else {
+			forceSendFields = append(forceSendFields, "ContentLanguage")
+		}
+	}
+	if uattrs.ContentEncoding != nil {
+		attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding)
+		forceSendFields = append(forceSendFields, "ContentEncoding")
+	}
+	if uattrs.ContentDisposition != nil {
+		attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition)
+		forceSendFields = append(forceSendFields, "ContentDisposition")
+	}
+	if uattrs.CacheControl != nil {
+		attrs.CacheControl = optional.ToString(uattrs.CacheControl)
+		forceSendFields = append(forceSendFields, "CacheControl")
+	}
+	if uattrs.Metadata != nil {
+		attrs.Metadata = uattrs.Metadata
+		if len(attrs.Metadata) == 0 {
+			// Sending the empty map is a no-op. We send null instead.
+			nullFields = append(nullFields, "Metadata")
+		} else {
+			forceSendFields = append(forceSendFields, "Metadata")
+		}
+	}
+	if uattrs.ACL != nil {
+		attrs.ACL = uattrs.ACL
+		// It's an error to attempt to delete the ACL, so
+		// we don't append to nullFields here.
+		forceSendFields = append(forceSendFields, "Acl")
+	}
+	rawObj := attrs.toRawObject(o.bucket)
+	rawObj.ForceSendFields = forceSendFields
+	rawObj.NullFields = nullFields
+	call := o.c.raw.Objects.Patch(o.bucket, o.object, rawObj).Projection("full").Context(ctx)
+	if err := applyConds("Update", o.gen, o.conds, call); err != nil {
+		return nil, err
+	}
+	if o.userProject != "" {
+		call.UserProject(o.userProject)
+	}
+	if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil {
+		return nil, err
+	}
+	var obj *raw.Object
+	var err error
+	setClientHeader(call.Header())
+	err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
+	if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+		return nil, ErrObjectNotExist
+	}
+	if err != nil {
+		return nil, err
+	}
+	return newObject(obj), nil
+}
+
+// ObjectAttrsToUpdate is used to update the attributes of an object.
+// Only fields set to non-nil values will be updated.
+// Set a field to its zero value to delete it.
+//
+// For example, to change ContentType and delete ContentEncoding and
+// Metadata, use
+//    ObjectAttrsToUpdate{
+//        ContentType: "text/html",
+//        ContentEncoding: "",
+//        Metadata: map[string]string{},
+//    }
+type ObjectAttrsToUpdate struct {
+	ContentType        optional.String
+	ContentLanguage    optional.String
+	ContentEncoding    optional.String
+	ContentDisposition optional.String
+	CacheControl       optional.String
+	Metadata           map[string]string // set to map[string]string{} to delete
+	ACL                []ACLRule
+}
+
+// Delete deletes the single specified object.
+func (o *ObjectHandle) Delete(ctx context.Context) error {
+	if err := o.validate(); err != nil {
+		return err
+	}
+	call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx)
+	if err := applyConds("Delete", o.gen, o.conds, call); err != nil {
+		return err
+	}
+	if o.userProject != "" {
+		call.UserProject(o.userProject)
+	}
+	// Encryption doesn't apply to Delete.
+	setClientHeader(call.Header())
+	err := runWithRetry(ctx, func() error { return call.Do() })
+	switch e := err.(type) {
+	case nil:
+		return nil
+	case *googleapi.Error:
+		if e.Code == http.StatusNotFound {
+			return ErrObjectNotExist
+		}
+	}
+	return err
+}
+
+// NewReader creates a new Reader to read the contents of the
+// object.
+// ErrObjectNotExist will be returned if the object is not found.
+//
+// The caller must call Close on the returned Reader when done reading.
+func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
+	return o.NewRangeReader(ctx, 0, -1)
+}
+
+// NewRangeReader reads part of an object, reading at most length bytes
+// starting at the given offset. If length is negative, the object is read
+// until the end.
+func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (*Reader, error) {
+	if err := o.validate(); err != nil {
+		return nil, err
+	}
+	if offset < 0 {
+		return nil, fmt.Errorf("storage: invalid offset %d < 0", offset)
+	}
+	if o.conds != nil {
+		if err := o.conds.validate("NewRangeReader"); err != nil {
+			return nil, err
+		}
+	}
+	u := &url.URL{
+		Scheme:   "https",
+		Host:     "storage.googleapis.com",
+		Path:     fmt.Sprintf("/%s/%s", o.bucket, o.object),
+		RawQuery: conditionsQuery(o.gen, o.conds),
+	}
+	verb := "GET"
+	if length == 0 {
+		verb = "HEAD"
+	}
+	req, err := http.NewRequest(verb, u.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+	req = withContext(req, ctx)
+	if length < 0 && offset > 0 {
+		req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
+	} else if length > 0 {
+		req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+length-1))
+	}
+	if o.userProject != "" {
+		req.Header.Set("X-Goog-User-Project", o.userProject)
+	}
+	if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil {
+		return nil, err
+	}
+	var res *http.Response
+	err = runWithRetry(ctx, func() error {
+		res, err = o.c.hc.Do(req)
+		if err != nil {
+			return err
+		}
+		if res.StatusCode == http.StatusNotFound {
+			res.Body.Close()
+			return ErrObjectNotExist
+		}
+		if res.StatusCode < 200 || res.StatusCode > 299 {
+			body, _ := ioutil.ReadAll(res.Body)
+			res.Body.Close()
+			return &googleapi.Error{
+				Code:   res.StatusCode,
+				Header: res.Header,
+				Body:   string(body),
+			}
+		}
+		if offset > 0 && length != 0 && res.StatusCode != http.StatusPartialContent {
+			res.Body.Close()
+			return errors.New("storage: partial request not satisfied")
+		}
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	var size int64 // total size of object, even if a range was requested.
+	if res.StatusCode == http.StatusPartialContent {
+		cr := strings.TrimSpace(res.Header.Get("Content-Range"))
+		if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") {
+			return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
+		}
+		size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
+		}
+	} else {
+		size = res.ContentLength
+	}
+
+	remain := res.ContentLength
+	body := res.Body
+	if length == 0 {
+		remain = 0
+		body.Close()
+		body = emptyBody
+	}
+	var (
+		checkCRC bool
+		crc      uint32
+	)
+	// Even if there is a CRC header, we can't compute the hash on partial data.
+	if remain == size {
+		crc, checkCRC = parseCRC32c(res)
+	}
+	return &Reader{
+		body:        body,
+		size:        size,
+		remain:      remain,
+		contentType: res.Header.Get("Content-Type"),
+		wantCRC:     crc,
+		checkCRC:    checkCRC,
+	}, nil
+}
+
+func parseCRC32c(res *http.Response) (uint32, bool) {
+	const prefix = "crc32c="
+	for _, spec := range res.Header["X-Goog-Hash"] {
+		if strings.HasPrefix(spec, prefix) {
+			c, err := decodeUint32(spec[len(prefix):])
+			if err == nil {
+				return c, true
+			}
+		}
+	}
+	return 0, false
+}
+
+var emptyBody = ioutil.NopCloser(strings.NewReader(""))
+
+// NewWriter returns a storage Writer that writes to the GCS object
+// associated with this ObjectHandle.
+//
+// A new object will be created unless an object with this name already exists.
+// Otherwise any previous object with the same name will be replaced.
+// The object will not be available (and any previous object will remain)
+// until Close has been called.
+//
+// Attributes can be set on the object by modifying the returned Writer's
+// ObjectAttrs field before the first call to Write. If no ContentType
+// attribute is specified, the content type will be automatically sniffed
+// using net/http.DetectContentType.
+//
+// It is the caller's responsibility to call Close when writing is done.
+func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer {
+	return &Writer{
+		ctx:         ctx,
+		o:           o,
+		donec:       make(chan struct{}),
+		ObjectAttrs: ObjectAttrs{Name: o.object},
+		ChunkSize:   googleapi.DefaultUploadChunkSize,
+	}
+}
+
+func (o *ObjectHandle) validate() error {
+	if o.bucket == "" {
+		return errors.New("storage: bucket name is empty")
+	}
+	if o.object == "" {
+		return errors.New("storage: object name is empty")
+	}
+	if !utf8.ValidString(o.object) {
+		return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
+	}
+	return nil
+}
+
+// parseKey converts the binary contents of a private key file
+// to an *rsa.PrivateKey. It detects whether the private key is in a
+// PEM container or not. If so, it extracts the the private key
+// from PEM container before conversion. It only supports PEM
+// containers with no passphrase.
+func parseKey(key []byte) (*rsa.PrivateKey, error) {
+	if block, _ := pem.Decode(key); block != nil {
+		key = block.Bytes
+	}
+	parsedKey, err := x509.ParsePKCS8PrivateKey(key)
+	if err != nil {
+		parsedKey, err = x509.ParsePKCS1PrivateKey(key)
+		if err != nil {
+			return nil, err
+		}
+	}
+	parsed, ok := parsedKey.(*rsa.PrivateKey)
+	if !ok {
+		return nil, errors.New("oauth2: private key is invalid")
+	}
+	return parsed, nil
+}
+
+func toRawObjectACL(oldACL []ACLRule) []*raw.ObjectAccessControl {
+	var acl []*raw.ObjectAccessControl
+	if len(oldACL) > 0 {
+		acl = make([]*raw.ObjectAccessControl, len(oldACL))
+		for i, rule := range oldACL {
+			acl[i] = &raw.ObjectAccessControl{
+				Entity: string(rule.Entity),
+				Role:   string(rule.Role),
+			}
+		}
+	}
+	return acl
+}
+
+// toRawObject copies the editable attributes from o to the raw library's Object type.
+func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object {
+	acl := toRawObjectACL(o.ACL)
+	return &raw.Object{
+		Bucket:             bucket,
+		Name:               o.Name,
+		ContentType:        o.ContentType,
+		ContentEncoding:    o.ContentEncoding,
+		ContentLanguage:    o.ContentLanguage,
+		CacheControl:       o.CacheControl,
+		ContentDisposition: o.ContentDisposition,
+		StorageClass:       o.StorageClass,
+		Acl:                acl,
+		Metadata:           o.Metadata,
+	}
+}
+
+// ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object.
+type ObjectAttrs struct {
+	// Bucket is the name of the bucket containing this GCS object.
+	// This field is read-only.
+	Bucket string
+
+	// Name is the name of the object within the bucket.
+	// This field is read-only.
+	Name string
+
+	// ContentType is the MIME type of the object's content.
+	ContentType string
+
+	// ContentLanguage is the content language of the object's content.
+	ContentLanguage string
+
+	// CacheControl is the Cache-Control header to be sent in the response
+	// headers when serving the object data.
+	CacheControl string
+
+	// ACL is the list of access control rules for the object.
+	ACL []ACLRule
+
+	// Owner is the owner of the object. This field is read-only.
+	//
+	// If non-zero, it is in the form of "user-<userId>".
+	Owner string
+
+	// Size is the length of the object's content. This field is read-only.
+	Size int64
+
+	// ContentEncoding is the encoding of the object's content.
+	ContentEncoding string
+
+	// ContentDisposition is the optional Content-Disposition header of the object
+	// sent in the response headers.
+	ContentDisposition string
+
+	// MD5 is the MD5 hash of the object's content. This field is read-only.
+	MD5 []byte
+
+	// CRC32C is the CRC32 checksum of the object's content using
+	// the Castagnoli93 polynomial. This field is read-only.
+	CRC32C uint32
+
+	// MediaLink is an URL to the object's content. This field is read-only.
+	MediaLink string
+
+	// Metadata represents user-provided metadata, in key/value pairs.
+	// It can be nil if no metadata is provided.
+	Metadata map[string]string
+
+	// Generation is the generation number of the object's content.
+	// This field is read-only.
+	Generation int64
+
+	// Metageneration is the version of the metadata for this
+	// object at this generation. This field is used for preconditions
+	// and for detecting changes in metadata. A metageneration number
+	// is only meaningful in the context of a particular generation
+	// of a particular object. This field is read-only.
+	Metageneration int64
+
+	// StorageClass is the storage class of the object.
+	// This value defines how objects in the bucket are stored and
+	// determines the SLA and the cost of storage. Typical values are
+	// "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD"
+	// and "DURABLE_REDUCED_AVAILABILITY".
+	// It defaults to "STANDARD", which is equivalent to "MULTI_REGIONAL"
+	// or "REGIONAL" depending on the bucket's location settings.
+	StorageClass string
+
+	// Created is the time the object was created. This field is read-only.
+	Created time.Time
+
+	// Deleted is the time the object was deleted.
+	// If not deleted, it is the zero value. This field is read-only.
+	Deleted time.Time
+
+	// Updated is the creation or modification time of the object.
+	// For buckets with versioning enabled, changing an object's
+	// metadata does not change this property. This field is read-only.
+	Updated time.Time
+
+	// CustomerKeySHA256 is the base64-encoded SHA-256 hash of the
+	// customer-supplied encryption key for the object. It is empty if there is
+	// no customer-supplied encryption key.
+	// See // https://cloud.google.com/storage/docs/encryption for more about
+	// encryption in Google Cloud Storage.
+	CustomerKeySHA256 string
+
+	// Prefix is set only for ObjectAttrs which represent synthetic "directory
+	// entries" when iterating over buckets using Query.Delimiter. See
+	// ObjectIterator.Next. When set, no other fields in ObjectAttrs will be
+	// populated.
+	Prefix string
+}
+
+// convertTime converts a time in RFC3339 format to time.Time.
+// If any error occurs in parsing, the zero-value time.Time is silently returned.
+func convertTime(t string) time.Time {
+	var r time.Time
+	if t != "" {
+		r, _ = time.Parse(time.RFC3339, t)
+	}
+	return r
+}
+
+func newObject(o *raw.Object) *ObjectAttrs {
+	if o == nil {
+		return nil
+	}
+	acl := make([]ACLRule, len(o.Acl))
+	for i, rule := range o.Acl {
+		acl[i] = ACLRule{
+			Entity: ACLEntity(rule.Entity),
+			Role:   ACLRole(rule.Role),
+		}
+	}
+	owner := ""
+	if o.Owner != nil {
+		owner = o.Owner.Entity
+	}
+	md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash)
+	crc32c, _ := decodeUint32(o.Crc32c)
+	var sha256 string
+	if o.CustomerEncryption != nil {
+		sha256 = o.CustomerEncryption.KeySha256
+	}
+	return &ObjectAttrs{
+		Bucket:            o.Bucket,
+		Name:              o.Name,
+		ContentType:       o.ContentType,
+		ContentLanguage:   o.ContentLanguage,
+		CacheControl:      o.CacheControl,
+		ACL:               acl,
+		Owner:             owner,
+		ContentEncoding:   o.ContentEncoding,
+		Size:              int64(o.Size),
+		MD5:               md5,
+		CRC32C:            crc32c,
+		MediaLink:         o.MediaLink,
+		Metadata:          o.Metadata,
+		Generation:        o.Generation,
+		Metageneration:    o.Metageneration,
+		StorageClass:      o.StorageClass,
+		CustomerKeySHA256: sha256,
+		Created:           convertTime(o.TimeCreated),
+		Deleted:           convertTime(o.TimeDeleted),
+		Updated:           convertTime(o.Updated),
+	}
+}
+
+// Decode a uint32 encoded in Base64 in big-endian byte order.
+func decodeUint32(b64 string) (uint32, error) {
+	d, err := base64.StdEncoding.DecodeString(b64)
+	if err != nil {
+		return 0, err
+	}
+	if len(d) != 4 {
+		return 0, fmt.Errorf("storage: %q does not encode a 32-bit value", d)
+	}
+	return uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3]), nil
+}
+
+// Encode a uint32 as Base64 in big-endian byte order.
+func encodeUint32(u uint32) string {
+	b := []byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)}
+	return base64.StdEncoding.EncodeToString(b)
+}
+
+// Query represents a query to filter objects from a bucket.
+type Query struct {
+	// Delimiter returns results in a directory-like fashion.
+	// Results will contain only objects whose names, aside from the
+	// prefix, do not contain delimiter. Objects whose names,
+	// aside from the prefix, contain delimiter will have their name,
+	// truncated after the delimiter, returned in prefixes.
+	// Duplicate prefixes are omitted.
+	// Optional.
+	Delimiter string
+
+	// Prefix is the prefix filter to query objects
+	// whose names begin with this prefix.
+	// Optional.
+	Prefix string
+
+	// Versions indicates whether multiple versions of the same
+	// object will be included in the results.
+	Versions bool
+}
+
+// contentTyper implements ContentTyper to enable an
+// io.ReadCloser to specify its MIME type.
+type contentTyper struct {
+	io.Reader
+	t string
+}
+
+func (c *contentTyper) ContentType() string {
+	return c.t
+}
+
+// Conditions constrain methods to act on specific generations of
+// objects.
+//
+// The zero value is an empty set of constraints. Not all conditions or
+// combinations of conditions are applicable to all methods.
+// See https://cloud.google.com/storage/docs/generations-preconditions
+// for details on how these operate.
+type Conditions struct {
+	// Generation constraints.
+	// At most one of the following can be set to a non-zero value.
+
+	// GenerationMatch specifies that the object must have the given generation
+	// for the operation to occur.
+	// If GenerationMatch is zero, it has no effect.
+	// Use DoesNotExist to specify that the object does not exist in the bucket.
+	GenerationMatch int64
+
+	// GenerationNotMatch specifies that the object must not have the given
+	// generation for the operation to occur.
+	// If GenerationNotMatch is zero, it has no effect.
+	GenerationNotMatch int64
+
+	// DoesNotExist specifies that the object must not exist in the bucket for
+	// the operation to occur.
+	// If DoesNotExist is false, it has no effect.
+	DoesNotExist bool
+
+	// Metadata generation constraints.
+	// At most one of the following can be set to a non-zero value.
+
+	// MetagenerationMatch specifies that the object must have the given
+	// metageneration for the operation to occur.
+	// If MetagenerationMatch is zero, it has no effect.
+	MetagenerationMatch int64
+
+	// MetagenerationNotMatch specifies that the object must not have the given
+	// metageneration for the operation to occur.
+	// If MetagenerationNotMatch is zero, it has no effect.
+	MetagenerationNotMatch int64
+}
+
+func (c *Conditions) validate(method string) error {
+	if *c == (Conditions{}) {
+		return fmt.Errorf("storage: %s: empty conditions", method)
+	}
+	if !c.isGenerationValid() {
+		return fmt.Errorf("storage: %s: multiple conditions specified for generation", method)
+	}
+	if !c.isMetagenerationValid() {
+		return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
+	}
+	return nil
+}
+
+func (c *Conditions) isGenerationValid() bool {
+	n := 0
+	if c.GenerationMatch != 0 {
+		n++
+	}
+	if c.GenerationNotMatch != 0 {
+		n++
+	}
+	if c.DoesNotExist {
+		n++
+	}
+	return n <= 1
+}
+
+func (c *Conditions) isMetagenerationValid() bool {
+	return c.MetagenerationMatch == 0 || c.MetagenerationNotMatch == 0
+}
+
+// applyConds modifies the provided call using the conditions in conds.
+// call is something that quacks like a *raw.WhateverCall.
+func applyConds(method string, gen int64, conds *Conditions, call interface{}) error {
+	cval := reflect.ValueOf(call)
+	if gen >= 0 {
+		if !setConditionField(cval, "Generation", gen) {
+			return fmt.Errorf("storage: %s: generation not supported", method)
+		}
+	}
+	if conds == nil {
+		return nil
+	}
+	if err := conds.validate(method); err != nil {
+		return err
+	}
+	switch {
+	case conds.GenerationMatch != 0:
+		if !setConditionField(cval, "IfGenerationMatch", conds.GenerationMatch) {
+			return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method)
+		}
+	case conds.GenerationNotMatch != 0:
+		if !setConditionField(cval, "IfGenerationNotMatch", conds.GenerationNotMatch) {
+			return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method)
+		}
+	case conds.DoesNotExist:
+		if !setConditionField(cval, "IfGenerationMatch", int64(0)) {
+			return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
+		}
+	}
+	switch {
+	case conds.MetagenerationMatch != 0:
+		if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
+			return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
+		}
+	case conds.MetagenerationNotMatch != 0:
+		if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
+			return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
+		}
+	}
+	return nil
+}
+
+func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error {
+	if gen >= 0 {
+		call.SourceGeneration(gen)
+	}
+	if conds == nil {
+		return nil
+	}
+	if err := conds.validate("CopyTo source"); err != nil {
+		return err
+	}
+	switch {
+	case conds.GenerationMatch != 0:
+		call.IfSourceGenerationMatch(conds.GenerationMatch)
+	case conds.GenerationNotMatch != 0:
+		call.IfSourceGenerationNotMatch(conds.GenerationNotMatch)
+	case conds.DoesNotExist:
+		call.IfSourceGenerationMatch(0)
+	}
+	switch {
+	case conds.MetagenerationMatch != 0:
+		call.IfSourceMetagenerationMatch(conds.MetagenerationMatch)
+	case conds.MetagenerationNotMatch != 0:
+		call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch)
+	}
+	return nil
+}
+
+// setConditionField sets a field on a *raw.WhateverCall.
+// We can't use anonymous interfaces because the return type is
+// different, since the field setters are builders.
+func setConditionField(call reflect.Value, name string, value interface{}) bool {
+	m := call.MethodByName(name)
+	if !m.IsValid() {
+		return false
+	}
+	m.Call([]reflect.Value{reflect.ValueOf(value)})
+	return true
+}
+
+// conditionsQuery returns the generation and conditions as a URL query
+// string suitable for URL.RawQuery.  It assumes that the conditions
+// have been validated.
+func conditionsQuery(gen int64, conds *Conditions) string {
+	// URL escapes are elided because integer strings are URL-safe.
+	var buf []byte
+
+	appendParam := func(s string, n int64) {
+		if len(buf) > 0 {
+			buf = append(buf, '&')
+		}
+		buf = append(buf, s...)
+		buf = strconv.AppendInt(buf, n, 10)
+	}
+
+	if gen >= 0 {
+		appendParam("generation=", gen)
+	}
+	if conds == nil {
+		return string(buf)
+	}
+	switch {
+	case conds.GenerationMatch != 0:
+		appendParam("ifGenerationMatch=", conds.GenerationMatch)
+	case conds.GenerationNotMatch != 0:
+		appendParam("ifGenerationNotMatch=", conds.GenerationNotMatch)
+	case conds.DoesNotExist:
+		appendParam("ifGenerationMatch=", 0)
+	}
+	switch {
+	case conds.MetagenerationMatch != 0:
+		appendParam("ifMetagenerationMatch=", conds.MetagenerationMatch)
+	case conds.MetagenerationNotMatch != 0:
+		appendParam("ifMetagenerationNotMatch=", conds.MetagenerationNotMatch)
+	}
+	return string(buf)
+}
+
+// composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods
+// that modifyCall searches for by name.
+type composeSourceObj struct {
+	src *raw.ComposeRequestSourceObjects
+}
+
+func (c composeSourceObj) Generation(gen int64) {
+	c.src.Generation = gen
+}
+
+func (c composeSourceObj) IfGenerationMatch(gen int64) {
+	// It's safe to overwrite ObjectPreconditions, since its only field is
+	// IfGenerationMatch.
+	c.src.ObjectPreconditions = &raw.ComposeRequestSourceObjectsObjectPreconditions{
+		IfGenerationMatch: gen,
+	}
+}
+
+func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) error {
+	if key == nil {
+		return nil
+	}
+	// TODO(jbd): Ask the API team to return a more user-friendly error
+	// and avoid doing this check at the client level.
+	if len(key) != 32 {
+		return errors.New("storage: not a 32-byte AES-256 key")
+	}
+	var cs string
+	if copySource {
+		cs = "copy-source-"
+	}
+	headers.Set("x-goog-"+cs+"encryption-algorithm", "AES256")
+	headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key))
+	keyHash := sha256.Sum256(key)
+	headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:]))
+	return nil
+}
+
+// TODO(jbd): Add storage.objects.watch.

+ 192 - 0
vendor/cloud.google.com/go/storage/writer.go

@@ -0,0 +1,192 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"io"
+	"unicode/utf8"
+
+	"golang.org/x/net/context"
+	"google.golang.org/api/googleapi"
+	raw "google.golang.org/api/storage/v1"
+)
+
+// A Writer writes a Cloud Storage object.
+type Writer struct {
+	// ObjectAttrs are optional attributes to set on the object. Any attributes
+	// must be initialized before the first Write call. Nil or zero-valued
+	// attributes are ignored.
+	ObjectAttrs
+
+	// SendCRC specifies whether to transmit a CRC32C field. It should be set
+	// to true in addition to setting the Writer's CRC32C field, because zero
+	// is a valid CRC and normally a zero would not be transmitted.
+	SendCRC32C bool
+
+	// ChunkSize controls the maximum number of bytes of the object that the
+	// Writer will attempt to send to the server in a single request. Objects
+	// smaller than the size will be sent in a single request, while larger
+	// objects will be split over multiple requests. The size will be rounded up
+	// to the nearest multiple of 256K. If zero, chunking will be disabled and
+	// the object will be uploaded in a single request.
+	//
+	// ChunkSize will default to a reasonable value. Any custom configuration
+	// must be done before the first Write call.
+	ChunkSize int
+
+	// ProgressFunc can be used to monitor the progress of a large write.
+	// operation. If ProgressFunc is not nil and writing requires multiple
+	// calls to the underlying service (see
+	// https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload),
+	// then ProgressFunc will be invoked after each call with the number of bytes of
+	// content copied so far.
+	//
+	// ProgressFunc should return quickly without blocking.
+	ProgressFunc func(int64)
+
+	ctx context.Context
+	o   *ObjectHandle
+
+	opened bool
+	pw     *io.PipeWriter
+
+	donec chan struct{} // closed after err and obj are set.
+	err   error
+	obj   *ObjectAttrs
+}
+
+func (w *Writer) open() error {
+	attrs := w.ObjectAttrs
+	// Check the developer didn't change the object Name (this is unfortunate, but
+	// we don't want to store an object under the wrong name).
+	if attrs.Name != w.o.object {
+		return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object)
+	}
+	if !utf8.ValidString(attrs.Name) {
+		return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name)
+	}
+	pr, pw := io.Pipe()
+	w.pw = pw
+	w.opened = true
+
+	if w.ChunkSize < 0 {
+		return errors.New("storage: Writer.ChunkSize must non-negative")
+	}
+	mediaOpts := []googleapi.MediaOption{
+		googleapi.ChunkSize(w.ChunkSize),
+	}
+	if c := attrs.ContentType; c != "" {
+		mediaOpts = append(mediaOpts, googleapi.ContentType(c))
+	}
+
+	go func() {
+		defer close(w.donec)
+
+		rawObj := attrs.toRawObject(w.o.bucket)
+		if w.SendCRC32C {
+			rawObj.Crc32c = encodeUint32(attrs.CRC32C)
+		}
+		if w.MD5 != nil {
+			rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5)
+		}
+		call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj).
+			Media(pr, mediaOpts...).
+			Projection("full").
+			Context(w.ctx)
+		if w.ProgressFunc != nil {
+			call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) })
+		}
+		if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil {
+			w.err = err
+			pr.CloseWithError(w.err)
+			return
+		}
+		var resp *raw.Object
+		err := applyConds("NewWriter", w.o.gen, w.o.conds, call)
+		if err == nil {
+			if w.o.userProject != "" {
+				call.UserProject(w.o.userProject)
+			}
+			setClientHeader(call.Header())
+			// We will only retry here if the initial POST, which obtains a URI for
+			// the resumable upload, fails with a retryable error. The upload itself
+			// has its own retry logic.
+			err = runWithRetry(w.ctx, func() error {
+				var err2 error
+				resp, err2 = call.Do()
+				return err2
+			})
+		}
+		if err != nil {
+			w.err = err
+			pr.CloseWithError(w.err)
+			return
+		}
+		w.obj = newObject(resp)
+	}()
+	return nil
+}
+
+// Write appends to w. It implements the io.Writer interface.
+//
+// Since writes happen asynchronously, Write may return a nil
+// error even though the write failed (or will fail). Always
+// use the error returned from Writer.Close to determine if
+// the upload was successful.
+func (w *Writer) Write(p []byte) (n int, err error) {
+	if w.err != nil {
+		return 0, w.err
+	}
+	if !w.opened {
+		if err := w.open(); err != nil {
+			return 0, err
+		}
+	}
+	return w.pw.Write(p)
+}
+
+// Close completes the write operation and flushes any buffered data.
+// If Close doesn't return an error, metadata about the written object
+// can be retrieved by calling Attrs.
+func (w *Writer) Close() error {
+	if !w.opened {
+		if err := w.open(); err != nil {
+			return err
+		}
+	}
+	if err := w.pw.Close(); err != nil {
+		return err
+	}
+	<-w.donec
+	return w.err
+}
+
+// CloseWithError aborts the write operation with the provided error.
+// CloseWithError always returns nil.
+func (w *Writer) CloseWithError(err error) error {
+	if !w.opened {
+		return nil
+	}
+	return w.pw.CloseWithError(err)
+}
+
+// Attrs returns metadata about a successfully-written object.
+// It's only valid to call it after Close returns nil.
+func (w *Writer) Attrs() *ObjectAttrs {
+	return w.obj
+}

+ 27 - 0
vendor/github.com/googleapis/gax-go/CONTRIBUTING.md

@@ -0,0 +1,27 @@
+Want to contribute? Great! First, read this page (including the small print at the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement]
+(https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the
+[Software Grant and Corporate Contributor License Agreement]
+(https://cla.developers.google.com/about/google-corporate).

+ 27 - 0
vendor/github.com/googleapis/gax-go/LICENSE

@@ -0,0 +1,27 @@
+Copyright 2016, Google Inc.
+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.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+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
+OWNER 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.

+ 24 - 0
vendor/github.com/googleapis/gax-go/README.md

@@ -0,0 +1,24 @@
+Google API Extensions for Go
+============================
+
+[![Build Status](https://travis-ci.org/googleapis/gax-go.svg?branch=master)](https://travis-ci.org/googleapis/gax-go)
+[![Code Coverage](https://img.shields.io/codecov/c/github/googleapis/gax-go.svg)](https://codecov.io/github/googleapis/gax-go)
+
+Google API Extensions for Go (gax-go) is a set of modules which aids the
+development of APIs for clients and servers based on `gRPC` and Google API
+conventions.
+
+Application code will rarely need to use this library directly,
+but the code generated automatically from API definition files can use it
+to simplify code generation and to provide more convenient and idiomatic API surface.
+
+**This project is currently experimental and not supported.**
+
+Go Versions
+===========
+This library requires Go 1.6 or above.
+
+License
+=======
+BSD - please see [LICENSE](https://github.com/googleapis/gax-go/blob/master/LICENSE)
+for more information.

+ 157 - 0
vendor/github.com/googleapis/gax-go/call_option.go

@@ -0,0 +1,157 @@
+// Copyright 2016, Google Inc.
+// 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.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+package gax
+
+import (
+	"math/rand"
+	"time"
+
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+// CallOption is an option used by Invoke to control behaviors of RPC calls.
+// CallOption works by modifying relevant fields of CallSettings.
+type CallOption interface {
+	// Resolve applies the option by modifying cs.
+	Resolve(cs *CallSettings)
+}
+
+// Retryer is used by Invoke to determine retry behavior.
+type Retryer interface {
+	// Retry reports whether a request should be retriedand how long to pause before retrying
+	// if the previous attempt returned with err. Invoke never calls Retry with nil error.
+	Retry(err error) (pause time.Duration, shouldRetry bool)
+}
+
+type retryerOption func() Retryer
+
+func (o retryerOption) Resolve(s *CallSettings) {
+	s.Retry = o
+}
+
+// WithRetry sets CallSettings.Retry to fn.
+func WithRetry(fn func() Retryer) CallOption {
+	return retryerOption(fn)
+}
+
+// OnCodes returns a Retryer that retries if and only if
+// the previous attempt returns a GRPC error whose error code is stored in cc.
+// Pause times between retries are specified by bo.
+//
+// bo is only used for its parameters; each Retryer has its own copy.
+func OnCodes(cc []codes.Code, bo Backoff) Retryer {
+	return &boRetryer{
+		backoff: bo,
+		codes:   append([]codes.Code(nil), cc...),
+	}
+}
+
+type boRetryer struct {
+	backoff Backoff
+	codes   []codes.Code
+}
+
+func (r *boRetryer) Retry(err error) (time.Duration, bool) {
+	st, ok := status.FromError(err)
+	if !ok {
+		return 0, false
+	}
+	c := st.Code()
+	for _, rc := range r.codes {
+		if c == rc {
+			return r.backoff.Pause(), true
+		}
+	}
+	return 0, false
+}
+
+// Backoff implements exponential backoff.
+// The wait time between retries is a random value between 0 and the "retry envelope".
+// The envelope starts at Initial and increases by the factor of Multiplier every retry,
+// but is capped at Max.
+type Backoff struct {
+	// Initial is the initial value of the retry envelope, defaults to 1 second.
+	Initial time.Duration
+
+	// Max is the maximum value of the retry envelope, defaults to 30 seconds.
+	Max time.Duration
+
+	// Multiplier is the factor by which the retry envelope increases.
+	// It should be greater than 1 and defaults to 2.
+	Multiplier float64
+
+	// cur is the current retry envelope
+	cur time.Duration
+}
+
+func (bo *Backoff) Pause() time.Duration {
+	if bo.Initial == 0 {
+		bo.Initial = time.Second
+	}
+	if bo.cur == 0 {
+		bo.cur = bo.Initial
+	}
+	if bo.Max == 0 {
+		bo.Max = 30 * time.Second
+	}
+	if bo.Multiplier < 1 {
+		bo.Multiplier = 2
+	}
+	// Select a duration between zero and the current max. It might seem counterintuitive to
+	// have so much jitter, but https://www.awsarchitectureblog.com/2015/03/backoff.html
+	// argues that that is the best strategy.
+	d := time.Duration(rand.Int63n(int64(bo.cur)))
+	bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier)
+	if bo.cur > bo.Max {
+		bo.cur = bo.Max
+	}
+	return d
+}
+
+type grpcOpt []grpc.CallOption
+
+func (o grpcOpt) Resolve(s *CallSettings) {
+	s.GRPC = o
+}
+
+func WithGRPCOptions(opt ...grpc.CallOption) CallOption {
+	return grpcOpt(append([]grpc.CallOption(nil), opt...))
+}
+
+type CallSettings struct {
+	// Retry returns a Retryer to be used to control retry logic of a method call.
+	// If Retry is nil or the returned Retryer is nil, the call will not be retried.
+	Retry func() Retryer
+
+	// CallOptions to be forwarded to GRPC.
+	GRPC []grpc.CallOption
+}

+ 40 - 0
vendor/github.com/googleapis/gax-go/gax.go

@@ -0,0 +1,40 @@
+// Copyright 2016, Google Inc.
+// 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.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+// Package gax contains a set of modules which aid the development of APIs
+// for clients and servers based on gRPC and Google API conventions.
+//
+// Application code will rarely need to use this library directly.
+// However, code generated automatically from API definition files can use it
+// to simplify code generation and to provide more convenient and idiomatic API surfaces.
+//
+// This project is currently experimental and not supported.
+package gax
+
+const Version = "0.1.0"

+ 24 - 0
vendor/github.com/googleapis/gax-go/header.go

@@ -0,0 +1,24 @@
+package gax
+
+import "bytes"
+
+// XGoogHeader is for use by the Google Cloud Libraries only.
+//
+// XGoogHeader formats key-value pairs.
+// The resulting string is suitable for x-goog-api-client header.
+func XGoogHeader(keyval ...string) string {
+	if len(keyval) == 0 {
+		return ""
+	}
+	if len(keyval)%2 != 0 {
+		panic("gax.Header: odd argument count")
+	}
+	var buf bytes.Buffer
+	for i := 0; i < len(keyval); i += 2 {
+		buf.WriteByte(' ')
+		buf.WriteString(keyval[i])
+		buf.WriteByte('/')
+		buf.WriteString(keyval[i+1])
+	}
+	return buf.String()[1:]
+}

+ 90 - 0
vendor/github.com/googleapis/gax-go/invoke.go

@@ -0,0 +1,90 @@
+// Copyright 2016, Google Inc.
+// 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.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+package gax
+
+import (
+	"time"
+
+	"golang.org/x/net/context"
+)
+
+// A user defined call stub.
+type APICall func(context.Context, CallSettings) error
+
+// Invoke calls the given APICall,
+// performing retries as specified by opts, if any.
+func Invoke(ctx context.Context, call APICall, opts ...CallOption) error {
+	var settings CallSettings
+	for _, opt := range opts {
+		opt.Resolve(&settings)
+	}
+	return invoke(ctx, call, settings, Sleep)
+}
+
+// Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing.
+// If interrupted, Sleep returns ctx.Err().
+func Sleep(ctx context.Context, d time.Duration) error {
+	t := time.NewTimer(d)
+	select {
+	case <-ctx.Done():
+		t.Stop()
+		return ctx.Err()
+	case <-t.C:
+		return nil
+	}
+}
+
+type sleeper func(ctx context.Context, d time.Duration) error
+
+// invoke implements Invoke, taking an additional sleeper argument for testing.
+func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
+	var retryer Retryer
+	for {
+		err := call(ctx, settings)
+		if err == nil {
+			return nil
+		}
+		if settings.Retry == nil {
+			return err
+		}
+		if retryer == nil {
+			if r := settings.Retry(); r != nil {
+				retryer = r
+			} else {
+				return err
+			}
+		}
+		if d, ok := retryer.Retry(err); !ok {
+			return err
+		} else if err = sp(ctx, d); err != nil {
+			return err
+		}
+	}
+}

+ 176 - 0
vendor/github.com/googleapis/gax-go/path_template.go

@@ -0,0 +1,176 @@
+// Copyright 2016, Google Inc.
+// 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.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+package gax
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+)
+
+type matcher interface {
+	match([]string) (int, error)
+	String() string
+}
+
+type segment struct {
+	matcher
+	name string
+}
+
+type labelMatcher string
+
+func (ls labelMatcher) match(segments []string) (int, error) {
+	if len(segments) == 0 {
+		return 0, fmt.Errorf("expected %s but no more segments found", ls)
+	}
+	if segments[0] != string(ls) {
+		return 0, fmt.Errorf("expected %s but got %s", ls, segments[0])
+	}
+	return 1, nil
+}
+
+func (ls labelMatcher) String() string {
+	return string(ls)
+}
+
+type wildcardMatcher int
+
+func (wm wildcardMatcher) match(segments []string) (int, error) {
+	if len(segments) == 0 {
+		return 0, errors.New("no more segments found")
+	}
+	return 1, nil
+}
+
+func (wm wildcardMatcher) String() string {
+	return "*"
+}
+
+type pathWildcardMatcher int
+
+func (pwm pathWildcardMatcher) match(segments []string) (int, error) {
+	length := len(segments) - int(pwm)
+	if length <= 0 {
+		return 0, errors.New("not sufficient segments are supplied for path wildcard")
+	}
+	return length, nil
+}
+
+func (pwm pathWildcardMatcher) String() string {
+	return "**"
+}
+
+type ParseError struct {
+	Pos      int
+	Template string
+	Message  string
+}
+
+func (pe ParseError) Error() string {
+	return fmt.Sprintf("at %d of template '%s', %s", pe.Pos, pe.Template, pe.Message)
+}
+
+// PathTemplate manages the template to build and match with paths used
+// by API services. It holds a template and variable names in it, and
+// it can extract matched patterns from a path string or build a path
+// string from a binding.
+//
+// See http.proto in github.com/googleapis/googleapis/ for the details of
+// the template syntax.
+type PathTemplate struct {
+	segments []segment
+}
+
+// NewPathTemplate parses a path template, and returns a PathTemplate
+// instance if successful.
+func NewPathTemplate(template string) (*PathTemplate, error) {
+	return parsePathTemplate(template)
+}
+
+// MustCompilePathTemplate is like NewPathTemplate but panics if the
+// expression cannot be parsed. It simplifies safe initialization of
+// global variables holding compiled regular expressions.
+func MustCompilePathTemplate(template string) *PathTemplate {
+	pt, err := NewPathTemplate(template)
+	if err != nil {
+		panic(err)
+	}
+	return pt
+}
+
+// Match attempts to match the given path with the template, and returns
+// the mapping of the variable name to the matched pattern string.
+func (pt *PathTemplate) Match(path string) (map[string]string, error) {
+	paths := strings.Split(path, "/")
+	values := map[string]string{}
+	for _, segment := range pt.segments {
+		length, err := segment.match(paths)
+		if err != nil {
+			return nil, err
+		}
+		if segment.name != "" {
+			value := strings.Join(paths[:length], "/")
+			if oldValue, ok := values[segment.name]; ok {
+				values[segment.name] = oldValue + "/" + value
+			} else {
+				values[segment.name] = value
+			}
+		}
+		paths = paths[length:]
+	}
+	if len(paths) != 0 {
+		return nil, fmt.Errorf("Trailing path %s remains after the matching", strings.Join(paths, "/"))
+	}
+	return values, nil
+}
+
+// Render creates a path string from its template and the binding from
+// the variable name to the value.
+func (pt *PathTemplate) Render(binding map[string]string) (string, error) {
+	result := make([]string, 0, len(pt.segments))
+	var lastVariableName string
+	for _, segment := range pt.segments {
+		name := segment.name
+		if lastVariableName != "" && name == lastVariableName {
+			continue
+		}
+		lastVariableName = name
+		if name == "" {
+			result = append(result, segment.String())
+		} else if value, ok := binding[name]; ok {
+			result = append(result, value)
+		} else {
+			return "", fmt.Errorf("%s is not found", name)
+		}
+	}
+	built := strings.Join(result, "/")
+	return built, nil
+}

+ 227 - 0
vendor/github.com/googleapis/gax-go/path_template_parser.go

@@ -0,0 +1,227 @@
+// Copyright 2016, Google Inc.
+// 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.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+package gax
+
+import (
+	"fmt"
+	"io"
+	"strings"
+)
+
+// This parser follows the syntax of path templates, from
+// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto.
+// The differences are that there is no custom verb, we allow the initial slash
+// to be absent, and that we are not strict as
+// https://tools.ietf.org/html/rfc6570 about the characters in identifiers and
+// literals.
+
+type pathTemplateParser struct {
+	r                *strings.Reader
+	runeCount        int             // the number of the current rune in the original string
+	nextVar          int             // the number to use for the next unnamed variable
+	seenName         map[string]bool // names we've seen already
+	seenPathWildcard bool            // have we seen "**" already?
+}
+
+func parsePathTemplate(template string) (pt *PathTemplate, err error) {
+	p := &pathTemplateParser{
+		r:        strings.NewReader(template),
+		seenName: map[string]bool{},
+	}
+
+	// Handle panics with strings like errors.
+	// See pathTemplateParser.error, below.
+	defer func() {
+		if x := recover(); x != nil {
+			errmsg, ok := x.(errString)
+			if !ok {
+				panic(x)
+			}
+			pt = nil
+			err = ParseError{p.runeCount, template, string(errmsg)}
+		}
+	}()
+
+	segs := p.template()
+	// If there is a path wildcard, set its length. We can't do this
+	// until we know how many segments we've got all together.
+	for i, seg := range segs {
+		if _, ok := seg.matcher.(pathWildcardMatcher); ok {
+			segs[i].matcher = pathWildcardMatcher(len(segs) - i - 1)
+			break
+		}
+	}
+	return &PathTemplate{segments: segs}, nil
+
+}
+
+// Used to indicate errors "thrown" by this parser. We don't use string because
+// many parts of the standard library panic with strings.
+type errString string
+
+// Terminates parsing immediately with an error.
+func (p *pathTemplateParser) error(msg string) {
+	panic(errString(msg))
+}
+
+// Template = [ "/" ] Segments
+func (p *pathTemplateParser) template() []segment {
+	var segs []segment
+	if p.consume('/') {
+		// Initial '/' needs an initial empty matcher.
+		segs = append(segs, segment{matcher: labelMatcher("")})
+	}
+	return append(segs, p.segments("")...)
+}
+
+// Segments = Segment { "/" Segment }
+func (p *pathTemplateParser) segments(name string) []segment {
+	var segs []segment
+	for {
+		subsegs := p.segment(name)
+		segs = append(segs, subsegs...)
+		if !p.consume('/') {
+			break
+		}
+	}
+	return segs
+}
+
+// Segment  = "*" | "**" | LITERAL | Variable
+func (p *pathTemplateParser) segment(name string) []segment {
+	if p.consume('*') {
+		if name == "" {
+			name = fmt.Sprintf("$%d", p.nextVar)
+			p.nextVar++
+		}
+		if p.consume('*') {
+			if p.seenPathWildcard {
+				p.error("multiple '**' disallowed")
+			}
+			p.seenPathWildcard = true
+			// We'll change 0 to the right number at the end.
+			return []segment{{name: name, matcher: pathWildcardMatcher(0)}}
+		}
+		return []segment{{name: name, matcher: wildcardMatcher(0)}}
+	}
+	if p.consume('{') {
+		if name != "" {
+			p.error("recursive named bindings are not allowed")
+		}
+		return p.variable()
+	}
+	return []segment{{name: name, matcher: labelMatcher(p.literal())}}
+}
+
+// Variable = "{" FieldPath [ "=" Segments ] "}"
+// "{" is already consumed.
+func (p *pathTemplateParser) variable() []segment {
+	// Simplification: treat FieldPath as LITERAL, instead of IDENT { '.' IDENT }
+	name := p.literal()
+	if p.seenName[name] {
+		p.error(name + " appears multiple times")
+	}
+	p.seenName[name] = true
+	var segs []segment
+	if p.consume('=') {
+		segs = p.segments(name)
+	} else {
+		// "{var}" is equivalent to "{var=*}"
+		segs = []segment{{name: name, matcher: wildcardMatcher(0)}}
+	}
+	if !p.consume('}') {
+		p.error("expected '}'")
+	}
+	return segs
+}
+
+// A literal is any sequence of characters other than a few special ones.
+// The list of stop characters is not quite the same as in the template RFC.
+func (p *pathTemplateParser) literal() string {
+	lit := p.consumeUntil("/*}{=")
+	if lit == "" {
+		p.error("empty literal")
+	}
+	return lit
+}
+
+// Read runes until EOF or one of the runes in stopRunes is encountered.
+// If the latter, unread the stop rune. Return the accumulated runes as a string.
+func (p *pathTemplateParser) consumeUntil(stopRunes string) string {
+	var runes []rune
+	for {
+		r, ok := p.readRune()
+		if !ok {
+			break
+		}
+		if strings.IndexRune(stopRunes, r) >= 0 {
+			p.unreadRune()
+			break
+		}
+		runes = append(runes, r)
+	}
+	return string(runes)
+}
+
+// If the next rune is r, consume it and return true.
+// Otherwise, leave the input unchanged and return false.
+func (p *pathTemplateParser) consume(r rune) bool {
+	rr, ok := p.readRune()
+	if !ok {
+		return false
+	}
+	if r == rr {
+		return true
+	}
+	p.unreadRune()
+	return false
+}
+
+// Read the next rune from the input. Return it.
+// The second return value is false at EOF.
+func (p *pathTemplateParser) readRune() (rune, bool) {
+	r, _, err := p.r.ReadRune()
+	if err == io.EOF {
+		return r, false
+	}
+	if err != nil {
+		p.error(err.Error())
+	}
+	p.runeCount++
+	return r, true
+}
+
+// Put the last rune that was read back on the input.
+func (p *pathTemplateParser) unreadRune() {
+	if err := p.r.UnreadRune(); err != nil {
+		p.error(err.Error())
+	}
+	p.runeCount--
+}

+ 30 - 6
vendor/vendor.json

@@ -6,6 +6,36 @@
 			"path": "appengine/cloudsql",
 			"revision": ""
 		},
+		{
+			"checksumSHA1": "/ixPd+hSgsbAjBI/fPqmHtTFRM8=",
+			"path": "cloud.google.com/go/iam",
+			"revision": "ef305dafe1fb55d8ee5fb61dd1e7b8f6a7d691e8",
+			"revisionTime": "2017-07-21T00:07:43Z"
+		},
+		{
+			"checksumSHA1": "vXPMGAHxvqWSpSFqqUfZBZS1dBo=",
+			"path": "cloud.google.com/go/internal",
+			"revision": "ef305dafe1fb55d8ee5fb61dd1e7b8f6a7d691e8",
+			"revisionTime": "2017-07-21T00:07:43Z"
+		},
+		{
+			"checksumSHA1": "W2xJ0+fvugRhRi1PMi64bYofBbU=",
+			"path": "cloud.google.com/go/internal/optional",
+			"revision": "ef305dafe1fb55d8ee5fb61dd1e7b8f6a7d691e8",
+			"revisionTime": "2017-07-21T00:07:43Z"
+		},
+		{
+			"checksumSHA1": "tGkW8f/KuiyOKB+vJh+1BNn765Q=",
+			"path": "cloud.google.com/go/internal/version",
+			"revision": "ef305dafe1fb55d8ee5fb61dd1e7b8f6a7d691e8",
+			"revisionTime": "2017-07-21T00:07:43Z"
+		},
+		{
+			"checksumSHA1": "hhbNfXCQ3cfJL/S47OMvQxb2hlk=",
+			"path": "cloud.google.com/go/storage",
+			"revision": "ef305dafe1fb55d8ee5fb61dd1e7b8f6a7d691e8",
+			"revisionTime": "2017-07-21T00:07:43Z"
+		},
 		{
 			"checksumSHA1": "7HXb3cry6luicWeJM9Uxwzfo9Rs=",
 			"path": "github.com/Unknwon/com",
@@ -430,12 +460,6 @@
 			"revision": "6687a2b4e824f4d87f2d65060ec5cb0d896dff1e",
 			"revisionTime": "2017-03-30T09:59:41Z"
 		},
-		{
-			"checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=",
-			"path": "github.com/golang/protobuf/proto",
-			"revision": "17ce1425424ab154092bbb43af630bd647f3bb0d",
-			"revisionTime": "2017-09-02T00:04:52Z"
-		},
 		{
 			"checksumSHA1": "B4bk7vdV9aD7AhrtATXfgEacdqE=",
 			"path": "github.com/gorilla/websocket",