summaryrefslogtreecommitdiffstats
path: root/services/doctor/packages_nuget.go
blob: 47fdb3ac12cc41de368eaa96f5ea9460c763ca55 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package doctor

import (
	"context"
	"fmt"
	"slices"
	"strings"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/models/packages"
	"code.gitea.io/gitea/modules/log"
	packages_module "code.gitea.io/gitea/modules/packages"
	nuget_module "code.gitea.io/gitea/modules/packages/nuget"
	packages_service "code.gitea.io/gitea/services/packages"

	"xorm.io/builder"
)

func init() {
	Register(&Check{
		Title:       "Extract Nuget Nuspec Files to content store",
		Name:        "packages-nuget-nuspec",
		IsDefault:   false,
		Run:         PackagesNugetNuspecCheck,
		Priority:    15,
		InitStorage: true,
	})
}

func PackagesNugetNuspecCheck(ctx context.Context, logger log.Logger, autofix bool) error {
	found := 0
	fixed := 0
	errors := 0

	err := db.Iterate(ctx, builder.Eq{"package.type": packages.TypeNuGet, "package.is_internal": false}, func(ctx context.Context, pkg *packages.Package) error {
		logger.Info("Processing package %s", pkg.Name)

		pvs, _, err := packages.SearchVersions(ctx, &packages.PackageSearchOptions{
			Type:      packages.TypeNuGet,
			PackageID: pkg.ID,
		})
		if err != nil {
			// Should never happen
			logger.Error("Failed to search for versions for package %s: %v", pkg.Name, err)
			return err
		}

		logger.Info("Found %d versions for package %s", len(pvs), pkg.Name)

		for _, pv := range pvs {
			pfs, err := packages.GetFilesByVersionID(ctx, pv.ID)
			if err != nil {
				logger.Error("Failed to get files for package version %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}

			if slices.ContainsFunc(pfs, func(pf *packages.PackageFile) bool { return strings.HasSuffix(pf.LowerName, ".nuspec") }) {
				logger.Debug("Nuspec file already exists for %s %s", pkg.Name, pv.Version)
				continue
			}

			nupkgIdx := slices.IndexFunc(pfs, func(pf *packages.PackageFile) bool { return pf.IsLead })

			if nupkgIdx < 0 {
				logger.Error("Missing nupkg file for %s %s", pkg.Name, pv.Version)
				errors++
				continue
			}

			pf := pfs[nupkgIdx]

			logger.Warn("Missing nuspec file found for %s %s", pkg.Name, pv.Version)
			found++

			if !autofix {
				continue
			}

			s, _, _, err := packages_service.GetPackageFileStream(ctx, pf)
			if err != nil {
				logger.Error("Failed to get nupkg file stream for %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}
			defer s.Close()

			buf, err := packages_module.CreateHashedBufferFromReader(s)
			if err != nil {
				logger.Error("Failed to create hashed buffer for nupkg from reader for %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}
			defer buf.Close()

			np, err := nuget_module.ParsePackageMetaData(buf, buf.Size())
			if err != nil {
				logger.Error("Failed to parse package metadata for %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}

			nuspecBuf, err := packages_module.CreateHashedBufferFromReaderWithSize(np.NuspecContent, np.NuspecContent.Len())
			if err != nil {
				logger.Error("Failed to create hashed buffer for nuspec from reader for %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}
			defer nuspecBuf.Close()

			_, err = packages_service.AddFileToPackageVersionInternal(
				ctx,
				pv,
				&packages_service.PackageFileCreationInfo{
					PackageFileInfo: packages_service.PackageFileInfo{
						Filename: fmt.Sprintf("%s.nuspec", pkg.LowerName),
					},
					Data:   nuspecBuf,
					IsLead: false,
				},
			)
			if err != nil {
				logger.Error("Failed to add nuspec file for %s %s: %v", pkg.Name, pv.Version, err)
				errors++
				continue
			}

			fixed++
		}

		return nil
	})
	if err != nil {
		logger.Error("Failed to iterate over users: %v", err)
		return err
	}

	if autofix {
		if fixed > 0 {
			logger.Info("Fixed %d package versions by extracting nuspec files", fixed)
		} else {
			logger.Info("No package versions with missing nuspec files found")
		}
	} else {
		if found > 0 {
			logger.Info("Found %d package versions with missing nuspec files", found)
		} else {
			logger.Info("No package versions with missing nuspec files found")
		}
	}

	if errors > 0 {
		return fmt.Errorf("failed to fix %d nuspec files", errors)
	}

	return nil
}