gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/snap/naming/snapref.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package naming 21 22 // A SnapRef references a snap by name and/or id. 23 type SnapRef interface { 24 SnapName() string 25 ID() string 26 } 27 28 // Snap references a snap by name only. 29 type Snap string 30 31 func (s Snap) SnapName() string { 32 return string(s) 33 } 34 35 func (s Snap) ID() string { 36 return "" 37 } 38 39 type snapRef struct { 40 name string 41 id string 42 } 43 44 // NewSnapRef returns a reference to the snap with given name and id. 45 func NewSnapRef(name, id string) SnapRef { 46 return &snapRef{name: name, id: id} 47 } 48 49 func (r *snapRef) SnapName() string { 50 return r.name 51 } 52 53 func (r *snapRef) ID() string { 54 return r.id 55 } 56 57 // SameSnap returns whether the two arguments refer to the same snap. 58 // If ids are not available for both it will fallback to names. 59 func SameSnap(snapRef1, snapRef2 SnapRef) bool { 60 id1 := snapRef1.ID() 61 id2 := snapRef2.ID() 62 if id1 != "" && id2 != "" { 63 return id1 == id2 64 } 65 return snapRef1.SnapName() == snapRef2.SnapName() 66 } 67 68 // SnapSet can hold a set of references to snaps. 69 type SnapSet struct { 70 byID map[string]SnapRef 71 byName map[string]SnapRef 72 73 n int 74 } 75 76 // NewSnapSet builds a snap set with the given references. 77 func NewSnapSet(refs []SnapRef) *SnapSet { 78 sz := len(refs) + 2 79 s := &SnapSet{ 80 byID: make(map[string]SnapRef, sz), 81 byName: make(map[string]SnapRef, sz), 82 } 83 for _, r := range refs { 84 s.Add(r) 85 } 86 return s 87 } 88 89 // Empty returns whether the snap set is empty. 90 func (s *SnapSet) Empty() bool { 91 return s.n == 0 92 } 93 94 // Size returns the number of snaps in the snap set. 95 func (s *SnapSet) Size() int { 96 return s.n 97 } 98 99 // Lookup finds the reference in the set matching the given one if any. 100 func (s *SnapSet) Lookup(which SnapRef) SnapRef { 101 whichID := which.ID() 102 name := which.SnapName() 103 if whichID != "" { 104 if ref := s.byID[whichID]; ref != nil { 105 return ref 106 } 107 } 108 ref := s.byName[name] 109 if ref == nil || (ref.ID() != "" && whichID != "") { 110 return nil 111 } 112 return ref 113 } 114 115 // Contains returns whether the set has a matching reference already. 116 func (s *SnapSet) Contains(ref SnapRef) bool { 117 return s.Lookup(ref) != nil 118 } 119 120 // Add adds one reference to the set. 121 // Already added ids or names will be ignored. The assumption is that 122 // a SnapSet is populated with distinct snaps. 123 func (s *SnapSet) Add(ref SnapRef) { 124 if s.Contains(ref) { 125 // nothing to do 126 return 127 } 128 inc := 0 129 if id := ref.ID(); id != "" { 130 s.byID[id] = ref 131 inc = 1 132 } 133 if name := ref.SnapName(); name != "" { 134 s.byName[name] = ref 135 inc = 1 136 } 137 s.n += inc 138 }