manifest.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package server
  2. import (
  3. "crypto/sha256"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "log/slog"
  9. "os"
  10. "path/filepath"
  11. "github.com/ollama/ollama/types/model"
  12. )
  13. type Manifest struct {
  14. ManifestV2
  15. filepath string
  16. fi os.FileInfo
  17. digest string
  18. }
  19. func (m *Manifest) Size() (size int64) {
  20. for _, layer := range append(m.Layers, m.Config) {
  21. size += layer.Size
  22. }
  23. return
  24. }
  25. func (m *Manifest) Remove() error {
  26. if err := os.Remove(m.filepath); err != nil {
  27. return err
  28. }
  29. manifests, err := GetManifestPath()
  30. if err != nil {
  31. return err
  32. }
  33. return PruneDirectory(manifests)
  34. }
  35. func (m *Manifest) RemoveLayers() error {
  36. for _, layer := range append(m.Layers, m.Config) {
  37. if err := layer.Remove(); errors.Is(err, os.ErrNotExist) {
  38. slog.Debug("layer does not exist", "digest", layer.Digest)
  39. } else if err != nil {
  40. return err
  41. }
  42. }
  43. return nil
  44. }
  45. func ParseNamedManifest(n model.Name) (*Manifest, error) {
  46. if !n.IsFullyQualified() {
  47. return nil, model.Unqualified(n)
  48. }
  49. manifests, err := GetManifestPath()
  50. if err != nil {
  51. return nil, err
  52. }
  53. p := filepath.Join(manifests, n.Filepath())
  54. var m ManifestV2
  55. f, err := os.Open(p)
  56. if err != nil {
  57. return nil, err
  58. }
  59. defer f.Close()
  60. fi, err := f.Stat()
  61. if err != nil {
  62. return nil, err
  63. }
  64. sha256sum := sha256.New()
  65. if err := json.NewDecoder(io.TeeReader(f, sha256sum)).Decode(&m); err != nil {
  66. return nil, err
  67. }
  68. return &Manifest{
  69. ManifestV2: m,
  70. filepath: p,
  71. fi: fi,
  72. digest: fmt.Sprintf("%x", sha256sum.Sum(nil)),
  73. }, nil
  74. }
  75. func WriteManifest(name model.Name, config *Layer, layers []*Layer) error {
  76. manifests, err := GetManifestPath()
  77. if err != nil {
  78. return err
  79. }
  80. p := filepath.Join(manifests, name.Filepath())
  81. if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
  82. return err
  83. }
  84. f, err := os.Create(p)
  85. if err != nil {
  86. return err
  87. }
  88. defer f.Close()
  89. m := ManifestV2{
  90. SchemaVersion: 2,
  91. MediaType: "application/vnd.docker.distribution.manifest.v2+json",
  92. Config: config,
  93. Layers: layers,
  94. }
  95. return json.NewEncoder(f).Encode(m)
  96. }
  97. func Manifests() (map[model.Name]*Manifest, error) {
  98. manifests, err := GetManifestPath()
  99. if err != nil {
  100. return nil, err
  101. }
  102. // TODO(mxyng): use something less brittle
  103. matches, err := filepath.Glob(filepath.Join(manifests, "*", "*", "*", "*"))
  104. if err != nil {
  105. return nil, err
  106. }
  107. ms := make(map[model.Name]*Manifest)
  108. for _, match := range matches {
  109. fi, err := os.Stat(match)
  110. if err != nil {
  111. return nil, err
  112. }
  113. if !fi.IsDir() {
  114. rel, err := filepath.Rel(manifests, match)
  115. if err != nil {
  116. slog.Warn("bad filepath", "path", match, "error", err)
  117. continue
  118. }
  119. n := model.ParseNameFromFilepath(rel)
  120. if !n.IsValid() {
  121. slog.Warn("bad manifest name", "path", rel, "error", err)
  122. continue
  123. }
  124. m, err := ParseNamedManifest(n)
  125. if err != nil {
  126. slog.Warn("bad manifest", "name", n, "error", err)
  127. continue
  128. }
  129. ms[n] = m
  130. }
  131. }
  132. return ms, nil
  133. }