layers.go 1.9 KB

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