summaryrefslogtreecommitdiff
diff options
authorMichael Vogt <mvo@ubuntu.com>2016-03-01 11:48:07 +0100
committerMichael Vogt <mvo@ubuntu.com>2016-03-01 11:48:07 +0100
commitf0b389954245746f1dea4653636245f65f20e314 (patch)
treef2189a93e076499d0433091f802b2e1042018989
parentf1a2bb025bad4954b2a07d462ae1d28b277d8d55 (diff)
Generate desktop files from snap.yamlfeature/generate-desktop-file
If there is a app.Icon or app.Comment key then snappy will generate a desktop file for the app.
-rw-r--r--dirs/dirs.go2
-rw-r--r--snappy/click.go60
-rw-r--r--snappy/click_test.go65
-rw-r--r--snappy/snap_yaml.go5
4 files changed, 132 insertions, 0 deletions
diff --git a/dirs/dirs.go b/dirs/dirs.go
index 7c71e7d11d..7d92882c26 100644
--- a/dirs/dirs.go
+++ b/dirs/dirs.go
@@ -46,6 +46,7 @@ var (
SnapBinariesDir string
SnapServicesDir string
+ SnapDesktopDir string
SnapBusPolicyDir string
CloudMetaDataFile string
@@ -89,6 +90,7 @@ func SetRootDir(rootdir string) {
SnapTrustedAccountKey = filepath.Join(rootdir, "/usr/share/snappy/trusted.acckey")
SnapBinariesDir = filepath.Join(SnapSnapsDir, "bin")
+ SnapDesktopDir = filepath.Join(rootdir, snappyDir, "applications")
SnapServicesDir = filepath.Join(rootdir, "/etc/systemd/system")
SnapBusPolicyDir = filepath.Join(rootdir, "/etc/dbus-1/system.d")
diff --git a/snappy/click.go b/snappy/click.go
index 25d87a351f..1f1adf99d8 100644
--- a/snappy/click.go
+++ b/snappy/click.go
@@ -59,6 +59,12 @@ func generateBinaryName(m *snapYaml, app *AppYaml) string {
return filepath.Join(dirs.SnapBinariesDir, binName)
}
+func generateDesktopFileName(m *snapYaml, app *AppYaml) string {
+ binName := fmt.Sprintf("%s_%s.desktop", m.Name, filepath.Base(app.Name))
+
+ return filepath.Join(dirs.SnapDesktopDir, binName)
+}
+
func binPathForBinary(pkgPath string, app *AppYaml) string {
return filepath.Join(pkgPath, app.Command)
}
@@ -176,6 +182,47 @@ ubuntu-core-launcher {{.UdevAppName}} {{.AaProfile}} {{.Target}} "$@"
return templateOut.String(), nil
}
+func generateSnapDesktopFile(app *AppYaml, pkgPath string, m *snapYaml) (string, error) {
+ desktopTemplate := `[Desktop Entry]
+Encoding=UTF-8
+Type=Application
+Name={{.Name}}
+Comment={{.Comment}}
+Icon={{.Icon}}
+Exec={{.Exec}}{{if .Categories}}
+Categories={{range .Categories}}{{.}};{{end}}{{end}}
+`
+
+ // no desktop file needed
+ if app.Icon == "" && app.Comment == "" {
+ return "", nil
+ }
+
+ run, err := filepath.Rel(dirs.GlobalRootDir, generateBinaryName(m, app))
+ if err != nil {
+ return "", err
+ }
+
+ var templateOut bytes.Buffer
+ t := template.Must(template.New("desktop").Parse(desktopTemplate))
+ wrapperData := struct {
+ Name string
+ Comment string
+ Icon string
+ Exec string
+ Categories []string
+ }{
+ Name: app.Name,
+ Comment: app.Comment,
+ Icon: filepath.Join(pkgPath, app.Icon),
+ Exec: fmt.Sprintf("/%s", run),
+ Categories: app.Categories,
+ }
+
+ t.Execute(&templateOut, wrapperData)
+ return templateOut.String(), nil
+}
+
// FIXME: too much magic, just do explicit validation of the few
// fields we have
// verifyStructStringsAgainstWhitelist takes a struct and ensures that
@@ -468,6 +515,18 @@ func addPackageBinaries(m *snapYaml, baseDir string) error {
if err := helpers.AtomicWriteFile(generateBinaryName(m, app), []byte(content), 0755, 0); err != nil {
return err
}
+
+ // now generate a desktop file (if needed)
+ desktop, err := generateSnapDesktopFile(app, realBaseDir, m)
+ if err != nil {
+ return err
+ }
+ // only write if there is anything for us)
+ if desktop != "" {
+ if err := helpers.AtomicWriteFile(generateDesktopFileName(m, app), []byte(desktop), 0644, 0); err != nil {
+ return err
+ }
+ }
}
return nil
@@ -476,6 +535,7 @@ func addPackageBinaries(m *snapYaml, baseDir string) error {
func removePackageBinaries(m *snapYaml, baseDir string) error {
for _, app := range m.Apps {
os.Remove(generateBinaryName(m, app))
+ os.Remove(generateDesktopFileName(m, app))
}
return nil
diff --git a/snappy/click_test.go b/snappy/click_test.go
index 6f90f046c5..9358c9cc09 100644
--- a/snappy/click_test.go
+++ b/snappy/click_test.go
@@ -1202,3 +1202,68 @@ apps:
c.Assert(helpers.FileExists(binaryWrapper), Equals, false)
c.Assert(helpers.FileExists(snapDir), Equals, false)
}
+
+func (s *SnapTestSuite) TestSnappyGenerateSnapDesktopFileNotNeeded(c *C) {
+ app := &AppYaml{Name: "pastebinit", Command: "bin/pastebinit"}
+ pkgPath := "/snaps/pastebinit.mvo/1.4.0.0.1/"
+ m := &snapYaml{
+ Name: "pastebinit",
+ Version: "1.4.0.0.1",
+ }
+
+ generatedDesktopFile, err := generateSnapDesktopFile(app, pkgPath, m)
+ c.Assert(err, IsNil)
+ c.Assert(generatedDesktopFile, Equals, "")
+}
+
+func (s *SnapTestSuite) TestSnappyGenerateSnapDesktopFile(c *C) {
+ app := &AppYaml{
+ Name: "pastebinit",
+ Command: "bin/pastebinit",
+ Comment: "Best evar",
+ Icon: "something.png",
+ Categories: []string{"Game", "LogicGame"},
+ }
+ pkgPath := "/snaps/pastebinit.mvo/1.4.0.0.1/"
+ m := &snapYaml{
+ Name: "pastebinit",
+ Version: "1.4.0.0.1",
+ }
+
+ generatedDesktopFile, err := generateSnapDesktopFile(app, pkgPath, m)
+ c.Assert(err, IsNil)
+ c.Assert(generatedDesktopFile, Equals, `[Desktop Entry]
+Encoding=UTF-8
+Type=Application
+Name=pastebinit
+Comment=Best evar
+Icon=/snaps/pastebinit.mvo/1.4.0.0.1/something.png
+Exec=/snaps/bin/pastebinit.pastebinit
+Categories=Game;LogicGame;
+`)
+}
+
+func (s *SnapTestSuite) TestSnappyGenerateSnapDesktopFileNoCategories(c *C) {
+ app := &AppYaml{
+ Name: "pastebinit",
+ Command: "bin/pastebinit",
+ Comment: "Best evar",
+ Icon: "something.png",
+ Categories: nil,
+ }
+ pkgPath := "/snaps/pastebinit.mvo/1.4.0.0.1/"
+ m := &snapYaml{
+ Name: "pastebinit",
+ Version: "1.4.0.0.1",
+ }
+ generatedDesktopFile, err := generateSnapDesktopFile(app, pkgPath, m)
+ c.Assert(err, IsNil)
+ c.Assert(generatedDesktopFile, Equals, `[Desktop Entry]
+Encoding=UTF-8
+Type=Application
+Name=pastebinit
+Comment=Best evar
+Icon=/snaps/pastebinit.mvo/1.4.0.0.1/something.png
+Exec=/snaps/bin/pastebinit.pastebinit
+`)
+}
diff --git a/snappy/snap_yaml.go b/snappy/snap_yaml.go
index 41c46bbde6..e2b71a5107 100644
--- a/snappy/snap_yaml.go
+++ b/snappy/snap_yaml.go
@@ -63,6 +63,11 @@ type AppYaml struct {
Command string `yaml:"command"`
Daemon string `yaml:"daemon"`
+ // desktop file stuff
+ Icon string `yaml:"icon,omitempty"`
+ Comment string `yaml:"comment,omitempty"`
+ Categories []string `yaml:"categories,omitempty"`
+
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Stop string `yaml:"stop,omitempty"`
PostStop string `yaml:"poststop,omitempty"`