manifest.go 2.8 KB

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