layer.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package server
  2. import (
  3. "crypto/sha256"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "os"
  8. )
  9. type Layer struct {
  10. MediaType string `json:"mediaType"`
  11. Digest string `json:"digest"`
  12. Size int64 `json:"size"`
  13. From string `json:"from,omitempty"`
  14. status string
  15. }
  16. func NewLayer(r io.Reader, mediatype string) (*Layer, error) {
  17. blobs, err := GetBlobsPath("")
  18. if err != nil {
  19. return nil, err
  20. }
  21. temp, err := os.CreateTemp(blobs, "sha256-")
  22. if err != nil {
  23. return nil, err
  24. }
  25. defer temp.Close()
  26. defer os.Remove(temp.Name())
  27. sha256sum := sha256.New()
  28. n, err := io.Copy(io.MultiWriter(temp, sha256sum), r)
  29. if err != nil {
  30. return nil, err
  31. }
  32. if err := temp.Close(); err != nil {
  33. return nil, err
  34. }
  35. digest := fmt.Sprintf("sha256:%x", sha256sum.Sum(nil))
  36. blob, err := GetBlobsPath(digest)
  37. if err != nil {
  38. return nil, err
  39. }
  40. status := "using existing layer"
  41. if _, err := os.Stat(blob); err != nil {
  42. status = "creating new layer"
  43. if err := os.Rename(temp.Name(), blob); err != nil {
  44. return nil, err
  45. }
  46. }
  47. return &Layer{
  48. MediaType: mediatype,
  49. Digest: digest,
  50. Size: n,
  51. status: fmt.Sprintf("%s %s", status, digest),
  52. }, nil
  53. }
  54. func NewLayerFromLayer(digest, mediatype, from string) (*Layer, error) {
  55. if digest == "" {
  56. return nil, errors.New("creating new layer from layer with empty digest")
  57. }
  58. blob, err := GetBlobsPath(digest)
  59. if err != nil {
  60. return nil, err
  61. }
  62. fi, err := os.Stat(blob)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return &Layer{
  67. MediaType: mediatype,
  68. Digest: digest,
  69. Size: fi.Size(),
  70. From: from,
  71. status: fmt.Sprintf("using existing layer %s", digest),
  72. }, nil
  73. }
  74. func (l *Layer) Open() (io.ReadSeekCloser, error) {
  75. if l.Digest == "" {
  76. return nil, errors.New("opening layer with empty digest")
  77. }
  78. blob, err := GetBlobsPath(l.Digest)
  79. if err != nil {
  80. return nil, err
  81. }
  82. return os.Open(blob)
  83. }
  84. func (l *Layer) Remove() error {
  85. if l.Digest == "" {
  86. return nil
  87. }
  88. ms, err := Manifests()
  89. if err != nil {
  90. return err
  91. }
  92. for _, m := range ms {
  93. for _, layer := range append(m.Layers, &m.Config) {
  94. if layer.Digest == l.Digest {
  95. // something is using this layer
  96. return nil
  97. }
  98. }
  99. }
  100. blob, err := GetBlobsPath(l.Digest)
  101. if err != nil {
  102. return err
  103. }
  104. return os.Remove(blob)
  105. }