Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/snap: gnome-software install via snap:// handler #5346

Merged
merged 12 commits into from
Oct 23, 2018

Conversation

jhenstridge
Copy link
Contributor

We would like snap:// links in the web browser to work on any system that has snapd installed. At present, these are handled by GNOME Software, provided that it has been built with the snap plugin.

This PR attempts to fill the gap for all other desktop systems with snapd installed as follows:

  1. install a .desktop file that advertises support for the mime type x-scheme-handler/snap, and calls snap snap-uri-handler %U.

  2. Add a snap-uri-handler command to the snap executable that does the following:

    • Check to see whether the gnome-software snap is installed.
    • If not, prompt the user to install it via a Zenity dialog (similar to that used by our xdg-open/xdg-mime proxies).
    • Run the snapped gnome-software with the URI as an argument.

The gnome-software snap is maintained by the Ubuntu Desktop team, and we plan for this to be the primary way of delivering the app to Ubuntu desktops going forward. When run on non-Ubuntu systems, we plan to limit it to only showing results from the Snap store, so it doesn't duplicate results from the host system's software store app (and also so we don't have to ensure it supports every packaging system under the sun).

Copy link
Contributor

@zyga zyga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial review, some questions and suggestions around

@@ -0,0 +1,2 @@
#!/bin/sh
echo "Open URI: $1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, nice idea :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:

Fake snap got %s

might help make the test more clear. As it is the test doesn't make clear that Open URI comes from this place. In other words, the diff is clear as we have everything here, but someone reading the test in a short while won't realize what's actually printing "Open URI".

prepare: |
#shellcheck source=tests/lib/pkgdb.sh
. "$TESTSLIB/pkgdb.sh"
distro_install_package xdg-utils

This comment was marked as resolved.

MATCH "GNOME Software required" < errors.log

echo "Now with gnome-software installed"
snap try "$TESTSLIB"/snaps/gnome-software
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could also use install_local, is there any specific purpose for try here?


echo "Now with gnome-software installed"
snap try "$TESTSLIB"/snaps/gnome-software
snap snap-uri-handler snap://package | MATCH "Open URI: snap://package"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is acknowledged with regards to design but I find it repetitive. snap uri-handler snap://package would look nicer IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I wanted to namespace the command to make it clear that it was for handling "snap://" URIs.

I don't think users would tend to call this directly, so ideally it'd be a hidden command. Some of the "snap debug" commands were hidden, but I couldn't see how to do the same for top level commands.

AUTOSTART_SOURCES = snap-userd-autostart.desktop.in
AUTOSTART_FILES = $(AUTOSTART_SOURCES:.in=)

DESKTOP_FILES = $(APPLICATION_FILES) $(AUTOSTART_FILES)

.PHONY: all
all: $(DESKTOP_FILES)

.PHONY: install
install: $(DESKTOP_FILES)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal but perhaps this would be cleaner:

# NOTE: old (e.g. 14.04) GNU coreutils doesn't -D with -t

install:: $(APPLICATION_FILES)
        install -d -m 0755 $(DESTDIR)/$(APPLICATIONSDIR)
        install -m 0644 -t $(DESTDIR)/$(APPLICATIONSDIR) $^

install:: $(AUTOSTART_FILES)
  	install -d -m 0755 $(DESTDIR)/$(SYSCONFXDGAUTOSTARTDIR)
 	install -m 0644 -t $(DESTDIR)/$(SYSCONFXDGAUTOSTARTDIR) $^

AUTOSTART_SOURCES = snap-userd-autostart.desktop.in
AUTOSTART_FILES = $(AUTOSTART_SOURCES:.in=)

DESKTOP_FILES = $(APPLICATION_FILES) $(AUTOSTART_FILES)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you follow my advice below please remove DESKTOP_FILES


func init() {
addCommand("snap-uri-handler",
"Handle a snap:// URI",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, please use i18n helpers.

return err
}
answeredYes := dialog.YesNo(
i18n.G("Install GNOME Software?"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading. The user may already have GNOME Software installed, just not as a snap. How about "Install snap-aware GNOME Software snap?"

if _, _, err := cli.Snap("gnome-software"); err == nil {
return nil
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be okay to use gnome-software from the classic distribution if it meets some requirements that we can test for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kenvandine's original idea was to use the gnome-software snap everywhere. I guess there are two questions when trying to determine if the host system version is sufficient:

  1. does it have the snap plugin?
  2. is it a new enough version of gnome-software to include all the features we want to expose? (e.g. old versions won't let you pick a channel for installed snaps).

I think checking for the presence of /usr/share/metainfo/org.gnome.Software.Plugin.Snap.metainfo.xml would satisfy (1), but (2) is a bit harder. @robert-ancell might have some input too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be okay to use gnome-software from the classic distribution if it meets some requirements that we can test for?

We can delay that decision for a while. It'll be nice to exercise the exception path on our end for longer and make sure it works well for everybody, before deciding to take the shortcut.

@jhenstridge
Copy link
Contributor Author

A few more notes about the change:

  1. without a mimeapps.list file setting the default handler for the URI scheme, it is undefined which .desktop file will be launched to handle the URI when there are multiple handlers. For the case of a snapped gnome-software, the two .desktop files should behave identically: one launches gnome-software directly, and the other launches it via "snap snap-uri-handler".

  2. I'm not sure what we can do about a classic packaged gnome-software. Looking at the source code, it advertises support for the snap URI scheme in its desktop file unconditionally. While we could improve things to only advertise the URI scheme if the snap plugin is actually built, that doesn't really for distros that split the app into multiple binary packages (e.g. Debian, Ubuntu, Fedora).

@robert-ancell
Copy link
Contributor

robert-ancell commented Jun 20, 2018

You may be able to make this a true "handler of last resort" by using TryExec in snap-uri-handler.desktop. That could run a program to determine if any other snap handler is installed, and return false in that case. This will avoid prompting the user to choose between "GNOME Software" (or KDE Discover etc) and "Handler for snap:// URIs".

A cleaner way might be to install /usr/share/applications/snap-store.desktop:
Name=Snap Store (install)
Exec=<snap install gnome-software, launch gnome-software with requested snap>
TryExec=<false if gnome-software snap installed>

In terms of trying to work out if you have a sufficiently recent version of the GNOME Software snap plugin installed, I think you're going to have a lot of trouble determining this reliably. I think it should be considered a bug in GNOME Software if it is reporting that it can handle snap:// URLs when it can't.

@jhenstridge jhenstridge force-pushed the snap-uri-handler branch 3 times, most recently from 7b01d2e to 699dcbc Compare June 21, 2018 04:47
@jhenstridge
Copy link
Contributor Author

Looking at glib/gio/gdesktopappinfo.c, it looks like it only checks for the presence of the TryExec executable rather than executing it, so I'm not sure that would actually work. The shell implementation in xdg-open doesn't seem to do anything with TryExec at all.

As far as gnome-software advertising support for the URI scheme goes, it could probably get around this by installing multiple .desktop files, with the URI schemes being advertised by hidden files that could be packaged with the plugins.

@jhenstridge jhenstridge force-pushed the snap-uri-handler branch 2 times, most recently from e0fe27a to e5687e9 Compare June 21, 2018 09:48
@jhenstridge
Copy link
Contributor Author

I've filed https://gitlab.gnome.org/GNOME/gnome-software/issues/405 to cover the issue of snap-less gnome-software installs advertising the snap: URI scheme.

One other issue with this PR is that it should be installing gnome-software from the stable channel. It isn't doing so currently because we haven't yet published to that channel and I needed something to test.

@jhenstridge jhenstridge force-pushed the snap-uri-handler branch 3 times, most recently from 0d71597 to 634bfa5 Compare June 22, 2018 08:01
@codecov-io
Copy link

codecov-io commented Jun 22, 2018

Codecov Report

Merging #5346 into master will decrease coverage by 0.06%.
The diff coverage is 18.42%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #5346      +/-   ##
==========================================
- Coverage   78.99%   78.93%   -0.07%     
==========================================
  Files         503      504       +1     
  Lines       37947    37985      +38     
==========================================
+ Hits        29977    29984       +7     
- Misses       5547     5578      +31     
  Partials     2423     2423
Impacted Files Coverage Δ
cmd/snap/cmd_snap_uri_handler.go 18.42% <18.42%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e3b7633...8e01d6e. Read the comment docs.

@mvo5 mvo5 added this to the 2.34 milestone Jun 27, 2018
Copy link
Contributor

@zyga zyga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code wise this looks fine. I added two comments for a makefile tweak. Please get a review from @niemeyer for the design.

install -d -m 0755 $(DESTDIR)/$(SYSCONFXDGAUTOSTARTDIR)
install -m 0644 -t $(DESTDIR)/$(SYSCONFXDGAUTOSTARTDIR) $^
install -m 0644 -t $(DESTDIR)/$(SYSCONFXDGAUTOSTARTDIR) $(AUTOSTART_FILES)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can keep using $^ here

# NOTE: old (e.g. 14.04) GNU coreutils doesn't -D with -t
install:: $(DESKTOP_FILES)
install -d -m 0755 $(DESTDIR)/$(APPLICATIONSDIR)
install -m 0644 -t $(DESTDIR)/$(APPLICATIONSDIR) $(DESKTOP_FILES)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use $^ as well

@Conan-Kudo
Copy link
Contributor

@jhenstridge In the Fedora case, we actually do build the snap plugin for both gnome-software and plasma-discover. I'd rather see this backup handler thing first query for a package that provides it and install it if it's not available. If that fails, then install the snap version of g-s...

Copy link
Contributor

@niemeyer niemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments, but nothing major.

Idea looks nice, thanks!

}

func init() {
addCommand("snap-uri-handler",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest "handle-link" for this, as being slightly more comfortable to use in conversations and nicer to read/write, and it's also a verb rather than a noun.

if _, _, err := cli.Snap("gnome-software"); err == nil {
return nil
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be okay to use gnome-software from the classic distribution if it meets some requirements that we can test for?

We can delay that decision for a while. It'll be nice to exercise the exception path on our end for longer and make sure it works well for everybody, before deciding to take the shortcut.

func init() {
addCommand("snap-uri-handler",
i18n.G("Handle a snap:// URI"),
i18n.G("The snap-uri-handler command installs the gnome-software snap and then invokes it."),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hadn't we decided not to call this "gnome-software", so it doesn't get confused with the deb or rpm version, and highlight the fact this is snap only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is my understanding too, talking to Ken and Robert. I don't think the name has been settled on yet, so I haven't changed it here. That's definitely something that blocks merging of this branch though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's now agreement that this is the "snap store" snap.

@@ -624,6 +624,7 @@ popd
%{_unitdir}/snapd.seeded.service
%{_unitdir}/snapd.autoimport.service
%{_unitdir}/snapd.seeded.service
%{_datadir}/applications/snap-uri-handler.desktop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's please name it after the new command name, whatever it ends up being (e.g. snap-handle-link.desktop assuming suggestion).

@@ -0,0 +1,2 @@
#!/bin/sh
echo "Open URI: $1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:

Fake snap got %s

might help make the test more clear. As it is the test doesn't make clear that Open URI comes from this place. In other words, the diff is clear as we have everything here, but someone reading the test in a short while won't realize what's actually printing "Open URI".


echo "URI Handler fails if gnome-software is not installed and user refuses to install it"
mount --bind /bin/false /usr/bin/zenity
if snap snap-uri-handler snap://package 2>errors.log; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't that be just something like:

snap handle-link snap://package 2>&1 | MATCH "GNOME Software required"

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to both check the exit code of the command invocation and that the expected message was printed to stderr (not stdout).

@mvo5 mvo5 removed this from the 2.34 milestone Jul 5, 2018
@jhenstridge jhenstridge force-pushed the snap-uri-handler branch 2 times, most recently from 418b7d0 to 4d90b4b Compare July 9, 2018 14:50
@niemeyer niemeyer changed the title cmd/snap: add a backup handler for snap:// URIs that prompts the user to install the gnome-software snap cmd/snap: gnome-software install via snap:// handler Aug 16, 2018
Copy link
Contributor

@niemeyer niemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.. just needs to be update to reflect the actual name of the snap store snap. Let's please avoid any mentions of "gnome software" here, so it's consistent.

func init() {
addCommand("handle-link",
i18n.G("Handle a snap:// URI"),
i18n.G("The handle-link command installs the gnome-software snap and then invokes it."),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, we have agreement about the name of the store snap:

% snap info snap-store
name:    snap-store
summary: Snap Store allows you to find and install new applications and remove existing installed
  applications.
publisher: Canonical✓
license:   GPL-3.0+


func (x *cmdHandleLink) ensureGnomeSoftwareInstalled(cli *client.Client) error {
// If the gnome-software snap is installed, our work is done
if _, _, err := cli.Snap("gnome-software"); err == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

return err
}
answeredYes := dialog.YesNo(
i18n.G("Install snap-aware GNOME Software snap?"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking. ("Install snap store snap?" maybe?)

}
answeredYes := dialog.YesNo(
i18n.G("Install snap-aware GNOME Software snap?"),
i18n.G("GNOME Software is required to open snaps from a web browser."),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

Footer: i18n.G("This dialog will close automatically after 5 minutes of inactivity."),
})
if !answeredYes {
return fmt.Errorf(i18n.G("GNOME Software required"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

Channel: "edge", // FIXME: remove this when gnome-software published to stable
Classic: true,
}
changeID, err := cli.Install("gnome-software", &opts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

return err
}

argv := []string{"snap", "run", "gnome-software", x.Positional.Uri}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

}, nil, nil)
}

func (x *cmdHandleLink) ensureGnomeSoftwareInstalled(cli *client.Client) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tweaking.

@niemeyer
Copy link
Contributor

By the way, I suggest testing with the actual snap which is published, just to make sure it really works in practice.

@Conan-Kudo
Copy link
Contributor

To be clear, this should not activate in cases that there's already a graphical tool to handle snaps, right?

@niemeyer
Copy link
Contributor

This is missing a second review. @pedronis? @chipaca?

@niemeyer
Copy link
Contributor

@Conan-Kudo This just registers a handler for snap:// as usual for the desktop.

Copy link
Contributor

@zyga zyga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@zyga
Copy link
Contributor

zyga commented Sep 12, 2018

Tests need to mock a browser for xdg-open

This version is using a shell implementation to determine the desktop ID
selected to handle the URI scheme and getting it wrong.  Full
implementations of the spec (e.g. GIO, Qt) will still get it right on
these distros.
@jhenstridge
Copy link
Contributor Author

I've disabled that part of the spread test on 16.04. It was passing when I started this branch but doesn't seem to now. The attempt to open a web browser is a fallback after failing to find the handler.

The shell fallback implementation in xdg-open seems a bit fragile, particularly the versions in older releases. So it might make sense to try and use the gio open instead, which has a more conformant implementation and uses the same code that e.g. Firefox ends up using.

As for other blockers, this branch still tries to install snap-store from the edge channel. This should be switched to stable, but of course that won't work until something is released in that channel.

@niemeyer
Copy link
Contributor

niemeyer commented Oct 4, 2018

@jdstrand remaining here? I had some review comments above unanswered, but I suppose they were all addressed? Anything else pending or should this go in?

@jdstrand
Copy link

@niemeyer pinged me on this, but I'm lacking context. I don't object to the concept of prompting to install the snap-store and quickly perusing the code, it defaults to not installing unless the user clicks to install it. I have not verified that mechanism can't be subverted, but at the level I looked at this, seems fine.

@jhenstridge jhenstridge force-pushed the snap-uri-handler branch 2 times, most recently from 05b6c57 to e342929 Compare October 18, 2018 15:08
@bboozzoo bboozzoo merged commit 4d120db into canonical:master Oct 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants