manifest.go 3.05 KB
Newer Older
1
2
3
4
package server

import (
	"crypto/sha256"
Michael Yang's avatar
lint  
Michael Yang committed
5
	"encoding/hex"
6
	"encoding/json"
7
	"errors"
8
	"io"
9
	"log/slog"
10
11
12
13
14
15
16
	"os"
	"path/filepath"

	"github.com/ollama/ollama/types/model"
)

type Manifest struct {
Michael Yang's avatar
Michael Yang committed
17
18
19
20
	SchemaVersion int      `json:"schemaVersion"`
	MediaType     string   `json:"mediaType"`
	Config        *Layer   `json:"config"`
	Layers        []*Layer `json:"layers"`
21
22

	filepath string
23
	fi       os.FileInfo
24
	digest   string
25
26
27
28
29
30
31
32
33
34
}

func (m *Manifest) Size() (size int64) {
	for _, layer := range append(m.Layers, m.Config) {
		size += layer.Size
	}

	return
}

35
36
37
38
39
40
41
42
43
44
45
46
47
func (m *Manifest) Remove() error {
	if err := os.Remove(m.filepath); err != nil {
		return err
	}

	manifests, err := GetManifestPath()
	if err != nil {
		return err
	}

	return PruneDirectory(manifests)
}

48
49
func (m *Manifest) RemoveLayers() error {
	for _, layer := range append(m.Layers, m.Config) {
50
51
52
		if err := layer.Remove(); errors.Is(err, os.ErrNotExist) {
			slog.Debug("layer does not exist", "digest", layer.Digest)
		} else if err != nil {
53
54
55
56
57
58
59
			return err
		}
	}

	return nil
}

60
61
62
func ParseNamedManifest(n model.Name) (*Manifest, error) {
	if !n.IsFullyQualified() {
		return nil, model.Unqualified(n)
63
64
65
66
67
68
69
	}

	manifests, err := GetManifestPath()
	if err != nil {
		return nil, err
	}

70
71
	p := filepath.Join(manifests, n.Filepath())

Michael Yang's avatar
Michael Yang committed
72
	var m Manifest
73
	f, err := os.Open(p)
74
75
76
	if err != nil {
		return nil, err
	}
77
	defer f.Close()
78

79
80
81
82
83
	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

84
	sha256sum := sha256.New()
85
	if err := json.NewDecoder(io.TeeReader(f, sha256sum)).Decode(&m); err != nil {
86
87
88
		return nil, err
	}

Michael Yang's avatar
Michael Yang committed
89
90
	m.filepath = p
	m.fi = fi
Michael Yang's avatar
lint  
Michael Yang committed
91
	m.digest = hex.EncodeToString(sha256sum.Sum(nil))
Michael Yang's avatar
Michael Yang committed
92
93

	return &m, nil
94
95
}

96
97
98
99
func WriteManifest(name model.Name, config *Layer, layers []*Layer) error {
	manifests, err := GetManifestPath()
	if err != nil {
		return err
100
101
	}

102
103
	p := filepath.Join(manifests, name.Filepath())
	if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
104
105
106
		return err
	}

107
	f, err := os.Create(p)
108
109
110
	if err != nil {
		return err
	}
111
	defer f.Close()
112

Michael Yang's avatar
Michael Yang committed
113
	m := Manifest{
114
115
116
117
		SchemaVersion: 2,
		MediaType:     "application/vnd.docker.distribution.manifest.v2+json",
		Config:        config,
		Layers:        layers,
118
119
	}

120
	return json.NewEncoder(f).Encode(m)
121
}
122
123
124
125
126
127
128
129

func Manifests() (map[model.Name]*Manifest, error) {
	manifests, err := GetManifestPath()
	if err != nil {
		return nil, err
	}

	// TODO(mxyng): use something less brittle
Michael Yang's avatar
Michael Yang committed
130
	matches, err := filepath.Glob(filepath.Join(manifests, "*", "*", "*", "*"))
131
132
133
134
135
136
	if err != nil {
		return nil, err
	}

	ms := make(map[model.Name]*Manifest)
	for _, match := range matches {
Michael Yang's avatar
Michael Yang committed
137
		fi, err := os.Stat(match)
138
139
140
141
		if err != nil {
			return nil, err
		}

Michael Yang's avatar
Michael Yang committed
142
143
144
145
146
147
148
149
150
151
152
153
154
		if !fi.IsDir() {
			rel, err := filepath.Rel(manifests, match)
			if err != nil {
				slog.Warn("bad filepath", "path", match, "error", err)
				continue
			}

			n := model.ParseNameFromFilepath(rel)
			if !n.IsValid() {
				slog.Warn("bad manifest name", "path", rel, "error", err)
				continue
			}

155
156
			m, err := ParseNamedManifest(n)
			if err != nil {
157
158
				slog.Warn("bad manifest", "name", n, "error", err)
				continue
159
160
161
162
163
164
165
166
			}

			ms[n] = m
		}
	}

	return ms, nil
}