/
manifest.go
103 lines (90 loc) · 3.42 KB
/
manifest.go
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
package manifest
import (
"bytes"
"fmt"
"io"
"maps"
"os"
"path/filepath"
"slices"
"deps.dev/util/resolve"
"deps.dev/util/resolve/dep"
"github.com/google/osv-scanner/pkg/lockfile"
)
type Manifest struct {
FilePath string // Path to the manifest file on disk
Root resolve.Version // Version representing this package
Requirements []resolve.RequirementVersion // All direct requirements, including dev
Groups map[resolve.PackageKey][]string // Dependency groups that the imports belong to
LocalManifests []Manifest // manifests of local packages
EcosystemSpecific any // Any ecosystem-specific information needed
}
func newManifest() Manifest {
return Manifest{
Groups: make(map[resolve.PackageKey][]string),
}
}
func (m Manifest) System() resolve.System {
return m.Root.System
}
func (m Manifest) Clone() Manifest {
return Manifest{
FilePath: m.FilePath,
Root: m.Root,
Requirements: slices.Clone(m.Requirements),
Groups: maps.Clone(m.Groups),
LocalManifests: slices.Clone(m.LocalManifests),
EcosystemSpecific: m.EcosystemSpecific, // TODO: Deep copy this?
}
}
type DependencyPatch struct {
Pkg resolve.PackageKey // The package this applies to
Type dep.Type // The dependency type
OrigRequire string // The original requirement string e.g. "1.*.*"
NewRequire string // The new requirement string e.g. "2.*.*"
OrigResolved string // The version the original resolves to e.g. "1.2.3" (for display only)
NewResolved string // The version the new resolves to e.g. "2.4.6" (for display only)
}
type ManifestPatch struct {
Manifest *Manifest // The original manifest
Deps []DependencyPatch // Changed direct dependencies
EcosystemSpecific any // Any ecosystem-specific information
}
type ManifestIO interface {
// Read parses a manifest file into a Manifest, possibly recursively following references to other local manifest files
Read(file lockfile.DepFile) (Manifest, error)
// Write applies the ManifestPatch to the manifest, with minimal changes to the file.
// `original` is the original manifest file to read from. The updated manifest is written to `output`.
Write(original lockfile.DepFile, output io.Writer, patches ManifestPatch) error
}
// Overwrite applies the ManifestPatch to the manifest at filename.
// Used so as to not have the same file open for reading and writing at the same time.
func Overwrite(rw ManifestIO, filename string, p ManifestPatch) error {
r, err := lockfile.OpenLocalDepFile(filename)
if err != nil {
return err
}
var buf bytes.Buffer
err = rw.Write(r, &buf, p)
r.Close() // Make sure the file is closed before we start writing to it.
if err != nil {
return err
}
//nolint:gosec // Complaining about the 0644 permissions.
// The file already exists anyway so the permissions don't matter.
if err := os.WriteFile(filename, buf.Bytes(), 0644); err != nil {
return err
}
return nil
}
func GetManifestIO(pathToManifest string) (ManifestIO, error) {
base := filepath.Base(pathToManifest)
switch {
case base == "pom.xml":
return MavenManifestIO{}, nil
case base == "package.json":
return NpmManifestIO{}, nil
default:
return nil, fmt.Errorf("unsupported manifest type: %s", base)
}
}