...
1# `stream`
2
3[](https://godoc.org/github.com/google/go-containerregistry/pkg/v1/stream)
4
5The `stream` package contains an implementation of
6[`v1.Layer`](https://godoc.org/github.com/google/go-containerregistry/pkg/v1#Layer)
7that supports _streaming_ access, i.e. the layer contents are read once and not
8buffered.
9
10## Usage
11
12```go
13package main
14
15import (
16 "os"
17
18 "github.com/google/go-containerregistry/pkg/name"
19 "github.com/google/go-containerregistry/pkg/v1/remote"
20 "github.com/google/go-containerregistry/pkg/v1/stream"
21)
22
23// upload the contents of stdin as a layer to a local registry
24func main() {
25 repo, err := name.NewRepository("localhost:5000/stream")
26 if err != nil {
27 panic(err)
28 }
29
30 layer := stream.NewLayer(os.Stdin)
31
32 if err := remote.WriteLayer(repo, layer); err != nil {
33 panic(err)
34 }
35}
36```
37
38## Structure
39
40This implements the layer portion of an [image
41upload](/pkg/v1/remote#anatomy-of-an-image-upload). We launch a goroutine that
42is responsible for hashing the uncompressed contents to compute the `DiffID`,
43gzipping them to produce the `Compressed` contents, and hashing/counting the
44bytes to produce the `Digest`/`Size`. This goroutine writes to an
45`io.PipeWriter`, which blocks until `Compressed` reads the gzipped contents from
46the corresponding `io.PipeReader`.
47
48<p align="center">
49 <img src="/images/stream.dot.svg" />
50</p>
51
52## Caveats
53
54This assumes that you have an uncompressed layer (i.e. a tarball) and would like
55to compress it. Calling `Uncompressed` is always an error. Likewise, other
56methods are invalid until the contents of `Compressed` have been completely
57consumed and `Close`d.
58
59Using a `stream.Layer` will likely not work without careful consideration. For
60example, in the `mutate` package, we defer computing the manifest and config
61file until they are actually called. This allows you to `mutate.Append` a
62streaming layer to an image without accidentally consuming it. Similarly, in
63`remote.Write`, if calling `Digest` on a layer fails, we attempt to upload the
64layer anyway, understanding that we may be dealing with a `stream.Layer` whose
65contents need to be uploaded before we can upload the config file.
66
67Given the [structure](#structure) of how this is implemented, forgetting to
68`Close` a `stream.Layer` will leak a goroutine.
View as plain text