layer.go 2.27 KB
Newer Older
Michael Yang's avatar
Michael Yang committed
1
2
3
4
package server

import (
	"crypto/sha256"
5
	"errors"
Michael Yang's avatar
Michael Yang committed
6
7
8
9
10
11
12
13
14
15
	"fmt"
	"io"
	"os"
)

type Layer struct {
	MediaType string `json:"mediaType"`
	Digest    string `json:"digest"`
	Size      int64  `json:"size"`
	From      string `json:"from,omitempty"`
Michael Yang's avatar
Michael Yang committed
16
	status    string
Michael Yang's avatar
Michael Yang committed
17
18
}

19
func NewLayer(r io.Reader, mediatype string) (Layer, error) {
Michael Yang's avatar
Michael Yang committed
20
21
	blobs, err := GetBlobsPath("")
	if err != nil {
22
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
23
24
	}

Michael Yang's avatar
Michael Yang committed
25
	temp, err := os.CreateTemp(blobs, "sha256-")
Michael Yang's avatar
Michael Yang committed
26
	if err != nil {
27
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
28
29
	}
	defer temp.Close()
Michael Yang's avatar
Michael Yang committed
30
	defer os.Remove(temp.Name())
Michael Yang's avatar
Michael Yang committed
31
32
33
34

	sha256sum := sha256.New()
	n, err := io.Copy(io.MultiWriter(temp, sha256sum), r)
	if err != nil {
35
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
36
37
	}

Michael Yang's avatar
Michael Yang committed
38
	if err := temp.Close(); err != nil {
39
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
40
41
42
43
44
	}

	digest := fmt.Sprintf("sha256:%x", sha256sum.Sum(nil))
	blob, err := GetBlobsPath(digest)
	if err != nil {
45
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
46
47
48
49
50
51
	}

	status := "using existing layer"
	if _, err := os.Stat(blob); err != nil {
		status = "creating new layer"
		if err := os.Rename(temp.Name(), blob); err != nil {
52
			return Layer{}, err
Michael Yang's avatar
Michael Yang committed
53
54
55
		}
	}

56
	return Layer{
Michael Yang's avatar
Michael Yang committed
57
58
59
60
		MediaType: mediatype,
		Digest:    digest,
		Size:      n,
		status:    fmt.Sprintf("%s %s", status, digest),
Michael Yang's avatar
Michael Yang committed
61
62
63
	}, nil
}

64
func NewLayerFromLayer(digest, mediatype, from string) (Layer, error) {
65
	if digest == "" {
66
		return Layer{}, errors.New("creating new layer from layer with empty digest")
67
68
	}

Michael Yang's avatar
Michael Yang committed
69
70
	blob, err := GetBlobsPath(digest)
	if err != nil {
71
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
72
73
74
75
	}

	fi, err := os.Stat(blob)
	if err != nil {
76
		return Layer{}, err
Michael Yang's avatar
Michael Yang committed
77
78
	}

79
	return Layer{
Michael Yang's avatar
Michael Yang committed
80
81
82
83
		MediaType: mediatype,
		Digest:    digest,
		Size:      fi.Size(),
		From:      from,
Michael Yang's avatar
Michael Yang committed
84
		status:    fmt.Sprintf("using existing layer %s", digest),
Michael Yang's avatar
Michael Yang committed
85
86
87
	}, nil
}

88
func (l *Layer) Open() (io.ReadSeekCloser, error) {
89
90
91
92
	if l.Digest == "" {
		return nil, errors.New("opening layer with empty digest")
	}

Michael Yang's avatar
Michael Yang committed
93
94
	blob, err := GetBlobsPath(l.Digest)
	if err != nil {
Michael Yang's avatar
Michael Yang committed
95
		return nil, err
Michael Yang's avatar
Michael Yang committed
96
97
	}

Michael Yang's avatar
Michael Yang committed
98
	return os.Open(blob)
Michael Yang's avatar
Michael Yang committed
99
}
100
101

func (l *Layer) Remove() error {
102
103
104
105
	if l.Digest == "" {
		return nil
	}

106
107
108
109
110
111
	ms, err := Manifests()
	if err != nil {
		return err
	}

	for _, m := range ms {
112
		for _, layer := range append(m.Layers, m.Config) {
113
114
115
116
117
118
119
120
121
122
123
124
125
126
			if layer.Digest == l.Digest {
				// something is using this layer
				return nil
			}
		}
	}

	blob, err := GetBlobsPath(l.Digest)
	if err != nil {
		return err
	}

	return os.Remove(blob)
}