123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package server
- import (
- "crypto/sha256"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "log/slog"
- "os"
- "path/filepath"
- "github.com/ollama/ollama/types/model"
- )
- type Manifest struct {
- SchemaVersion int `json:"schemaVersion"`
- MediaType string `json:"mediaType"`
- Config *Layer `json:"config"`
- Layers []*Layer `json:"layers"`
- filepath string
- fi os.FileInfo
- digest string
- }
- func (m *Manifest) Size() (size int64) {
- for _, layer := range append(m.Layers, m.Config) {
- size += layer.Size
- }
- return
- }
- 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)
- }
- func (m *Manifest) RemoveLayers() error {
- for _, layer := range append(m.Layers, m.Config) {
- if err := layer.Remove(); errors.Is(err, os.ErrNotExist) {
- slog.Debug("layer does not exist", "digest", layer.Digest)
- } else if err != nil {
- return err
- }
- }
- return nil
- }
- func ParseNamedManifest(n model.Name) (*Manifest, error) {
- if !n.IsFullyQualified() {
- return nil, model.Unqualified(n)
- }
- manifests, err := GetManifestPath()
- if err != nil {
- return nil, err
- }
- p := filepath.Join(manifests, n.Filepath())
- var m Manifest
- f, err := os.Open(p)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- fi, err := f.Stat()
- if err != nil {
- return nil, err
- }
- sha256sum := sha256.New()
- if err := json.NewDecoder(io.TeeReader(f, sha256sum)).Decode(&m); err != nil {
- return nil, err
- }
- m.filepath = p
- m.fi = fi
- m.digest = fmt.Sprintf("%x", sha256sum.Sum(nil))
- return &m, nil
- }
- func WriteManifest(name model.Name, config *Layer, layers []*Layer) error {
- manifests, err := GetManifestPath()
- if err != nil {
- return err
- }
- p := filepath.Join(manifests, name.Filepath())
- if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
- return err
- }
- f, err := os.Create(p)
- if err != nil {
- return err
- }
- defer f.Close()
- m := Manifest{
- SchemaVersion: 2,
- MediaType: "application/vnd.docker.distribution.manifest.v2+json",
- Config: config,
- Layers: layers,
- }
- return json.NewEncoder(f).Encode(m)
- }
- func Manifests() (map[model.Name]*Manifest, error) {
- manifests, err := GetManifestPath()
- if err != nil {
- return nil, err
- }
- // TODO(mxyng): use something less brittle
- matches, err := filepath.Glob(filepath.Join(manifests, "*", "*", "*", "*"))
- if err != nil {
- return nil, err
- }
- ms := make(map[model.Name]*Manifest)
- for _, match := range matches {
- fi, err := os.Stat(match)
- if err != nil {
- return nil, err
- }
- 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
- }
- m, err := ParseNamedManifest(n)
- if err != nil {
- slog.Warn("bad manifest", "name", n, "error", err)
- continue
- }
- ms[n] = m
- }
- }
- return ms, nil
- }
|