Skip to content

Commit

Permalink
Merge pull request canonical#6717 from zyga/fix/implicit-hooks-ifaces
Browse files Browse the repository at this point in the history
snap: fix interface bindings on implicit hooks
  • Loading branch information
zyga authored Apr 26, 2019
2 parents d33b032 + ae73876 commit a7dc812
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 93 deletions.
4 changes: 4 additions & 0 deletions snap/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ var (
func (info *Info) ForceRenamePlug(oldName, newName string) {
info.forceRenamePlug(oldName, newName)
}

func NewScopedTracker() *scopedTracker {
return new(scopedTracker)
}
17 changes: 8 additions & 9 deletions snap/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,6 @@ type Info struct {
Plugs map[string]*PlugInfo
Slots map[string]*SlotInfo

toplevelPlugs []*PlugInfo
toplevelSlots []*SlotInfo

// Plugs or slots with issues (they are not included in Plugs or Slots)
BadInterfaces map[string]string // slot or plug => message

Expand Down Expand Up @@ -931,8 +928,8 @@ func envFromMap(envMap *strutil.OrderedMap) []string {
return env
}

func infoFromSnapYamlWithSideInfo(meta []byte, si *SideInfo) (*Info, error) {
info, err := InfoFromSnapYaml(meta)
func infoFromSnapYamlWithSideInfo(meta []byte, si *SideInfo, strk *scopedTracker) (*Info, error) {
info, err := infoFromSnapYaml(meta, strk)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1004,7 +1001,8 @@ func ReadInfo(name string, si *SideInfo) (*Info, error) {
return nil, err
}

info, err := infoFromSnapYamlWithSideInfo(meta, si)
strk := new(scopedTracker)
info, err := infoFromSnapYamlWithSideInfo(meta, si, strk)
if err != nil {
return nil, &invalidMetaError{Snap: name, Revision: si.Revision, Msg: err.Error()}
}
Expand All @@ -1017,7 +1015,7 @@ func ReadInfo(name string, si *SideInfo) (*Info, error) {
return nil, &invalidMetaError{Snap: name, Revision: si.Revision, Msg: err.Error()}
}

bindImplicitHooks(info)
bindImplicitHooks(info, strk)

mountFile := MountFile(name, si.Revision)
st, err := os.Lstat(mountFile)
Expand Down Expand Up @@ -1065,7 +1063,8 @@ func ReadInfoFromSnapFile(snapf Container, si *SideInfo) (*Info, error) {
return nil, err
}

info, err := infoFromSnapYamlWithSideInfo(meta, si)
strk := new(scopedTracker)
info, err := infoFromSnapYamlWithSideInfo(meta, si, strk)
if err != nil {
return nil, err
}
Expand All @@ -1080,7 +1079,7 @@ func ReadInfoFromSnapFile(snapf Container, si *SideInfo) (*Info, error) {
return nil, err
}

bindImplicitHooks(info)
bindImplicitHooks(info, strk)

err = Validate(info)
if err != nil {
Expand Down
137 changes: 83 additions & 54 deletions snap/info_snap_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,38 @@ type socketsYaml struct {

// InfoFromSnapYaml creates a new info based on the given snap.yaml data
func InfoFromSnapYaml(yamlData []byte) (*Info, error) {
return infoFromSnapYaml(yamlData, new(scopedTracker))
}

// scopedTracker helps keeping track of which slots/plugs are scoped
// to apps and hooks.
type scopedTracker struct {
plugs map[*PlugInfo]bool
slots map[*SlotInfo]bool
}

func (strk *scopedTracker) init(sizeGuess int) {
strk.plugs = make(map[*PlugInfo]bool, sizeGuess)
strk.slots = make(map[*SlotInfo]bool, sizeGuess)
}

func (strk *scopedTracker) markPlug(plug *PlugInfo) {
strk.plugs[plug] = true
}

func (strk *scopedTracker) markSlot(slot *SlotInfo) {
strk.slots[slot] = true
}

func (strk *scopedTracker) plug(plug *PlugInfo) bool {
return strk.plugs[plug]
}

func (strk *scopedTracker) slot(slot *SlotInfo) bool {
return strk.slots[slot]
}

func infoFromSnapYaml(yamlData []byte, strk *scopedTracker) (*Info, error) {
var y snapYaml
// Customize hints for the typo detector.
y.TypoLayouts.Hint = `use singular "layout" instead of plural "layouts"`
Expand All @@ -145,28 +177,17 @@ func InfoFromSnapYaml(yamlData []byte) (*Info, error) {
return nil, err
}

// At this point snap.Plugs and snap.Slots only contain globally-declared
// plugs and slots, so copy them for later.
snap.toplevelPlugs = make([]*PlugInfo, 0, len(snap.Plugs))
snap.toplevelSlots = make([]*SlotInfo, 0, len(snap.Slots))
for _, plug := range snap.Plugs {
snap.toplevelPlugs = append(snap.toplevelPlugs, plug)
}
for _, slot := range snap.Slots {
snap.toplevelSlots = append(snap.toplevelSlots, slot)
}
strk.init(len(y.Apps) + len(y.Hooks))

// Collect all apps, their aliases and hooks
if err := setAppsFromSnapYaml(y, snap); err != nil {
if err := setAppsFromSnapYaml(y, snap, strk); err != nil {
return nil, err
}
setHooksFromSnapYaml(y, snap)

// Bind unbound plugs to all apps and hooks
bindUnboundPlugs(snap)
setHooksFromSnapYaml(y, snap, strk)

// Bind unbound slots to all apps and hooks
bindUnboundSlots(snap)
// Bind plugs and slots that are not scoped to all known apps and hooks.
bindUnscopedPlugs(snap, strk)
bindUnscopedSlots(snap, strk)

// Collect layout elements.
if y.Layout != nil {
Expand Down Expand Up @@ -309,7 +330,7 @@ func setSlotsFromSnapYaml(y snapYaml, snap *Info) error {
return nil
}

func setAppsFromSnapYaml(y snapYaml, snap *Info) error {
func setAppsFromSnapYaml(y snapYaml, snap *Info, strk *scopedTracker) error {
for appName, yApp := range y.Apps {
// Collect all apps
app := &AppInfo{
Expand Down Expand Up @@ -367,6 +388,8 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info) error {
}
snap.Plugs[plugName] = plug
}
// Mark the plug as scoped.
strk.markPlug(plug)
app.Plugs[plugName] = plug
plug.Apps[appName] = app
}
Expand All @@ -381,6 +404,8 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info) error {
}
snap.Slots[slotName] = slot
}
// Mark the slot as scoped.
strk.markSlot(slot)
app.Slots[slotName] = slot
slot.Apps[appName] = app
}
Expand All @@ -406,7 +431,7 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info) error {
return nil
}

func setHooksFromSnapYaml(y snapYaml, snap *Info) {
func setHooksFromSnapYaml(y snapYaml, snap *Info, strk *scopedTracker) {
for hookName, yHook := range y.Hooks {
if !IsHookSupported(hookName) {
continue
Expand Down Expand Up @@ -440,7 +465,10 @@ func setHooksFromSnapYaml(y snapYaml, snap *Info) {
Hooks: make(map[string]*HookInfo),
}
snap.Plugs[plugName] = plug
} else if plug.Hooks == nil {
}
// Mark the plug as scoped.
strk.markPlug(plug)
if plug.Hooks == nil {
plug.Hooks = make(map[string]*HookInfo)
}
hook.Plugs[plugName] = plug
Expand All @@ -457,7 +485,10 @@ func setHooksFromSnapYaml(y snapYaml, snap *Info) {
Hooks: make(map[string]*HookInfo),
}
snap.Slots[slotName] = slot
} else if slot.Hooks == nil {
}
// Mark the slot as scoped.
strk.markSlot(slot)
if slot.Hooks == nil {
slot.Hooks = make(map[string]*HookInfo)
}
hook.Slots[slotName] = slot
Expand All @@ -466,46 +497,47 @@ func setHooksFromSnapYaml(y snapYaml, snap *Info) {
}
}

func bindUnboundPlugs(snap *Info) {
func bindUnscopedPlugs(snap *Info, strk *scopedTracker) {
for plugName, plug := range snap.Plugs {
// A plug is considered unbound if it isn't being used by any apps
// or hooks. In which case we bind them to all apps and hooks.
if len(plug.Apps) == 0 && len(plug.Hooks) == 0 {
for appName, app := range snap.Apps {
app.Plugs[plugName] = plug
plug.Apps[appName] = app
}
if strk.plug(plug) {
continue
}
for appName, app := range snap.Apps {
app.Plugs[plugName] = plug
plug.Apps[appName] = app
}

for hookName, hook := range snap.Hooks {
hook.Plugs[plugName] = plug
plug.Hooks[hookName] = hook
}
for hookName, hook := range snap.Hooks {
hook.Plugs[plugName] = plug
plug.Hooks[hookName] = hook
}
}
}

func bindUnboundSlots(snap *Info) {
func bindUnscopedSlots(snap *Info, strk *scopedTracker) {
for slotName, slot := range snap.Slots {
// A slot is considered unbound if it isn't being used by any apps
// or hooks. In which case we bind them to all apps and hooks.
if len(slot.Apps) == 0 && len(slot.Hooks) == 0 {
for appName, app := range snap.Apps {
app.Slots[slotName] = slot
slot.Apps[appName] = app
}
for hookName, hook := range snap.Hooks {
hook.Slots[slotName] = slot
slot.Hooks[hookName] = hook
}
if strk.slot(slot) {
continue
}
for appName, app := range snap.Apps {
app.Slots[slotName] = slot
slot.Apps[appName] = app
}
for hookName, hook := range snap.Hooks {
hook.Slots[slotName] = slot
slot.Hooks[hookName] = hook
}
}
}

// bindImplicitHooks binds all global plugs and slots to implicit hooks
func bindImplicitHooks(snap *Info) {
for _, plug := range snap.toplevelPlugs {
for hookName, hook := range snap.Hooks {
if hook.Explicit {
func bindImplicitHooks(snap *Info, strk *scopedTracker) {
for hookName, hook := range snap.Hooks {
if hook.Explicit {
continue
}
for _, plug := range snap.Plugs {
if strk.plug(plug) {
continue
}
if hook.Plugs == nil {
Expand All @@ -517,11 +549,8 @@ func bindImplicitHooks(snap *Info) {
}
plug.Hooks[hookName] = hook
}
}

for _, slot := range snap.toplevelSlots {
for hookName, hook := range snap.Hooks {
if hook.Explicit {
for _, slot := range snap.Slots {
if strk.slot(slot) {
continue
}
if hook.Slots == nil {
Expand Down
Loading

0 comments on commit a7dc812

Please sign in to comment.