github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/client/clientutil/snapinfo.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018-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 clientutil offers utilities to turn snap.Info and related 21 // structs into client structs and to work with the latter. 22 package clientutil 23 24 import ( 25 "sort" 26 "strings" 27 28 "github.com/snapcore/snapd/client" 29 "github.com/snapcore/snapd/osutil" 30 "github.com/snapcore/snapd/snap" 31 ) 32 33 // A StatusDecorator is able to decorate client.AppInfos with service status. 34 type StatusDecorator interface { 35 DecorateWithStatus(appInfo *client.AppInfo, snapApp *snap.AppInfo) error 36 } 37 38 // ClientSnapFromSnapInfo returns a client.Snap derived from snap.Info. 39 // If an optional StatusDecorator is provided it will be used to 40 // add service status information. 41 func ClientSnapFromSnapInfo(snapInfo *snap.Info, decorator StatusDecorator) (*client.Snap, error) { 42 var publisher *snap.StoreAccount 43 if snapInfo.Publisher.Username != "" { 44 publisher = &snapInfo.Publisher 45 } 46 47 confinement := snapInfo.Confinement 48 if confinement == "" { 49 confinement = snap.StrictConfinement 50 } 51 52 snapapps := make([]*snap.AppInfo, 0, len(snapInfo.Apps)) 53 for _, app := range snapInfo.Apps { 54 snapapps = append(snapapps, app) 55 } 56 sort.Sort(snap.AppInfoBySnapApp(snapapps)) 57 58 apps, err := ClientAppInfosFromSnapAppInfos(snapapps, decorator) 59 result := &client.Snap{ 60 Description: snapInfo.Description(), 61 Developer: snapInfo.Publisher.Username, 62 Publisher: publisher, 63 Icon: snapInfo.Media.IconURL(), 64 ID: snapInfo.ID(), 65 InstallDate: snapInfo.InstallDate(), 66 Name: snapInfo.InstanceName(), 67 Revision: snapInfo.Revision, 68 Summary: snapInfo.Summary(), 69 Type: string(snapInfo.Type()), 70 Base: snapInfo.Base, 71 Version: snapInfo.Version, 72 Channel: snapInfo.Channel, 73 Private: snapInfo.Private, 74 Confinement: string(confinement), 75 Apps: apps, 76 Broken: snapInfo.Broken, 77 Contact: snapInfo.Contact, 78 Title: snapInfo.Title(), 79 License: snapInfo.License, 80 Media: snapInfo.Media, 81 Prices: snapInfo.Prices, 82 Channels: snapInfo.Channels, 83 Tracks: snapInfo.Tracks, 84 CommonIDs: snapInfo.CommonIDs, 85 Website: snapInfo.Website, 86 StoreURL: snapInfo.StoreURL, 87 } 88 89 return result, err 90 } 91 92 func ClientAppInfoNotes(app *client.AppInfo) string { 93 if !app.IsService() { 94 return "-" 95 } 96 97 var notes = make([]string, 0, 2) 98 var seenTimer, seenSocket bool 99 for _, act := range app.Activators { 100 switch act.Type { 101 case "timer": 102 seenTimer = true 103 case "socket": 104 seenSocket = true 105 } 106 } 107 if seenTimer { 108 notes = append(notes, "timer-activated") 109 } 110 if seenSocket { 111 notes = append(notes, "socket-activated") 112 } 113 if len(notes) == 0 { 114 return "-" 115 } 116 return strings.Join(notes, ",") 117 } 118 119 // ClientAppInfosFromSnapAppInfos returns client.AppInfos derived from 120 // the given snap.AppInfos. 121 // If an optional StatusDecorator is provided it will be used to add 122 // service status information as well, this will be done only if the 123 // snap is active and when the app is a service. 124 func ClientAppInfosFromSnapAppInfos(apps []*snap.AppInfo, decorator StatusDecorator) ([]client.AppInfo, error) { 125 out := make([]client.AppInfo, 0, len(apps)) 126 for _, app := range apps { 127 appInfo := client.AppInfo{ 128 Snap: app.Snap.InstanceName(), 129 Name: app.Name, 130 CommonID: app.CommonID, 131 } 132 if fn := app.DesktopFile(); osutil.FileExists(fn) { 133 appInfo.DesktopFile = fn 134 } 135 136 appInfo.Daemon = app.Daemon 137 if !app.IsService() || decorator == nil || !app.Snap.IsActive() { 138 out = append(out, appInfo) 139 continue 140 } 141 142 if err := decorator.DecorateWithStatus(&appInfo, app); err != nil { 143 return nil, err 144 } 145 out = append(out, appInfo) 146 } 147 148 return out, nil 149 }