deduplicate.go 2.76 KB
Newer Older
songlinfeng's avatar
songlinfeng committed
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
/**
# Copyright (c) 2024, HCUOpt CORPORATION.  All rights reserved.
**/

package transform

import (
	"tags.cncf.io/container-device-interface/specs-go"
)

type dedupe struct{}

var _ Transformer = (*dedupe)(nil)

// NewDedupe creates a transformer that deduplicates container edits.
func NewDedupe() (Transformer, error) {
	return &dedupe{}, nil
}

// Transform removes duplicate entris from devices and common container edits.
func (d dedupe) Transform(spec *specs.Spec) error {
	if spec == nil {
		return nil
	}
	if err := d.transformEdits(&spec.ContainerEdits); err != nil {
		return err
	}
	var updatedDevices []specs.Device
	for _, device := range spec.Devices {
		device := device
		if err := d.transformEdits(&device.ContainerEdits); err != nil {
			return err
		}
		updatedDevices = append(updatedDevices, device)
	}
	spec.Devices = updatedDevices
	return nil
}

func (d dedupe) transformEdits(edits *specs.ContainerEdits) error {
	deviceNodes, err := d.deduplicateDeviceNodes(edits.DeviceNodes)
	if err != nil {
		return err
	}
	edits.DeviceNodes = deviceNodes

	envs, err := d.deduplicateEnvs(edits.Env)
	if err != nil {
		return err
	}
	edits.Env = envs

	hooks, err := d.deduplicateHooks(edits.Hooks)
	if err != nil {
		return err
	}
	edits.Hooks = hooks

	mounts, err := d.deduplicateMounts(edits.Mounts)
	if err != nil {
		return err
	}
	edits.Mounts = mounts

	return nil
}

func (d dedupe) deduplicateDeviceNodes(entities []*specs.DeviceNode) ([]*specs.DeviceNode, error) {
	seen := make(map[string]bool)
	var deviceNodes []*specs.DeviceNode
	for _, e := range entities {
		if e == nil {
			continue
		}
		id, err := deviceNode(*e).id()
		if err != nil {
			return nil, err
		}
		if seen[id] {
			continue
		}
		seen[id] = true
		deviceNodes = append(deviceNodes, e)
	}
	return deviceNodes, nil
}

func (d dedupe) deduplicateEnvs(entities []string) ([]string, error) {
	seen := make(map[string]bool)
	var envs []string
	for _, e := range entities {
		id := e
		if seen[id] {
			continue
		}
		seen[id] = true
		envs = append(envs, e)
	}
	return envs, nil
}

func (d dedupe) deduplicateHooks(entities []*specs.Hook) ([]*specs.Hook, error) {
	seen := make(map[string]bool)
	var hooks []*specs.Hook
	for _, e := range entities {
		if e == nil {
			continue
		}
		id, err := hook(*e).id()
		if err != nil {
			return nil, err
		}
		if seen[id] {
			continue
		}
		seen[id] = true
		hooks = append(hooks, e)
	}
	return hooks, nil
}

func (d dedupe) deduplicateMounts(entities []*specs.Mount) ([]*specs.Mount, error) {
	seen := make(map[string]bool)
	var mounts []*specs.Mount
	for _, e := range entities {
		if e == nil {
			continue
		}
		id, err := mount(*e).id()
		if err != nil {
			return nil, err
		}
		if seen[id] {
			continue
		}
		seen[id] = true
		mounts = append(mounts, e)
	}
	return mounts, nil
}