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  }