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

import (
	"crypto/sha256"
xuxzh1's avatar
init  
xuxzh1 committed
5
	"errors"
mashun1's avatar
v1  
mashun1 committed
6
7
8
9
10
11
12
13
14
15
16
17
18
	"fmt"
	"io"
	"os"
)

type Layer struct {
	MediaType string `json:"mediaType"`
	Digest    string `json:"digest"`
	Size      int64  `json:"size"`
	From      string `json:"from,omitempty"`
	status    string
}

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

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

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

	if err := temp.Close(); err != nil {
xuxzh1's avatar
init  
xuxzh1 committed
39
		return Layer{}, err
mashun1's avatar
v1  
mashun1 committed
40
41
42
43
44
	}

	digest := fmt.Sprintf("sha256:%x", sha256sum.Sum(nil))
	blob, err := GetBlobsPath(digest)
	if err != nil {
xuxzh1's avatar
init  
xuxzh1 committed
45
		return Layer{}, err
mashun1's avatar
v1  
mashun1 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 {
xuxzh1's avatar
init  
xuxzh1 committed
52
			return Layer{}, err
mashun1's avatar
v1  
mashun1 committed
53
54
55
		}
	}

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

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

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

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

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

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

mashun1's avatar
v1  
mashun1 committed
93
94
95
96
97
98
99
100
101
	blob, err := GetBlobsPath(l.Digest)
	if err != nil {
		return nil, err
	}

	return os.Open(blob)
}

func (l *Layer) Remove() error {
xuxzh1's avatar
init  
xuxzh1 committed
102
103
104
105
	if l.Digest == "" {
		return nil
	}

mashun1's avatar
v1  
mashun1 committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
	ms, err := Manifests()
	if err != nil {
		return err
	}

	for _, m := range ms {
		for _, layer := range append(m.Layers, m.Config) {
			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)
}