func()

in manifest/schema1/config_builder.go [65:209]


func (mb *configManifestBuilder) Build(ctx context.Context) (m distribution.Manifest, err error) {
	type imageRootFS struct {
		Type      string   `json:"type"`
		DiffIDs   []diffID `json:"diff_ids,omitempty"`
		BaseLayer string   `json:"base_layer,omitempty"`
	}

	type imageHistory struct {
		Created    time.Time `json:"created"`
		Author     string    `json:"author,omitempty"`
		CreatedBy  string    `json:"created_by,omitempty"`
		Comment    string    `json:"comment,omitempty"`
		EmptyLayer bool      `json:"empty_layer,omitempty"`
	}

	type imageConfig struct {
		RootFS       *imageRootFS   `json:"rootfs,omitempty"`
		History      []imageHistory `json:"history,omitempty"`
		Architecture string         `json:"architecture,omitempty"`
	}

	var img imageConfig

	if err := json.Unmarshal(mb.configJSON, &img); err != nil {
		return nil, err
	}

	if len(img.History) == 0 {
		return nil, errors.New("empty history when trying to create schema1 manifest")
	}

	if len(img.RootFS.DiffIDs) != len(mb.descriptors) {
		return nil, fmt.Errorf("number of descriptors and number of layers in rootfs must match: len(%v) != len(%v)", img.RootFS.DiffIDs, mb.descriptors)
	}

	// Generate IDs for each layer
	// For non-top-level layers, create fake V1Compatibility strings that
	// fit the format and don't collide with anything else, but don't
	// result in runnable images on their own.
	type v1Compatibility struct {
		ID              string    `json:"id"`
		Parent          string    `json:"parent,omitempty"`
		Comment         string    `json:"comment,omitempty"`
		Created         time.Time `json:"created"`
		ContainerConfig struct {
			Cmd []string
		} `json:"container_config,omitempty"`
		Author    string `json:"author,omitempty"`
		ThrowAway bool   `json:"throwaway,omitempty"`
	}

	fsLayerList := make([]FSLayer, len(img.History))
	history := make([]History, len(img.History))

	parent := ""
	layerCounter := 0
	for i, h := range img.History[:len(img.History)-1] {
		var blobsum digest.Digest
		if h.EmptyLayer {
			if blobsum, err = mb.emptyTar(ctx); err != nil {
				return nil, err
			}
		} else {
			if len(img.RootFS.DiffIDs) <= layerCounter {
				return nil, errors.New("too many non-empty layers in History section")
			}
			blobsum = mb.descriptors[layerCounter].Digest
			layerCounter++
		}

		v1ID := digest.FromBytes([]byte(blobsum.Hex() + " " + parent)).Hex()

		if i == 0 && img.RootFS.BaseLayer != "" {
			// windows-only baselayer setup
			baseID := sha512.Sum384([]byte(img.RootFS.BaseLayer))
			parent = fmt.Sprintf("%x", baseID[:32])
		}

		v1Compatibility := v1Compatibility{
			ID:      v1ID,
			Parent:  parent,
			Comment: h.Comment,
			Created: h.Created,
			Author:  h.Author,
		}
		v1Compatibility.ContainerConfig.Cmd = []string{img.History[i].CreatedBy}
		if h.EmptyLayer {
			v1Compatibility.ThrowAway = true
		}
		jsonBytes, err := json.Marshal(&v1Compatibility)
		if err != nil {
			return nil, err
		}

		reversedIndex := len(img.History) - i - 1
		history[reversedIndex].V1Compatibility = string(jsonBytes)
		fsLayerList[reversedIndex] = FSLayer{BlobSum: blobsum}

		parent = v1ID
	}

	latestHistory := img.History[len(img.History)-1]

	var blobsum digest.Digest
	if latestHistory.EmptyLayer {
		if blobsum, err = mb.emptyTar(ctx); err != nil {
			return nil, err
		}
	} else {
		if len(img.RootFS.DiffIDs) <= layerCounter {
			return nil, errors.New("too many non-empty layers in History section")
		}
		blobsum = mb.descriptors[layerCounter].Digest
	}

	fsLayerList[0] = FSLayer{BlobSum: blobsum}
	dgst := digest.FromBytes([]byte(blobsum.Hex() + " " + parent + " " + string(mb.configJSON)))

	// Top-level v1compatibility string should be a modified version of the
	// image config.
	transformedConfig, err := MakeV1ConfigFromConfig(mb.configJSON, dgst.Hex(), parent, latestHistory.EmptyLayer)
	if err != nil {
		return nil, err
	}

	history[0].V1Compatibility = string(transformedConfig)

	tag := ""
	if tagged, isTagged := mb.ref.(reference.Tagged); isTagged {
		tag = tagged.Tag()
	}

	mfst := Manifest{
		Versioned: manifest.Versioned{
			SchemaVersion: 1,
		},
		Name:         mb.ref.Name(),
		Tag:          tag,
		Architecture: img.Architecture,
		FSLayers:     fsLayerList,
		History:      history,
	}

	return Sign(&mfst, mb.pk)
}