layers.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package server
  2. import (
  3. "crypto/sha256"
  4. "fmt"
  5. "io"
  6. "os"
  7. "strings"
  8. "golang.org/x/exp/slices"
  9. )
  10. type Layers struct {
  11. items []*Layer
  12. }
  13. func (ls *Layers) Add(layer *Layer) {
  14. if layer.Size > 0 {
  15. ls.items = append(ls.items, layer)
  16. }
  17. }
  18. func (ls *Layers) Replace(layer *Layer) {
  19. if layer.Size > 0 {
  20. mediatype := layer.MediaType
  21. layers := slices.DeleteFunc(ls.items, func(l *Layer) bool {
  22. return l.MediaType == mediatype
  23. })
  24. ls.items = append(layers, layer)
  25. }
  26. }
  27. type Layer struct {
  28. MediaType string `json:"mediaType"`
  29. Digest string `json:"digest"`
  30. Size int64 `json:"size"`
  31. From string `json:"from,omitempty"`
  32. tempFileName string
  33. }
  34. func NewLayer(r io.Reader, mediatype string) (*Layer, error) {
  35. blobs, err := GetBlobsPath("")
  36. if err != nil {
  37. return nil, err
  38. }
  39. const delimiter = "-"
  40. pattern := strings.Join([]string{"sha256", "*-partial"}, delimiter)
  41. temp, err := os.CreateTemp(blobs, pattern)
  42. if err != nil {
  43. return nil, err
  44. }
  45. defer temp.Close()
  46. sha256sum := sha256.New()
  47. n, err := io.Copy(io.MultiWriter(temp, sha256sum), r)
  48. if err != nil {
  49. return nil, err
  50. }
  51. return &Layer{
  52. MediaType: mediatype,
  53. Digest: fmt.Sprintf("sha256:%x", sha256sum.Sum(nil)),
  54. Size: n,
  55. tempFileName: temp.Name(),
  56. }, nil
  57. }
  58. func NewLayerFromLayer(digest, mediatype, from string) (*Layer, error) {
  59. blob, err := GetBlobsPath(digest)
  60. if err != nil {
  61. return nil, err
  62. }
  63. fi, err := os.Stat(blob)
  64. if err != nil {
  65. return nil, err
  66. }
  67. return &Layer{
  68. MediaType: mediatype,
  69. Digest: digest,
  70. Size: fi.Size(),
  71. From: from,
  72. }, nil
  73. }
  74. func (l *Layer) Commit() (bool, error) {
  75. // always remove temp
  76. defer os.Remove(l.tempFileName)
  77. blob, err := GetBlobsPath(l.Digest)
  78. if err != nil {
  79. return false, err
  80. }
  81. if _, err := os.Stat(blob); err != nil {
  82. return true, os.Rename(l.tempFileName, blob)
  83. }
  84. return false, nil
  85. }