File: manager.go

package info (click to toggle)
docker-buildx 0.19.3%2Bds1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,852 kB
  • sloc: sh: 318; makefile: 73
file content (143 lines) | stat: -rw-r--r-- 3,600 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package driver

import (
	"context"
	"sort"
	"sync"

	"github.com/docker/cli/cli/context/store"
	dockerclient "github.com/docker/docker/client"
	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/util/tracing/delegated"
	specs "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

type Factory interface {
	Name() string
	Usage() string
	Priority(ctx context.Context, endpoint string, api dockerclient.APIClient, dialMeta map[string][]string) int
	New(ctx context.Context, cfg InitConfig) (Driver, error)
	AllowsInstances() bool
}

type BuildkitConfig struct {
	// Entitlements []string
	// Rootless bool
}

type InitConfig struct {
	Name            string
	EndpointAddr    string
	DockerAPI       dockerclient.APIClient
	ContextStore    store.Reader
	BuildkitdFlags  []string
	Files           map[string][]byte
	DriverOpts      map[string]string
	Auth            Auth
	Platforms       []specs.Platform
	ContextPathHash string
	DialMeta        map[string][]string
}

var drivers map[string]Factory

func Register(f Factory) {
	if drivers == nil {
		drivers = map[string]Factory{}
	}
	drivers[f.Name()] = f
}

func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient, instanceRequired bool, dialMeta map[string][]string) (Factory, error) {
	if len(drivers) == 0 {
		return nil, errors.Errorf("no drivers available")
	}
	type p struct {
		f        Factory
		priority int
	}
	dd := make([]p, 0, len(drivers))
	for _, f := range drivers {
		if instanceRequired && !f.AllowsInstances() {
			continue
		}
		dd = append(dd, p{f: f, priority: f.Priority(ctx, ep, c, dialMeta)})
	}
	sort.Slice(dd, func(i, j int) bool {
		return dd[i].priority < dd[j].priority
	})
	return dd[0].f, nil
}

func GetFactory(name string, instanceRequired bool) (Factory, error) {
	for _, f := range drivers {
		if f.Name() == name {
			if instanceRequired && !f.AllowsInstances() {
				return nil, errors.Errorf("additional instances of driver %q cannot be created", name)
			}
			return f, nil
		}
	}
	return nil, errors.Errorf("failed to find driver %q", name)
}

func GetDriver(ctx context.Context, f Factory, cfg InitConfig) (*DriverHandle, error) {
	if f == nil {
		var err error
		f, err = GetDefaultFactory(ctx, cfg.EndpointAddr, cfg.DockerAPI, false, cfg.DialMeta)
		if err != nil {
			return nil, err
		}
	}
	d, err := f.New(ctx, cfg)
	if err != nil {
		return nil, err
	}
	return &DriverHandle{Driver: d}, nil
}

func GetFactories(instanceRequired bool) []Factory {
	ds := make([]Factory, 0, len(drivers))
	for _, d := range drivers {
		if instanceRequired && !d.AllowsInstances() {
			continue
		}
		ds = append(ds, d)
	}
	sort.Slice(ds, func(i, j int) bool {
		return ds[i].Name() < ds[j].Name()
	})
	return ds
}

type DriverHandle struct {
	Driver
	client                  *client.Client
	err                     error
	once                    sync.Once
	historyAPISupportedOnce sync.Once
	historyAPISupported     bool
}

func (d *DriverHandle) Client(ctx context.Context, opt ...client.ClientOpt) (*client.Client, error) {
	d.once.Do(func() {
		d.client, d.err = d.Driver.Client(ctx, append(d.getClientOptions(), opt...)...)
	})
	return d.client, d.err
}

func (d *DriverHandle) getClientOptions() []client.ClientOpt {
	return []client.ClientOpt{
		client.WithTracerDelegate(delegated.DefaultExporter),
	}
}

func (d *DriverHandle) HistoryAPISupported(ctx context.Context) bool {
	d.historyAPISupportedOnce.Do(func() {
		if c, err := d.Client(ctx); err == nil {
			d.historyAPISupported = historyAPISupported(ctx, c)
		}
	})
	return d.historyAPISupported
}