github.com/cornelk/go-cloud@v0.17.1/blob/example_test.go (about) 1 // Copyright 2018 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package blob_test 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "log" 23 "os" 24 25 "cloud.google.com/go/storage" 26 "github.com/aws/aws-sdk-go/aws/awserr" 27 "github.com/cornelk/go-cloud/blob" 28 "github.com/cornelk/go-cloud/blob/fileblob" 29 _ "github.com/cornelk/go-cloud/blob/gcsblob" 30 _ "github.com/cornelk/go-cloud/blob/s3blob" 31 ) 32 33 func ExampleBucket_NewReader() { 34 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 35 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 36 ctx := context.Background() 37 var bucket *blob.Bucket 38 39 // Open the key "foo.txt" for reading with the default options. 40 r, err := bucket.NewReader(ctx, "foo.txt", nil) 41 if err != nil { 42 log.Fatal(err) 43 } 44 defer r.Close() 45 // Readers also have a limited view of the blob's metadata. 46 fmt.Println("Content-Type:", r.ContentType()) 47 fmt.Println() 48 // Copy from the reader to stdout. 49 if _, err := io.Copy(os.Stdout, r); err != nil { 50 log.Fatal(err) 51 } 52 } 53 54 func ExampleBucket_NewRangeReader() { 55 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 56 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 57 ctx := context.Background() 58 var bucket *blob.Bucket 59 60 // Open the key "foo.txt" for reading at offset 1024 and read up to 4096 bytes. 61 r, err := bucket.NewRangeReader(ctx, "foo.txt", 1024, 4096, nil) 62 if err != nil { 63 log.Fatal(err) 64 } 65 defer r.Close() 66 // Copy from the read range to stdout. 67 if _, err := io.Copy(os.Stdout, r); err != nil { 68 log.Fatal(err) 69 } 70 } 71 72 func ExampleBucket_NewWriter() { 73 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 74 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 75 ctx := context.Background() 76 var bucket *blob.Bucket 77 78 // Open the key "foo.txt" for writing with the default options. 79 w, err := bucket.NewWriter(ctx, "foo.txt", nil) 80 if err != nil { 81 log.Fatal(err) 82 } 83 _, writeErr := fmt.Fprintln(w, "Hello, World!") 84 // Always check the return value of Close when writing. 85 closeErr := w.Close() 86 if writeErr != nil { 87 log.Fatal(writeErr) 88 } 89 if closeErr != nil { 90 log.Fatal(closeErr) 91 } 92 } 93 94 func ExampleBucket_NewWriter_cancel() { 95 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 96 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 97 ctx := context.Background() 98 var bucket *blob.Bucket 99 100 // Create a cancelable context from the existing context. 101 writeCtx, cancelWrite := context.WithCancel(ctx) 102 defer cancelWrite() 103 104 // Open the key "foo.txt" for writing with the default options. 105 w, err := bucket.NewWriter(writeCtx, "foo.txt", nil) 106 if err != nil { 107 log.Fatal(err) 108 } 109 110 // Assume some writes happened and we encountered an error. 111 // Now we want to abort the write. 112 113 if err != nil { 114 // First cancel the context. 115 cancelWrite() 116 // You must still close the writer to avoid leaking resources. 117 w.Close() 118 } 119 } 120 121 func ExampleBucket_Delete() { 122 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 123 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 124 ctx := context.Background() 125 var bucket *blob.Bucket 126 127 if err := bucket.Delete(ctx, "foo.txt"); err != nil { 128 log.Fatal(err) 129 } 130 } 131 132 func Example() { 133 // Connect to a bucket when your program starts up. 134 // This example uses the file-based implementation in fileblob, and creates 135 // a temporary directory to use as the root directory. 136 dir, cleanup := newTempDir() 137 defer cleanup() 138 bucket, err := fileblob.OpenBucket(dir, nil) 139 if err != nil { 140 log.Fatal(err) 141 } 142 defer bucket.Close() 143 144 // We now have a *blob.Bucket! We can write our application using the 145 // *blob.Bucket type, and have the freedom to change the initialization code 146 // above to choose a different service-specific driver later. 147 148 // In this example, we'll write a blob and then read it. 149 ctx := context.Background() 150 if err := bucket.WriteAll(ctx, "foo.txt", []byte("Go Cloud Development Kit"), nil); err != nil { 151 log.Fatal(err) 152 } 153 b, err := bucket.ReadAll(ctx, "foo.txt") 154 if err != nil { 155 log.Fatal(err) 156 } 157 fmt.Println(string(b)) 158 159 // Output: 160 // Go Cloud Development Kit 161 } 162 163 func ExampleBucket_ErrorAs() { 164 // This example is specific to the s3blob implementation; it demonstrates 165 // access to the underlying awserr.Error type. 166 // The types exposed for ErrorAs by s3blob are documented in 167 // https://godoc.org/github.com/cornelk/go-cloud/blob/s3blob#hdr-As 168 169 ctx := context.Background() 170 171 b, err := blob.OpenBucket(ctx, "s3://my-bucket") 172 if err != nil { 173 log.Fatal(err) 174 } 175 defer b.Close() 176 177 _, err = b.ReadAll(ctx, "nosuchfile") 178 if err != nil { 179 var awsErr awserr.Error 180 if b.ErrorAs(err, &awsErr) { 181 fmt.Println(awsErr.Code()) 182 } 183 } 184 } 185 186 func ExampleBucket_List() { 187 // Connect to a bucket when your program starts up. 188 // This example uses the file-based implementation. 189 dir, cleanup := newTempDir() 190 defer cleanup() 191 192 // Create the file-based bucket. 193 bucket, err := fileblob.OpenBucket(dir, nil) 194 if err != nil { 195 log.Fatal(err) 196 } 197 defer bucket.Close() 198 199 // Create some blob objects for listing: "foo[0..4].txt". 200 ctx := context.Background() 201 for i := 0; i < 5; i++ { 202 if err := bucket.WriteAll(ctx, fmt.Sprintf("foo%d.txt", i), []byte("Go Cloud Development Kit"), nil); err != nil { 203 log.Fatal(err) 204 } 205 } 206 207 // Iterate over them. 208 // This will list the blobs created above because fileblob is strongly 209 // consistent, but is not guaranteed to work on all services. 210 iter := bucket.List(nil) 211 for { 212 obj, err := iter.Next(ctx) 213 if err == io.EOF { 214 break 215 } 216 if err != nil { 217 log.Fatal(err) 218 } 219 fmt.Println(obj.Key) 220 } 221 222 // Output: 223 // foo0.txt 224 // foo1.txt 225 // foo2.txt 226 // foo3.txt 227 // foo4.txt 228 } 229 230 func ExampleBucket_List_withDelimiter() { 231 // Connect to a bucket when your program starts up. 232 // This example uses the file-based implementation. 233 dir, cleanup := newTempDir() 234 defer cleanup() 235 236 // Create the file-based bucket. 237 bucket, err := fileblob.OpenBucket(dir, nil) 238 if err != nil { 239 log.Fatal(err) 240 } 241 defer bucket.Close() 242 243 // Create some blob objects in a hierarchy. 244 ctx := context.Background() 245 for _, key := range []string{ 246 "dir1/subdir/a.txt", 247 "dir1/subdir/b.txt", 248 "dir2/c.txt", 249 "d.txt", 250 } { 251 if err := bucket.WriteAll(ctx, key, []byte("Go Cloud Development Kit"), nil); err != nil { 252 log.Fatal(err) 253 } 254 } 255 256 // list lists files in b starting with prefix. It uses the delimiter "/", 257 // and recurses into "directories", adding 2 spaces to indent each time. 258 // It will list the blobs created above because fileblob is strongly 259 // consistent, but is not guaranteed to work on all services. 260 var list func(context.Context, *blob.Bucket, string, string) 261 list = func(ctx context.Context, b *blob.Bucket, prefix, indent string) { 262 iter := b.List(&blob.ListOptions{ 263 Delimiter: "/", 264 Prefix: prefix, 265 }) 266 for { 267 obj, err := iter.Next(ctx) 268 if err == io.EOF { 269 break 270 } 271 if err != nil { 272 log.Fatal(err) 273 } 274 fmt.Printf("%s%s\n", indent, obj.Key) 275 if obj.IsDir { 276 list(ctx, b, obj.Key, indent+" ") 277 } 278 } 279 } 280 list(ctx, bucket, "", "") 281 282 // Output: 283 // d.txt 284 // dir1/ 285 // dir1/subdir/ 286 // dir1/subdir/a.txt 287 // dir1/subdir/b.txt 288 // dir2/ 289 // dir2/c.txt 290 } 291 292 func ExampleBucket_As() { 293 // This example is specific to the gcsblob implementation; it demonstrates 294 // access to the underlying cloud.google.com/go/storage.Client type. 295 // The types exposed for As by gcsblob are documented in 296 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 297 298 // This URL will open the bucket "my-bucket" using default credentials. 299 ctx := context.Background() 300 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 301 if err != nil { 302 log.Fatal(err) 303 } 304 defer b.Close() 305 306 // Access storage.Client fields via gcsClient here. 307 var gcsClient *storage.Client 308 if b.As(&gcsClient) { 309 email, err := gcsClient.ServiceAccount(ctx, "project-name") 310 if err != nil { 311 log.Fatal(err) 312 } 313 _ = email 314 } else { 315 log.Println("Unable to access storage.Client through Bucket.As") 316 } 317 } 318 319 func ExampleWriterOptions() { 320 // This example is specific to the gcsblob implementation; it demonstrates 321 // access to the underlying cloud.google.com/go/storage.Writer type. 322 // The types exposed for As by gcsblob are documented in 323 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 324 325 ctx := context.Background() 326 327 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 328 if err != nil { 329 log.Fatal(err) 330 } 331 defer b.Close() 332 333 beforeWrite := func(as func(interface{}) bool) error { 334 var sw *storage.Writer 335 if as(&sw) { 336 fmt.Println(sw.ChunkSize) 337 } 338 return nil 339 } 340 341 options := blob.WriterOptions{BeforeWrite: beforeWrite} 342 if err := b.WriteAll(ctx, "newfile.txt", []byte("hello\n"), &options); err != nil { 343 log.Fatal(err) 344 } 345 } 346 347 func ExampleListObject_As() { 348 // This example is specific to the gcsblob implementation; it demonstrates 349 // access to the underlying cloud.google.com/go/storage.ObjectAttrs type. 350 // The types exposed for As by gcsblob are documented in 351 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 352 353 ctx := context.Background() 354 355 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 356 if err != nil { 357 log.Fatal(err) 358 } 359 defer b.Close() 360 361 iter := b.List(nil) 362 for { 363 obj, err := iter.Next(ctx) 364 if err == io.EOF { 365 break 366 } 367 if err != nil { 368 log.Fatal(err) 369 } 370 // Access storage.ObjectAttrs via oa here. 371 var oa storage.ObjectAttrs 372 if obj.As(&oa) { 373 _ = oa.Owner 374 } 375 } 376 } 377 378 func ExampleListOptions() { 379 // This example is specific to the gcsblob implementation; it demonstrates 380 // access to the underlying cloud.google.com/go/storage.Query type. 381 // The types exposed for As by gcsblob are documented in 382 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 383 384 ctx := context.Background() 385 386 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 387 if err != nil { 388 log.Fatal(err) 389 } 390 defer b.Close() 391 392 beforeList := func(as func(interface{}) bool) error { 393 // Access storage.Query via q here. 394 var q *storage.Query 395 if as(&q) { 396 _ = q.Delimiter 397 } 398 return nil 399 } 400 401 iter := b.List(&blob.ListOptions{Prefix: "", Delimiter: "/", BeforeList: beforeList}) 402 for { 403 obj, err := iter.Next(ctx) 404 if err == io.EOF { 405 break 406 } 407 if err != nil { 408 log.Fatal(err) 409 } 410 _ = obj 411 } 412 } 413 414 func ExamplePrefixedBucket() { 415 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 416 // PRAGMA: On github.com/cornelk/go-cloud, hide lines until the next blank line. 417 var bucket *blob.Bucket 418 419 // Wrap the bucket using blob.PrefixedBucket. 420 // The prefix should end with "/", so that the resulting bucket operates 421 // in a subfolder. 422 bucket = blob.PrefixedBucket(bucket, "a/subfolder/") 423 424 // The original bucket is no longer usable; it has been closed. 425 // The wrapped bucket should be closed when done. 426 defer bucket.Close() 427 428 // Bucket operations on <key> will be translated to "a/subfolder/<key>". 429 } 430 431 func ExampleReader_As() { 432 // This example is specific to the gcsblob implementation; it demonstrates 433 // access to the underlying cloud.google.com/go/storage.Reader type. 434 // The types exposed for As by gcsblob are documented in 435 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 436 437 ctx := context.Background() 438 439 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 440 if err != nil { 441 log.Fatal(err) 442 } 443 defer b.Close() 444 445 r, err := b.NewReader(ctx, "gopher.png", nil) 446 if err != nil { 447 log.Fatal(err) 448 } 449 defer r.Close() 450 451 // Access storage.Reader via sr here. 452 var sr *storage.Reader 453 if r.As(&sr) { 454 _ = sr.Attrs 455 } 456 } 457 458 func ExampleAttributes_As() { 459 // This example is specific to the gcsblob implementation; it demonstrates 460 // access to the underlying cloud.google.com/go/storage.ObjectAttrs type. 461 // The types exposed for As by gcsblob are documented in 462 // https://godoc.org/github.com/cornelk/go-cloud/blob/gcsblob#hdr-As 463 ctx := context.Background() 464 465 b, err := blob.OpenBucket(ctx, "gs://my-bucket") 466 if err != nil { 467 log.Fatal(err) 468 } 469 defer b.Close() 470 471 attrs, err := b.Attributes(ctx, "gopher.png") 472 if err != nil { 473 log.Fatal(err) 474 } 475 476 var oa storage.ObjectAttrs 477 if attrs.As(&oa) { 478 fmt.Println(oa.Owner) 479 } 480 } 481 482 func newTempDir() (string, func()) { 483 dir, err := ioutil.TempDir("", "go-cloud-blob-example") 484 if err != nil { 485 panic(err) 486 } 487 return dir, func() { os.RemoveAll(dir) } 488 }