github.com/rigado/snapd@v2.42.5-go-mod+incompatible/wrappers/icons.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 wrappers 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "strings" 28 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/osutil" 31 "github.com/snapcore/snapd/snap" 32 ) 33 34 func findIconFiles(snapName string, rootDir string) (icons []string, err error) { 35 if !osutil.IsDirectory(rootDir) { 36 return nil, nil 37 } 38 iconGlob := fmt.Sprintf("snap.%s.*", snapName) 39 forbiddenDirGlob := "snap.*" 40 err = filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { 41 if err != nil { 42 return err 43 } 44 rel, err := filepath.Rel(rootDir, path) 45 if err != nil { 46 return err 47 } 48 base := filepath.Base(path) 49 if info.IsDir() { 50 // Ignore directories that could match an icon glob 51 if ok, err := filepath.Match(forbiddenDirGlob, base); ok || err != nil { 52 return filepath.SkipDir 53 } 54 } else { 55 if ok, err := filepath.Match(iconGlob, base); err != nil { 56 return err 57 } else if ok { 58 ext := filepath.Ext(base) 59 if ext == ".png" || ext == ".svg" { 60 icons = append(icons, rel) 61 } 62 } 63 } 64 return nil 65 }) 66 return icons, err 67 } 68 69 func deriveIconContent(instanceName string, rootDir string, icons []string) (content map[string]map[string]*osutil.FileState, err error) { 70 content = make(map[string]map[string]*osutil.FileState) 71 snapPrefix := fmt.Sprintf("snap.%s.", snap.InstanceSnap(instanceName)) 72 instancePrefix := fmt.Sprintf("snap.%s.", instanceName) 73 74 for _, iconFile := range icons { 75 dir := filepath.Dir(iconFile) 76 base := filepath.Base(iconFile) 77 dirContent := content[dir] 78 if dirContent == nil { 79 dirContent = make(map[string]*osutil.FileState) 80 content[dir] = dirContent 81 } 82 data, err := ioutil.ReadFile(filepath.Join(rootDir, iconFile)) 83 if err != nil { 84 return nil, err 85 } 86 if !strings.HasPrefix(base, snapPrefix) { 87 return nil, fmt.Errorf("cannot use icon file %q: must start with snap prefix %q", iconFile, snapPrefix) 88 } 89 // rename icons to match snap instance name 90 base = instancePrefix + base[len(snapPrefix):] 91 dirContent[base] = &osutil.FileState{ 92 Content: data, 93 Mode: 0644, 94 } 95 } 96 return content, nil 97 } 98 99 func AddSnapIcons(s *snap.Info) error { 100 if err := os.MkdirAll(dirs.SnapDesktopIconsDir, 0755); err != nil { 101 return err 102 } 103 104 rootDir := filepath.Join(s.MountDir(), "meta", "gui", "icons") 105 icons, err := findIconFiles(s.SnapName(), rootDir) 106 if err != nil { 107 return err 108 } 109 110 content, err := deriveIconContent(s.InstanceName(), rootDir, icons) 111 if err != nil { 112 return err 113 } 114 iconGlob := fmt.Sprintf("snap.%s.*", s.InstanceName()) 115 _, _, err = osutil.EnsureTreeState(dirs.SnapDesktopIconsDir, []string{iconGlob}, content) 116 return err 117 } 118 119 func RemoveSnapIcons(s *snap.Info) error { 120 if !osutil.IsDirectory(dirs.SnapDesktopIconsDir) { 121 return nil 122 } 123 iconGlob := fmt.Sprintf("snap.%s.*", s.InstanceName()) 124 _, _, err := osutil.EnsureTreeState(dirs.SnapDesktopIconsDir, []string{iconGlob}, nil) 125 return err 126 }