appimaged icon indicating copy to clipboard operation
appimaged copied to clipboard

Consider to unify 4 tools into one

Open probonopd opened this issue 6 years ago • 38 comments

Let's consider to unify 4 tools into one

  • https://github.com/AppImage/appimaged
  • https://github.com/azubieta/appimage-desktop-integration
  • https://github.com/TheAssassin/AppImageLauncher
  • https://github.com/CalebQ42/LinuxPA

In times in which people complain about fragmentation of the already small Desktop Linux user base, we should try not to add further fragmentation by offering 3 different ways to achieve desktop integration for AppImages.

As it stands now, not even I would be able to explain to a user which one to use, and why.

Hence I suggest we make a table that lists the differences, and then see if we can make one tool that either does it all, or at least can be configured to do either-or.

Aspect/feature appimaged AppImageLauncher appimage-desktop-integration For comparison: macOS LaunchServices
Triggered by Watching directories with inotify AppImages registered with binfmt MimeType handler or Watching $HOME/Applications directory .app extension
Put application into menu Yes Yes Yes No
Move AppImage file No Yes (asks user) Yes (asks user) No (suggests user to drag the .app into /Applications using the Finder)
Sandbox Yes (if Firejail is present) ? Not yet No (warns if app is not signed)
Update Adds update context menu item (if AppImageUpdate is present) ? Not yet No (apps can embed Sparkle framework)
Needs an app store/app center No ? No No
Runs nicely alongside an app store/app center Yes Yes Yes Yes

Please add to the list (maybe we should move it to the wiki for better edit-ability).

probonopd avatar May 16 '18 18:05 probonopd

AppImageLauncher doesn't intercept calls to AppImages solely with binfmt-misc, but also the MIME type. It adds an update and remove desktop action to the desktop files. It ships with tools for this purpose, and doesn't depend on external tools (which need to have any specific filename). You can't break this functionality, like you can with appimaged, when the tool goes away. Firejail support is planned (see https://github.com/TheAssassin/AppImageLauncher/issues/32).

appimage-desktop-integration relies on the MIME type, and doesn't intercept calls. It has a different focus, it's more about "do you want to make this executable" instead of "do you want to integrate this AppImage in your system".

It should be noted that appimaged isn't scalable, and, compared to the other solutions, slows down the system e.g., during boot, and generates a lot of I/O operations (mainly read).

TheAssassin avatar May 16 '18 19:05 TheAssassin

The three are mutually exclusive (in the sense that no one ever will want to use all three), right?

probonopd avatar May 16 '18 20:05 probonopd

I don't think that the tools are mutually exclusive. They provide similar functionalities what differs are the workflows. So unifying the code base is possible and recommended. Additionally we could have a config tool to allow users to enable/disable things as they please.

azubieta avatar May 16 '18 20:05 azubieta

I think using them all together is pointless, though. But they're compatible. You could switch from appimaged to AppImageLauncher and vice versa. Brought to you by libappimage.

TheAssassin avatar May 16 '18 20:05 TheAssassin

These are two questions:

  • Would anyone want to use all three together on the same machine, as of today?
  • Can the three tools be merged (possibly by using runtime configuration options)?

probonopd avatar May 16 '18 20:05 probonopd

Why would you want to merge them? AppImageLauncher and appimaged work so differently. AppImageLauncher focuses on user control, not on automagic integration. There is no real point in merging appimaged and AppImageLauncher.

Using them together doesn't make much sense to me either. The update and removal tools AppImageLauncher provides are not compatible with what appimaged does. And AppImageLauncher is run only on behalf of a user action.

I don't see any point in merging them. Why don't you explain why you think it would be possible and make sense to merge any of them?

TheAssassin avatar May 16 '18 20:05 TheAssassin

In AppImage-Desktop-Integration ( ADI now on ), automatic integration is used along with the single app user control. So it's a merge between both approach. The rationale behind it is: I have several of apps in my system, the ones that I use every day are in $HOME/Applications and they are integrated in the system. The ones that I rarely use are somewhere else.

