github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/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, 4) 98 if app.DaemonScope == snap.UserDaemon { 99 notes = append(notes, "user") 100 } 101 var seenTimer, seenSocket, seenDbus bool 102 for _, act := range app.Activators { 103 switch act.Type { 104 case "timer": 105 seenTimer = true 106 case "socket": 107 seenSocket = true 108 case "dbus": 109 seenDbus = true 110 } 111 } 112 if seenTimer { 113 notes = append(notes, "timer-activated") 114 } 115 if seenSocket { 116 notes = append(notes, "socket-activated") 117 } 118 if seenDbus { 119 notes = append(notes, "dbus-activated") 120 } 121 if len(notes) == 0 { 122 return "-" 123 } 124 return strings.Join(notes, ",") 125 } 126 127 // ClientAppInfosFromSnapAppInfos returns client.AppInfos derived from 128 // the given snap.AppInfos. 129 // If an optional StatusDecorator is provided it will be used to add 130 // service status information as well, this will be done only if the 131 // snap is active and when the app is a service. 132 func ClientAppInfosFromSnapAppInfos(apps []*snap.AppInfo, decorator StatusDecorator) ([]client.AppInfo, error) { 133 out := make([]client.AppInfo, 0, len(apps)) 134 for _, app := range apps { 135 appInfo := client.AppInfo{ 136 Snap: app.Snap.InstanceName(), 137 Name: app.Name, 138 CommonID: app.CommonID, 139 } 140 if fn := app.DesktopFile(); osutil.FileExists(fn) { 141 appInfo.DesktopFile = fn 142 } 143 144 appInfo.Daemon = app.Daemon 145 appInfo.DaemonScope = app.DaemonScope 146 if !app.IsService() || decorator == nil || !app.Snap.IsActive() { 147 out = append(out, appInfo) 148 continue 149 } 150 151 if err := decorator.DecorateWithStatus(&appInfo, app); err != nil { 152 return nil, err 153 } 154 out = append(out, appInfo) 155 } 156 157 return out, nil 158 }