github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/osutils/shortcut/shortcut_linux.go (about) 1 package shortcut 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 8 "github.com/ActiveState/cli/internal/errs" 9 "github.com/ActiveState/cli/internal/fileutils" 10 "github.com/ActiveState/cli/internal/logging" 11 "github.com/ActiveState/cli/internal/multilog" 12 "github.com/ActiveState/cli/internal/osutils" 13 "github.com/ActiveState/cli/internal/rollbar" 14 "github.com/ActiveState/cli/internal/strutils" 15 ) 16 17 type SaveOpts struct { 18 Name string 19 GenericName string 20 Comment string 21 Keywords string 22 IconData []byte 23 IconPath string 24 } 25 26 func Save(target, path string, args []string, opts SaveOpts) (file string, err error) { 27 if !fileutils.FileExists(target) { 28 return "", errs.New("Target does not exist") 29 } 30 31 iconName := filepath.Base(opts.IconPath) 32 iconName = strings.TrimSuffix(iconName, filepath.Ext(iconName)) 33 34 name := opts.Name 35 if name == "" { 36 name = filepath.Base(path) 37 } 38 39 exec := []string{target} 40 exec = append(exec, args...) 41 42 data := desktopFileData{ 43 Name: name, 44 GenericName: opts.GenericName, 45 Comment: opts.Comment, 46 Exec: strings.Join(exec, " "), 47 Keywords: opts.Keywords, 48 IconName: iconName, 49 } 50 desktopFile, err := strutils.ParseTemplate(desktopFileTmpl, data, nil) 51 if err != nil { 52 return "", errs.Wrap(err, "Could not execute template") 53 } 54 55 if err := fileutils.WriteFile(opts.IconPath, opts.IconData); err != nil { 56 return "", errs.Wrap(err, "Could not write icon file") 57 } 58 59 if err := fileutils.WriteFile(path, []byte(desktopFile)); err != nil { 60 return "", errs.Wrap(err, "Could not write desktop file") 61 } 62 63 f, err := os.Open(path) 64 if err != nil { 65 return "", errs.Wrap(err, "Could not open desktop file") 66 } 67 err = f.Chmod(0770) 68 f.Close() 69 if err != nil { 70 return "", errs.Wrap(err, "Could not make file executable") 71 } 72 73 // set the executable as trusted so users do not need to do it manually 74 // gio is "Gnome input/output" 75 stdoutText, stderrText, err := osutils.ExecSimple("gio", []string{"set", path, "metadata::trusted", "true"}, []string{}) 76 if err != nil { 77 multilog.Log(logging.ErrorNoStacktrace, rollbar.Error)("Could not set desktop file as trusted: %v (stdout: %s; stderr: %s)", errs.JoinMessage(err), stdoutText, stderrText) 78 } 79 80 return path, nil 81 } 82 83 type desktopFileData struct { 84 Name string 85 GenericName string 86 Comment string 87 Exec string 88 Keywords string 89 IconName string 90 } 91 92 var desktopFileTmpl = strings.TrimPrefix(` 93 [Desktop Entry] 94 Name={{ .Name }} 95 GenericName={{ .GenericName }} 96 Type=Application 97 Comment={{ .Comment }} 98 Exec="{{ .Exec }}" 99 Terminal=false 100 Keywords={{ .Keywords }} 101 Categories=Utility;Development; 102 Hidden=false 103 NoDisplay=false 104 StartupNotify=false 105 Icon={{ .IconName }} 106 Name[en_US]={{ .Name }} 107 `, "\n")