copyLayerFromStream is an implementation detail of copyLayer; mostly providing a separate “defer” scope. it copies a blob with srcInfo (with known Digest and Annotations and possibly known Size) from srcStream to dest, perhaps (de/re/)compressing the stream, and returns a complete blobInfo of the co
(ctx context.Context, srcStream io.Reader, srcInfo types.BlobInfo, diffIDIsNeeded bool, toEncrypt bool, bar *progressBar, layerIndex int, emptyLayer bool)
| 934 | // perhaps (de/re/)compressing the stream, |
| 935 | // and returns a complete blobInfo of the copied blob and perhaps a <-chan diffIDResult if diffIDIsNeeded, to be read by the caller. |
| 936 | func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Reader, srcInfo types.BlobInfo, |
| 937 | diffIDIsNeeded bool, toEncrypt bool, bar *progressBar, layerIndex int, emptyLayer bool) (types.BlobInfo, <-chan diffIDResult, error) { |
| 938 | var getDiffIDRecorder func(compressiontypes.DecompressorFunc) io.Writer // = nil |
| 939 | var diffIDChan chan diffIDResult |
| 940 | |
| 941 | err := errors.New("Internal error: unexpected panic in copyLayer") // For pipeWriter.CloseWithbelow |
| 942 | if diffIDIsNeeded { |
| 943 | diffIDChan = make(chan diffIDResult, 1) // Buffered, so that sending a value after this or our caller has failed and exited does not block. |
| 944 | pipeReader, pipeWriter := io.Pipe() |
| 945 | defer func() { // Note that this is not the same as {defer pipeWriter.CloseWithError(err)}; we need err to be evaluated lazily. |
| 946 | _ = pipeWriter.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil |
| 947 | }() |
| 948 | |
| 949 | getDiffIDRecorder = func(decompressor compressiontypes.DecompressorFunc) io.Writer { |
| 950 | // If this fails, e.g. because we have exited and due to pipeWriter.CloseWithError() above further |
| 951 | // reading from the pipe has failed, we don’t really care. |
| 952 | // We only read from diffIDChan if the rest of the flow has succeeded, and when we do read from it, |
| 953 | // the return value includes an error indication, which we do check. |
| 954 | // |
| 955 | // If this gets never called, pipeReader will not be used anywhere, but pipeWriter will only be |
| 956 | // closed above, so we are happy enough with both pipeReader and pipeWriter to just get collected by GC. |
| 957 | go diffIDComputationGoroutine(diffIDChan, pipeReader, decompressor) // Closes pipeReader |
| 958 | return pipeWriter |
| 959 | } |
| 960 | } |
| 961 | |
| 962 | blobInfo, err := ic.copyBlobFromStream(ctx, srcStream, srcInfo, getDiffIDRecorder, false, toEncrypt, bar, layerIndex, emptyLayer) // Sets err to nil on success |
| 963 | return blobInfo, diffIDChan, err |
| 964 | // We need the defer … pipeWriter.CloseWithError() to happen HERE so that the caller can block on reading from diffIDChan |
| 965 | } |
| 966 | |
| 967 | // diffIDComputationGoroutine reads all input from layerStream, uncompresses using decompressor if necessary, and sends its digest, and status, if any, to dest. |
| 968 | func diffIDComputationGoroutine(dest chan<- diffIDResult, layerStream io.ReadCloser, decompressor compressiontypes.DecompressorFunc) { |
no test coverage detected