ImageLoad takes an OCI format image tar stream and writes it locally. It should be efficient and only write missing blobs, based on their content hash. Returns any descriptors that are in the tar stream's index.json as manifests. Does not try to resolve lower levels. Most such tar streams will have
(r io.Reader)
| 148 | // Does not try to resolve lower levels. Most such tar streams will have a single |
| 149 | // manifest in the index.json's manifests list, but it is possible to have more. |
| 150 | func (p *Provider) ImageLoad(r io.Reader) ([]v1.Descriptor, error) { |
| 151 | var ( |
| 152 | tr = tar.NewReader(r) |
| 153 | index bytes.Buffer |
| 154 | ) |
| 155 | log.Debugf("ImageWriteTar to cache") |
| 156 | // get our lock |
| 157 | if err := p.Lock(); err != nil { |
| 158 | return nil, fmt.Errorf("unable to lock cache: %v", err) |
| 159 | } |
| 160 | defer p.Unlock() |
| 161 | for { |
| 162 | header, err := tr.Next() |
| 163 | if err == io.EOF { |
| 164 | break // End of archive |
| 165 | } |
| 166 | if err != nil { |
| 167 | return nil, err |
| 168 | } |
| 169 | |
| 170 | // get the filename and decide what to do with the file on that basis |
| 171 | // there are only a few kinds of files in an oci archive: |
| 172 | // blobs/sha256/<hash> - these we write out to our cache unless it already exists |
| 173 | // index.json - we just take the data out of it and append to our index.json |
| 174 | // manifest.json - not interested |
| 175 | // oci-layout - not interested |
| 176 | filename := header.Name |
| 177 | switch { |
| 178 | case filename == "manifest.json": |
| 179 | log.Debugf("ignoring %s", filename) |
| 180 | case filename == "oci-layout": |
| 181 | log.Debugf("ignoring %s", filename) |
| 182 | case header.Typeflag == tar.TypeDir: |
| 183 | log.Debugf("ignoring directory %s", filename) |
| 184 | case filename == "index.json": |
| 185 | log.Debugf("saving %s to memory to parse", filename) |
| 186 | // any errors should stop and get reported |
| 187 | if _, err := io.Copy(&index, tr); err != nil { |
| 188 | return nil, fmt.Errorf("error reading data for file %s : %v", filename, err) |
| 189 | } |
| 190 | case strings.HasPrefix(filename, "blobs/sha256/"): |
| 191 | // must have a file named blob/sha256/<hash> |
| 192 | parts := strings.Split(filename, "/") |
| 193 | // if we had a file that is just the directory, ignore it |
| 194 | if len(parts) != 3 { |
| 195 | log.Debugf("ignoring %s", filename) |
| 196 | continue |
| 197 | } |
| 198 | hash, err := v1.NewHash(fmt.Sprintf("%s:%s", parts[1], parts[2])) |
| 199 | if err != nil { |
| 200 | // malformed file |
| 201 | return nil, fmt.Errorf("invalid hash filename for %s: %v", filename, err) |
| 202 | } |
| 203 | log.Debugf("writing %s as hash %s", filename, hash) |
| 204 | if err := p.cache.WriteBlob(hash, io.NopCloser(tr)); err != nil { |
| 205 | return nil, fmt.Errorf("error reading data for file %s : %v", filename, err) |
| 206 | } |
| 207 | } |
no test coverage detected