| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,6 +62,7 @@ type storageClient interface { | |||
| 62 | 62 | GetObject(ctx context.Context, params *getObjectParams, opts ...storageOption) (*ObjectAttrs, error) | |
| 63 | 63 | UpdateObject(ctx context.Context, params *updateObjectParams, opts ...storageOption) (*ObjectAttrs, error) | |
| 64 | 64 | RestoreObject(ctx context.Context, params *restoreObjectParams, opts ...storageOption) (*ObjectAttrs, error) | |
| 65 | + MoveObject(ctx context.Context, params *moveObjectParams, opts ...storageOption) (*ObjectAttrs, error) | ||
| 65 | 66 | ||
| 66 | 67 | // Default Object ACL methods. | |
| 67 | 68 | ||
@@ -313,6 +314,13 @@ type restoreObjectParams struct { | |||
| 313 | 314 | copySourceACL bool | |
| 314 | 315 | } | |
| 315 | 316 | ||
| 317 | + type moveObjectParams struct { | ||
| 318 | + bucket, srcObject, dstObject string | ||
| 319 | + srcConds *Conditions | ||
| 320 | + dstConds *Conditions | ||
| 321 | + encryptionKey []byte | ||
| 322 | + } | ||
| 323 | + | ||
| 316 | 324 | type composeObjectRequest struct { | |
| 317 | 325 | dstBucket string | |
| 318 | 326 | dstObject destinationObject | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,7 +6,7 @@ retract [v1.25.0, v1.27.0] // due to https://github.com/googleapis/google-cloud- | |||
| 6 | 6 | ||
| 7 | 7 | require ( | |
| 8 | 8 | cloud.google.com/go v0.116.0 | |
| 9 | - cloud.google.com/go/compute/metadata v0.5.2 | ||
| 9 | + cloud.google.com/go/compute/metadata v0.6.0 | ||
| 10 | 10 | cloud.google.com/go/iam v1.2.2 | |
| 11 | 11 | cloud.google.com/go/longrunning v0.6.2 | |
| 12 | 12 | github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 | |
@@ -20,7 +20,7 @@ require ( | |||
| 20 | 20 | go.opentelemetry.io/otel/sdk/metric v1.29.0 | |
| 21 | 21 | golang.org/x/oauth2 v0.24.0 | |
| 22 | 22 | golang.org/x/sync v0.10.0 | |
| 23 | - google.golang.org/api v0.211.0 | ||
| 23 | + google.golang.org/api v0.212.0 | ||
| 24 | 24 | google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 | |
| 25 | 25 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 | |
| 26 | 26 | google.golang.org/grpc v1.67.3 | |
@@ -29,7 +29,7 @@ require ( | |||
| 29 | 29 | ||
| 30 | 30 | require ( | |
| 31 | 31 | cel.dev/expr v0.16.1 // indirect | |
| 32 | - cloud.google.com/go/auth v0.12.1 // indirect | ||
| 32 | + cloud.google.com/go/auth v0.13.0 // indirect | ||
| 33 | 33 | cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect | |
| 34 | 34 | cloud.google.com/go/monitoring v1.21.2 // indirect | |
| 35 | 35 | github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,12 +3,12 @@ cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= | |||
| 3 | 3 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |
| 4 | 4 | cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= | |
| 5 | 5 | cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= | |
| 6 | - cloud.google.com/go/auth v0.12.1 h1:n2Bj25BUMM0nvE9D2XLTiImanwZhO3DkfWSYS/SAJP4= | ||
| 7 | - cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9mbendF4= | ||
| 6 | + cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= | ||
| 7 | + cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= | ||
| 8 | 8 | cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= | |
| 9 | 9 | cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= | |
| 10 | - cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= | ||
| 11 | - cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= | ||
| 10 | + cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= | ||
| 11 | + cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= | ||
| 12 | 12 | cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= | |
| 13 | 13 | cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= | |
| 14 | 14 | cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk= | |
@@ -167,8 +167,8 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 | |||
| 167 | 167 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |
| 168 | 168 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | |
| 169 | 169 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
| 170 | - google.golang.org/api v0.211.0 h1:IUpLjq09jxBSV1lACO33CGY3jsRcbctfGzhj+ZSE/Bg= | ||
| 171 | - google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0= | ||
| 170 | + google.golang.org/api v0.212.0 h1:BcRj3MJfHF3FYD29rk7u9kuu1SyfGqfHcA0hSwKqkHg= | ||
| 171 | + google.golang.org/api v0.212.0/go.mod h1:gICpLlpp12/E8mycRMzgy3SQ9cFh2XnVJ6vJi/kQbvI= | ||
| 172 | 172 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |
| 173 | 173 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |
| 174 | 174 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -662,6 +662,36 @@ func (c *grpcStorageClient) RestoreObject(ctx context.Context, params *restoreOb | |||
| 662 | 662 | return attrs, err | |
| 663 | 663 | } | |
| 664 | 664 | ||
| 665 | + func (c *grpcStorageClient) MoveObject(ctx context.Context, params *moveObjectParams, opts ...storageOption) (*ObjectAttrs, error) { | ||
| 666 | + s := callSettings(c.settings, opts...) | ||
| 667 | + req := &storagepb.MoveObjectRequest{ | ||
| 668 | + Bucket: bucketResourceName(globalProjectAlias, params.bucket), | ||
| 669 | + SourceObject: params.srcObject, | ||
| 670 | + DestinationObject: params.dstObject, | ||
| 671 | + } | ||
| 672 | + if err := applyCondsProto("MoveObjectDestination", defaultGen, params.dstConds, req); err != nil { | ||
| 673 | + return nil, err | ||
| 674 | + } | ||
| 675 | + if err := applySourceCondsProto("MoveObjectSource", defaultGen, params.srcConds, req); err != nil { | ||
| 676 | + return nil, err | ||
| 677 | + } | ||
| 678 | + | ||
| 679 | + if s.userProject != "" { | ||
| 680 | + ctx = setUserProjectMetadata(ctx, s.userProject) | ||
| 681 | + } | ||
| 682 | + | ||
| 683 | + var attrs *ObjectAttrs | ||
| 684 | + err := run(ctx, func(ctx context.Context) error { | ||
| 685 | + res, err := c.raw.MoveObject(ctx, req, s.gax...) | ||
| 686 | + attrs = newObjectFromProto(res) | ||
| 687 | + return err | ||
| 688 | + }, s.retry, s.idempotent) | ||
| 689 | + if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound { | ||
| 690 | + return nil, ErrObjectNotExist | ||
| 691 | + } | ||
| 692 | + return attrs, err | ||
| 693 | + } | ||
| 694 | + | ||
| 665 | 695 | // Default Object ACL methods. | |
| 666 | 696 | ||
| 667 | 697 | func (c *grpcStorageClient) DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { | |
@@ -926,7 +956,7 @@ func (c *grpcStorageClient) RewriteObject(ctx context.Context, req *rewriteObjec | |||
| 926 | 956 | if err := applyCondsProto("Copy destination", defaultGen, req.dstObject.conds, call); err != nil { | |
| 927 | 957 | return nil, err | |
| 928 | 958 | } | |
| 929 | - if err := applySourceCondsProto(req.srcObject.gen, req.srcObject.conds, call); err != nil { | ||
| 959 | + if err := applySourceCondsProto("Copy source", req.srcObject.gen, req.srcObject.conds, call); err != nil { | ||
| 930 | 960 | return nil, err | |
| 931 | 961 | } | |
| 932 | 962 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -593,6 +593,31 @@ func (c *httpStorageClient) RestoreObject(ctx context.Context, params *restoreOb | |||
| 593 | 593 | return newObject(obj), err | |
| 594 | 594 | } | |
| 595 | 595 | ||
| 596 | + func (c *httpStorageClient) MoveObject(ctx context.Context, params *moveObjectParams, opts ...storageOption) (*ObjectAttrs, error) { | ||
| 597 | + s := callSettings(c.settings, opts...) | ||
| 598 | + req := c.raw.Objects.Move(params.bucket, params.srcObject, params.dstObject).Context(ctx) | ||
| 599 | + if err := applyConds("MoveObjectDestination", defaultGen, params.dstConds, req); err != nil { | ||
| 600 | + return nil, err | ||
| 601 | + } | ||
| 602 | + if err := applySourceConds("MoveObjectSource", defaultGen, params.srcConds, req); err != nil { | ||
| 603 | + return nil, err | ||
| 604 | + } | ||
| 605 | + if s.userProject != "" { | ||
| 606 | + req.UserProject(s.userProject) | ||
| 607 | + } | ||
| 608 | + if err := setEncryptionHeaders(req.Header(), params.encryptionKey, false); err != nil { | ||
| 609 | + return nil, err | ||
| 610 | + } | ||
| 611 | + var obj *raw.Object | ||
| 612 | + var err error | ||
| 613 | + err = run(ctx, func(ctx context.Context) error { obj, err = req.Context(ctx).Do(); return err }, s.retry, s.idempotent) | ||
| 614 | + var e *googleapi.Error | ||
| 615 | + if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound { | ||
| 616 | + return nil, ErrObjectNotExist | ||
| 617 | + } | ||
| 618 | + return newObject(obj), err | ||
| 619 | + } | ||
| 620 | + | ||
| 596 | 621 | // Default Object ACL methods. | |
| 597 | 622 | ||
| 598 | 623 | func (c *httpStorageClient) DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { | |
@@ -798,7 +823,7 @@ func (c *httpStorageClient) RewriteObject(ctx context.Context, req *rewriteObjec | |||
| 798 | 823 | if err := applyConds("Copy destination", defaultGen, req.dstObject.conds, call); err != nil { | |
| 799 | 824 | return nil, err | |
| 800 | 825 | } | |
| 801 | - if err := applySourceConds(req.srcObject.gen, req.srcObject.conds, call); err != nil { | ||
| 826 | + if err := applySourceConds("Copy source", req.srcObject.gen, req.srcObject.conds, call); err != nil { | ||
| 802 | 827 | return nil, err | |
| 803 | 828 | } | |
| 804 | 829 | if s.userProject != "" { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4603,6 +4603,78 @@ func TestIntegration_SoftDelete(t *testing.T) { | |||
| 4603 | 4603 | }) | |
| 4604 | 4604 | } | |
| 4605 | 4605 | ||
| 4606 | + func TestIntegration_ObjectMove(t *testing.T) { | ||
| 4607 | + multiTransportTest(skipJSONReads(context.Background(), "no reads in test"), t, func(t *testing.T, ctx context.Context, _, prefix string, client *Client) { | ||
| 4608 | + h := testHelper{t} | ||
| 4609 | + srcObj := "move-src-obj" | ||
| 4610 | + dstObj := "move-dst-obj" | ||
| 4611 | + | ||
| 4612 | + // Create bucket with HNS enabled | ||
| 4613 | + bkt := client.Bucket(prefix + uidSpace.New()) | ||
| 4614 | + attrs := &BucketAttrs{ | ||
| 4615 | + HierarchicalNamespace: &HierarchicalNamespace{Enabled: true}, | ||
| 4616 | + UniformBucketLevelAccess: UniformBucketLevelAccess{Enabled: true}, | ||
| 4617 | + SoftDeletePolicy: &SoftDeletePolicy{RetentionDuration: 0}, | ||
| 4618 | + } | ||
| 4619 | + if err := bkt.Create(ctx, testutil.ProjID(), attrs); err != nil { | ||
| 4620 | + t.Fatalf("error creating bucket with soft delete policy set: %v", err) | ||
| 4621 | + } | ||
| 4622 | + t.Cleanup(func() { h.mustDeleteBucket(bkt) }) | ||
| 4623 | + | ||
| 4624 | + // Create source object | ||
| 4625 | + obj := bkt.Object(srcObj) | ||
| 4626 | + w := obj.NewWriter(ctx) | ||
| 4627 | + h.mustWrite(w, randomContents()) | ||
| 4628 | + t.Cleanup(func() { h.mustDeleteObject(bkt.Object(dstObj)) }) | ||
| 4629 | + | ||
| 4630 | + // Move object | ||
| 4631 | + objAttrs, err := obj.Move(ctx, MoveObjectDestination{Object: dstObj}) | ||
| 4632 | + if err != nil { | ||
| 4633 | + t.Fatalf("ObjectHandle.Move: %v", err) | ||
| 4634 | + } | ||
| 4635 | + // Check attrs are populated. | ||
| 4636 | + if objAttrs == nil || objAttrs.Name == "" { | ||
| 4637 | + t.Errorf("wanted object attrs to be populated; got %+v", objAttrs) | ||
| 4638 | + } | ||
| 4639 | + // Check source object is no longer present. | ||
| 4640 | + if _, err := obj.Attrs(ctx); !errors.Is(err, ErrObjectNotExist) { | ||
| 4641 | + t.Errorf("source object: got err %v, want ErrObjectNotExist", err) | ||
| 4642 | + } | ||
| 4643 | + | ||
| 4644 | + // Test that source and destination preconditions are applied appropriately. | ||
| 4645 | + srcObj2 := "move-src-obj2" | ||
| 4646 | + dstObj2 := "move-dst-obj2" | ||
| 4647 | + | ||
| 4648 | + obj2 := bkt.Object(srcObj2) | ||
| 4649 | + w2 := obj2.NewWriter(ctx) | ||
| 4650 | + h.mustWrite(w2, randomContents()) | ||
| 4651 | + t.Cleanup(func() { h.mustDeleteObject(bkt.Object(dstObj2)) }) | ||
| 4652 | + | ||
| 4653 | + // Bad source generation should cause 412. | ||
| 4654 | + _, err = obj2.If(Conditions{ | ||
| 4655 | + GenerationMatch: 123, | ||
| 4656 | + }).Move(ctx, MoveObjectDestination{Object: dstObj2}) | ||
| 4657 | + if err == nil || !(status.Code(err) == codes.FailedPrecondition || extractErrCode(err) == http.StatusPreconditionFailed) { | ||
| 4658 | + t.Errorf("ObjectHandle.Move: got err %v, want failed precondition (412)", err) | ||
| 4659 | + } | ||
| 4660 | + | ||
| 4661 | + // Bad dest generation should also cause 412. | ||
| 4662 | + _, err = obj2.Move(ctx, MoveObjectDestination{Object: dstObj2, Conditions: &Conditions{GenerationMatch: 123}}) | ||
| 4663 | + if err == nil || !(status.Code(err) == codes.FailedPrecondition || extractErrCode(err) == http.StatusPreconditionFailed) { | ||
| 4664 | + t.Errorf("ObjectHandle.Move: got err %v, want failed precondition (412)", err) | ||
| 4665 | + } | ||
| 4666 | + | ||
| 4667 | + // Correctly applied preconditions should work. | ||
| 4668 | + _, err = obj2.If(Conditions{ | ||
| 4669 | + GenerationMatch: w2.Attrs().Generation, | ||
| 4670 | + MetagenerationMatch: w2.Attrs().Metageneration, | ||
| 4671 | + }).Move(ctx, MoveObjectDestination{Object: dstObj2, Conditions: &Conditions{DoesNotExist: true}}) | ||
| 4672 | + if err != nil { | ||
| 4673 | + t.Fatalf("ObjectHandle.Move: %v", err) | ||
| 4674 | + } | ||
| 4675 | + }) | ||
| 4676 | + } | ||
| 4677 | + | ||
| 4606 | 4678 | func TestIntegration_KMS(t *testing.T) { | |
| 4607 | 4679 | multiTransportTest(context.Background(), t, func(t *testing.T, ctx context.Context, bucket, prefix string, client *Client) { | |
| 4608 | 4680 | h := testHelper{t} | |
| Back | FazBrowse Home | New Git URL |
0 commit comments