summaryrefslogtreecommitdiffstats
path: root/models/migrations/v1_20/v250.go
blob: 86388ef0b801990599cfba04b8eafaebc358e7ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_20 //nolint

import (
	"strings"

	"code.gitea.io/gitea/modules/json"

	"xorm.io/xorm"
)

func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
	sess := x.NewSession()
	defer sess.Close()

	if err := sess.Begin(); err != nil {
		return err
	}

	type PackageVersion struct {
		ID           int64  `xorm:"pk autoincr"`
		MetadataJSON string `xorm:"metadata_json"`
	}

	type PackageBlob struct{}

	// Get all relevant packages (manifest list images have a container.manifest.reference property)

	var pvs []*PackageVersion
	err := sess.
		Table("package_version").
		Select("id, metadata_json").
		Where("id IN (SELECT DISTINCT ref_id FROM package_property WHERE ref_type = 0 AND name = 'container.manifest.reference')").
		Find(&pvs)
	if err != nil {
		return err
	}

	type MetadataOld struct {
		Type             string            `json:"type"`
		IsTagged         bool              `json:"is_tagged"`
		Platform         string            `json:"platform,omitempty"`
		Description      string            `json:"description,omitempty"`
		Authors          []string          `json:"authors,omitempty"`
		Licenses         string            `json:"license,omitempty"`
		ProjectURL       string            `json:"project_url,omitempty"`
		RepositoryURL    string            `json:"repository_url,omitempty"`
		DocumentationURL string            `json:"documentation_url,omitempty"`
		Labels           map[string]string `json:"labels,omitempty"`
		ImageLayers      []string          `json:"layer_creation,omitempty"`
		MultiArch        map[string]string `json:"multiarch,omitempty"`
	}

	type Manifest struct {
		Platform string `json:"platform"`
		Digest   string `json:"digest"`
		Size     int64  `json:"size"`
	}

	type MetadataNew struct {
		Type             string            `json:"type"`
		IsTagged         bool              `json:"is_tagged"`
		Platform         string            `json:"platform,omitempty"`
		Description      string            `json:"description,omitempty"`
		Authors          []string          `json:"authors,omitempty"`
		Licenses         string            `json:"license,omitempty"`
		ProjectURL       string            `json:"project_url,omitempty"`
		RepositoryURL    string            `json:"repository_url,omitempty"`
		DocumentationURL string            `json:"documentation_url,omitempty"`
		Labels           map[string]string `json:"labels,omitempty"`
		ImageLayers      []string          `json:"layer_creation,omitempty"`
		Manifests        []*Manifest       `json:"manifests,omitempty"`
	}

	for _, pv := range pvs {
		var old *MetadataOld
		if err := json.Unmarshal([]byte(pv.MetadataJSON), &old); err != nil {
			return err
		}

		// Calculate the size of every contained manifest

		manifests := make([]*Manifest, 0, len(old.MultiArch))
		for platform, digest := range old.MultiArch {
			size, err := sess.
				Table("package_blob").
				Join("INNER", "package_file", "package_blob.id = package_file.blob_id").
				Join("INNER", "package_version pv", "pv.id = package_file.version_id").
				Join("INNER", "package_version pv2", "pv2.package_id = pv.package_id").
				Where("pv.lower_version = ? AND pv2.id = ?", strings.ToLower(digest), pv.ID).
				SumInt(new(PackageBlob), "size")
			if err != nil {
				return err
			}

			manifests = append(manifests, &Manifest{
				Platform: platform,
				Digest:   digest,
				Size:     size,
			})
		}

		// Convert to new metadata format

		newMetadata := &MetadataNew{
			Type:             old.Type,
			IsTagged:         old.IsTagged,
			Platform:         old.Platform,
			Description:      old.Description,
			Authors:          old.Authors,
			Licenses:         old.Licenses,
			ProjectURL:       old.ProjectURL,
			RepositoryURL:    old.RepositoryURL,
			DocumentationURL: old.DocumentationURL,
			Labels:           old.Labels,
			ImageLayers:      old.ImageLayers,
			Manifests:        manifests,
		}

		metadataJSON, err := json.Marshal(newMetadata)
		if err != nil {
			return err
		}

		pv.MetadataJSON = string(metadataJSON)

		if _, err := sess.ID(pv.ID).Update(pv); err != nil {
			return err
		}
	}

	return sess.Commit()
}