This allows automatic and unattended integration and removal of apps by means of the Applications directory. At the appimaged style, which keeps the idea making dead simple to integrate or remove an application in the system.

Also consider the AppImageLauncher is launcher functionalities useful, in the case of we would like to use Appimages from a CLI (where mime-types handlers are not used). Or to integrate/remove some applications that for some reason the user didn't want to have with the rest (by example in a Applications folder).

About the merge, we could provide from a single code base the three workflows:

  • full $HOME folder monitoring
  • only $HOME/Applications monitoring
  • first run assistant (AppImageLauncher)
  • update menu entry
  • remove integration menu entry (which to be honest looks a bit awkward alongside with the delete menu entry)

azubieta avatar May 16 '18 21:05 azubieta

Why would you want to merge them?

AppImage is supposed to be simple, and having 3 tools doing kinda similar things (integrate AppImages into the desktop) is confusing - even me...

probonopd avatar May 16 '18 21:05 probonopd

AppImageLauncher keeps things simple from a user perspective. Much more simple than appimaged. Less magic, more control, and more visible actions. The user interface is kept really simple and understandable, but it has a lot of functionality in it.

TheAssassin avatar May 16 '18 21:05 TheAssassin

If simplicity means that the user have to do lees stuff to use a newly acquired application I must vote for appimaged (and it's magic which is totally transparent for the user). Once the application is download you can go and launch it from your menu or from the file.

IMHO The hard point about AppImageLauncher is control, the user can decide what is being integrated and what is not.

azubieta avatar May 16 '18 21:05 azubieta

Simplicity is more than just "count of mouse clicks". Simplicity involves the user experience, especially how understandable it is for the user. Nobody really understands appimaged. It does monitor only a set of predefined directories (which the user doesn't necessarily know), and doesn't work for applications on the entire system. If I'd plug in a USB drive with a set of AppImages, AppImages on then couldn't be run by the user if they weren't executable. And the user might not even want these to be integrated, not even for a minute.

Also, if AppImageLauncher crashes, the user will notice immediately, and can report the issue. If a daemon ever crashes, a user needs to spend time on investigating this when they want to launch an AppImage that they expect to be integrated.

Also AppImageLauncher is not prone to common daemon bugs like memleaks. It just runs during the launch, and then terminates. This is quite understandable. It works similar to a runtime.

TheAssassin avatar May 16 '18 22:05 TheAssassin

Actually end user doesn't want to understand anything about adding or removing applications from their systems. They just want to have an application or not. The only thing that they should know: applications are stored at $HOME/Applications (or wherever you like) Also it's true that there would be some applications that you are only testing and you don't want to integrate. If the deamon crashes Apport (or something alike) will let you know to report the error.

Memleaks it's not a valid argument, it just says that we are not good C/C++ programmers.

azubieta avatar May 16 '18 22:05 azubieta

Nobody really understands appimaged.

Then we need to fix it or replace it by something better. Just piling up additional alternatives is not gonna help the cause. Can any of the other two solutions integrate (and make executable, if needed) AppImages prior to them being run at least once?

probonopd avatar May 17 '18 05:05 probonopd

Memleaks it's not a valid argument, it just says that we are not good C/C++ programmers.

It's just an example. There's many reasons a daemon could fail. And therefore you need to manage it. Claiming you're a good programmer so you may not produce a bug is quite arrogant, we all produce bugs from time to time.

If you're interested in integrating your tool into AppImageLauncher, we could talk about the following model: We implement the daemon you have written in AppImageLauncher based on your code but using my integration code (in order to provide a consistent experience). We should write at least a systemd user config like appimaged. The workflow is as follows: if a user launches an AppImage that is not in ~/Applications, AppImageLauncher will ask about the integration. If a user moves an AppImage into ~/Applications themselves, the AppImage is automatically integrated. If it is removed, it is "un"-integrated. (We don't need to have the daemon do that even, actually, due to TryExec being a thing). The user can optionally choose to disable the daemon by disabling it via systemd.

Would that be acceptable for you? We would have the "best of both worlds", combining the daemon and launcher approaches.

TheAssassin avatar May 17 '18 11:05 TheAssassin

Claiming you're a good programmer so you may not produce a bug is quite arrogant, we all produce bugs from time to time.

It wasn't my intention to show of that I don't have bugs in my code. I just want to say that bugs must be fixed as soon as possible instead of assuming that is fine living whit some of them.

azubieta avatar May 17 '18 14:05 azubieta

About merging, I agreed about creating systemd and upstart configurations for the daemon along with the auto-start entry (as backward compatibility, it's already done so it will not mean any extra effort). The TryExec indeed hides the entry but when the menu cache is updated, there will be a time in which the entry is shown but the file will not exist.

About using binfmt as hocking method on the integration assistant. the binfmt hook provides an interpreter for AppImage files so every time you call exec on one of those it will be triggered instead. As the AppImage are already binary files that can be executed there is no need of such interpreter. Also AppImageLauncher and "appimage-desktop-integration-first-run" are binfmt Graphical Applications that will be used in a Graphical Desktop Environment where mime-types are well known and supported everywhere. Therefore a mime-type handler is a lot less complex and also does the job of handling non-runnable AppImage files. If the file has already execution permissions there is no need for us to stand in the way.

About the functionalities of finding collisions and adding the menu entries for update and remove applications. They are excellent as they are.

About the overall merge I think that the appimage-desktop-integration has a better structure to accept the new changes. Because components are more decoupled and sorted. Already has a configuration to generate multiple runnables (daemon and launcher) and the launcher application GUI already has the views for checking the appimage file integrity and signature (only the views because signature checking is not complete yet).

azubieta avatar May 17 '18 17:05 azubieta

@azubieta you don't seem to understand the point of AppImageLauncher. AppImageLauncher is more than a simple "make it executable" application. It's supposed to ask the user whether to integrate AppImages on every run. And by taking control of the AppImage execution, one can improve the experience a lot. For example, suppressing the old-style desktop integration dialog isn't possible in 100% of all cases without binfmt_misc support. That's the core difference between our tools. AppImageLauncher might gain more functionality in the future that requires such a form of control about the application instance life cycle. There is nothing that could replace this form of control to implement the current set of features.

What I am looking for at the moment is a way to execute AppImages directly bypassing binfmt_misc in some way, e.g., by calling ld-linux.so.2 directly. Unfortunately I couldn't find a method that works so far, as the magic bytes in the AppImage runtime seem to violate the ELF specification in a way that makes ld-linux.so.2 refuse to execute it.

Regarding the structure: your application is a little more class-based than mine is. This might be due to me not being very used to Qt, and also because I prefer a more "functional" approach as long as encapsulation or inheritance isn't needed. I could only "decouple" my code more if I'd split up the shared module I have. But other than that, there is no real need for classes, or for a separate source file for every single functionality that is shared, following the KISS principle.

TheAssassin avatar May 18 '18 14:05 TheAssassin

@TheAssassin I know it's much more than "make it executable". I already test it, read the code and you even have explained to me several times.

What seems wrong to me is to try intercepting every call of an AppImage file like an interpreter would do (let's call it interceptor to not create misunderstandings). Once the user have granted executable permissions there is no need for us to stay in the execution way. An AppImage is "a self-sufficient application in a single file", there is no room for interceptors or pseudo-interpreters in that statement. I fear that, as you said, new features were implemented making the fact of having this application in the system mandatory to execute properly some kind of AppImages. Would you mind to mention some example future features that will require or be improved by having this solution approach?

I use classes (and OOP in general) not just because I'm used to Qt nor because I like them. Actually encapsulation implies a better "separation of concerns" by keeping the not only the functions but also the data they handle together. Also reduce the scope of the code forcing us to be less messy with the result of a more malleable solution. By pushing our code to be more modular we will reduce tremendously the amount of comments required as the entities name will do that job (if we name them well). Also the side effects of our changes will be reduced as they will stay inside the module scope. Finally higher modularity allows more granular testing giving us peace of mind in every release and the confidence to change stuff without fearing that we could break something else.

The same applies to files, they will expose the architecture of the solution. By example: in my project I could put all the "core" classes in a single "core.cpp" file as functions and the whole module structure will be hidden.

You can use classes and don't violate KISS, there are no fake inheritance trees or forced design patterns in the solution. Just simple classes that provide a simple set of related functionalities and share some common data.

To summarize, in this case I use OOP and a very decoupled file structure to:

  • have more malleable modules
  • reduce side-effects
  • expose the solution architecture
  • improve readability (using entities name as documentation)
  • ease testing

NOTE: Suppression of the old stile desktop integration could be achieved by setting an environment variable.

azubieta avatar May 18 '18 17:05 azubieta

I fear that, as you said, new features were implemented making the fact of having this application in the system mandatory to execute properly some kind of AppImages.

Would you like to explain why you think there will be AppImages that won't run without AppImageLauncher? I already explained very often that AppImageLauncher is an enhancement. AppImages don't depend on it to run. Not at all. The opposite applies. AppImages can run fine without it.

What AppImageLauncher does, however, is that it can control some aspects of how the AppImage is launched. Setting the $DESKTOPINTEGRATION environment variable is a good example. Only by intercepting the calls to AppImages, this variable can be set reliably. There is no other way to do so reliably. Users can unset a system wide set $DESKTOPINTEGRATION variable. And if they do so, they break the system AppImageLauncher uses, as the old desktop integration isn't compatible with the libappimage one.

I don't see how there's an issue in intercepting calls at all by the way. If a desktop environment would do so in order to improve their AppImage support, would you mind? Why can't a third party app do so?

As said before, I don't like to ship with my own runtime to run AppImages. What I would rather like to do is edit the environment and then forward the call. That's the only real issue that needs to be solved.

TheAssassin avatar May 18 '18 18:05 TheAssassin

My fear is founded on that binfmt, as you said, give us a great power. You know the phrase "with a great power comes a great responsibility"? I just don't want to have responsibility of watching that what I'm doing will not break the applications run-time.

I'm calling on the KISS principle here, if a mime-type handler allows you to do intercept opening attempts on AppImage files in desktop environments why taking it to the CLI where there is no need to do anything for an AppImage to work as expected.

About your ISSUE did you tried loading the file as a regular shared lib and calling "main" ?

About the reliability of the environments variable. Yes the user can unset them, as they can also unset the binfmt entry. Does the fact that an user can break a system makes it unreliable ? If the answer is yes, then all GNU/Linux distributions are unreliable. I think your are exaggerating a bit on this topic. A lot of solid applications relies on environment variables starting from the initrd to the whole desktop environment.

azubieta avatar May 18 '18 19:05 azubieta

as they can also unset the binfmt entry.

The actual user can't alter these entries. You need to become root. And as root, you can create a lot of damage. So, actions as root user don't count really. If you're just a simple user, you can still call unset DESKTOPINTEGRATION in your shell, but you can't escape binfmt_misc support.

Considering your second argument regarding the MIME type, no, that's not quite true. As soon as the file is executable, you can't control its execution any more. That's why I implemented support for these use cases via binfmt_misc.

I will try to hack around using with dlopen().

TheAssassin avatar May 18 '18 19:05 TheAssassin

Escape binfmt_misc support is harder I know, but the thing is that you don't need it. Using an environment variable is good enough. If a regular user unset an environment variable they will do it on purpose, there is an unset command they have to run.

Would you please tell me why would you like to control an AppImage that was already set as executable by the user ? And what will you do with it besides of actually executing it ?

azubieta avatar May 18 '18 19:05 azubieta

Another reason to make use of binfmt_misc: https://github.com/TheAssassin/AppImageLauncher/issues/42

TheAssassin avatar May 20 '18 14:05 TheAssassin

From the discussion in the ticket it looks like this is not a simple question. Maybe we should schedule a time at which we can have a conf call/jit.si session? May be easier. I'd like to understand all of the a) requirements b) potential solutions to arrive at something that is really simple for our users. Having 3 tools that superficially(!) seem to do the same thing is not ,-)

probonopd avatar May 24 '18 16:05 probonopd

@probonopd we're working on this topic already behind the scenes (i.e., not on GitHub, but IRC etc.). We'll post an update soon.

TheAssassin avatar May 24 '18 20:05 TheAssassin

I would add another point. Could we have in non installed mode?

Namely I ran it, it runs in the background with all integrations applied. But it is not installed or becomes permanent part of the system. It is only work when initiated by user (For instance, it doesn't run automatically on restarts).

RoyiAvital avatar May 28 '18 17:05 RoyiAvital

...and to add one, https://github.com/CalebQ42/LinuxPA

probonopd avatar May 30 '18 05:05 probonopd

@probonopd , I'm not sure one must combine all. Letting different approaches develop on their own means anyone can choose.

In my opinion the missing tool (Which will have some features of each still missing). I will try describing it:

  1. Has the ability to work with no installation (Better be AppImage on its own).
  2. Runs only on demand (Namely it is not a background daemon with extra privileges, it is a regular program with System Tray icon).
  3. Scans User Defined single location (By default the folder it resides at). Scan period should be user adjustable.
  4. Here we have 2 approaches:
    • Application Menu of its own similar to PortableMenu.
    • Ability to integrate applications (And remove applications which were deleted) into the system menu.
  5. Ability to register MIME for applications (User level, not system).
  6. By default works in Portable Mode (Namely creates .home and .config folders per AppImage automatically).

In the long run with a data base of AppImage applications we can allow updating of AppImage as well.

RoyiAvital avatar May 30 '18 05:05 RoyiAvital

One difference between the tools is that appimaged runs as a daemon in the background, whereas other tools avoid this. A discussion at Discourse triggered by @RoyiAvital brought up the idea that we could turn appimaged into a non-daemon that does not run in the background, and have something else invoke it when needed. This "something" could either be a MIME type, or binfmt, or systemd Path Units (which uses inotify under the hood).

The beauty of this would be that we could decouple what the system integration tool does from how it is invoked, making for a more flexible system than we currently have.

wdyt?

probonopd avatar May 30 '18 05:05 probonopd

Has the ability to work with no installation

appimaged can do that. If you are fine with launching it manually, you can start and stop it like any other program, and for this it needs no installation.

it is not a background daemon with extra privileges, it is a regular program with System Tray icon

It has no extra privileges. In fact, it does what you describe but it doesn't have a tray icon (I don't like these).

Runs only on demand

What do you mean by "demand"? The user launching it whenever he has downloaded an AppImage? Or the system somehow (how?) invoking it when it "sees" a new AppImage?

Scans User Defined single location (By default the folder it resides at).

Currently we are scanning the locations listed in the README.md, but I like your suggestion that it should also scan the location at which it itself resides. Opened https://github.com/AppImage/appimaged/issues/7 for it.

Scan period should be user adjustable.

Why that? Currently it gets notified about changes by the kernel using the efficient inotify system.

In the long run with a data base of AppImage applications we can allow updating of AppImage as well.

This is out of scope here, but check https://appimage.github.io/apps/ and the various app centers and tools that use its data, e.g., https://github.com/opendesktop/opendesktop-app and https://github.com/nomad-desktop/nx-software-center (these are available as AppImages themselves, too).

probonopd avatar May 30 '18 06:05 probonopd