A while ago we discussed an idea about presenting snap data in a way better than today.
We identified some shortcomings of the current model:
-
The folder
~/snap/$SNAP_NAME/
presents data for various revisions as well as the English wordscurrent
andcommon
. Revisions are technical and users will typically not understand their significance. The two English words cannot be localized in any sensible way. -
The folder
~/snap/$SNAP_NAME/current/
is a miniature home directory, with hidden dot-folders and dot-files. In a typical case, following the path of least resistance, actual snap application data is inside one of the standard dot-directories like.config
,.local/share
or.cache
. A non-trivial number of applications also use custom dot-files that donât follow the scheme outlined above. -
Browsing using typical file managers is more challenging as they do not show hidden files or folders by default.
Those factors have largely contributed to the idea that the ~/snap
is not very user friendly as finding the right data requires overcoming some usability challenges.
Iâd like to propose changing how we present snap data in a dramatic way. There are two parts of this idea. The first part is that snap developers can now have a say in how their application data is presented to the user which is distinct to how the actual data is stored in the filesystem. The second part is technical and outlines various aspects of the proposed implementation.
Conceptually the snap packaging format leaves a lot of flexibility and decision making in the hands of the packager. The central interaction point is the meta/snap.yaml
file, which describes how various applications and content from the snap is to be presented to the system. This proposal extends that idea to user data. Using a new section in the snap.yaml
file, packages would be able to express meaningful presentation, or mapping, of the internal filesystem hierarchy in terms that users find comprehensible.
Letâs work through an example game. As a classic package the game would store itâs content in ~/.gamename. Most of the interesting files there being ~/.gamename/saves
and ~/.gamename/maps
. Packaged as a snap this becomes ~/snap/gamename/current/.gamename/saves
and a corresponding path for maps
.
There may be additional directories for caches, internal data files and other things that players typically do not interact with.
The snap packager could expose the relevant information to the user with the following, tentative, YAML declaration in the snap.yaml
file:
name: gamename
...
user-data-presentation:
saves:
path $SNAP_USER_DATA/.gamename/saves
maps:
path: $SNAP_USER_COMMON/.gamename/maps
The syntax is a mapping of top-level names that map to real path names from the point of view of the software. In the language above Iâve used two data sources - one being specific to the current revision and one that is common across revisions. From the user point of view there is no difference but from the packager point of view it may be beneficial to store some of the data in the common
directory, for instance, because it is particularly large and the format is stable across revisions.
There are many more ideas we could explore here. We could expose both folders and regular files. We could offer localized names, so that a player from Poland might see the names sejwy
and mapy
respectively. We could allow the snap packager to offer a special icon that is attached to the generic folder icon and use that icon when displaying the folder ~/snap/$SNAP_NAME
. This part is explicitly open-ended as there are many ideas we could explore.
Before jumping into the technical side we could also consider what happens to packages do not contain the new YAML language. We could present them as we do currently. We could choose not to present them at all, encouraging adoption and giving packagers a way to say that a particular snap does not have any user data to present at the same time. This is something to discuss later.
The remainder of this post is a technical overview of the idea.
The central component of the idea is the new FUSE filesystem, snapdatafs
, which runs in userspace in the session of a particular user. With the state of the desktop system interaction we could meaningfully support this in 18.04+, perhaps also in 16.04 but I did not evaluate it enough to be sure.
The filesystem is mounted on demand in the user session, it could be also not mounted at all, if the user strongly prefers that option. The actual name of the mount point could also be distinct from ~/snap
. It could be as simple as ~/Snap
(note the upper case) or anything more sophisticated.
The filesystem would consume a collection of meta/snap.yaml
files. Most likely aggregated by snapd into a trusted location that is available regardless of the state of the actual snaps. In my prototype I used /var/lib/snapd/snapdatafs/v1.yaml
. The application loads the file and establishes notification of file changes. The advantage of monitoring one file is that Linux filesystem notification APIs are rather unreliable and scale poorly - handling one aggregate file is much easier to do correctly.
The aggregate file is prepared by snapd and can be also used as a validation/post-processing point, providing a way to control the evolution of the format and compatibility with the file system.
The FUSE filesystem would present synthetic structure comprising the contents of todayâs ~/snap/
. Running with the game idea mentioned earlier it would create this synthetic structure:
gamename/ - directory
gamename/saves - directory
gamename/saves/* - bridge to actual backing store
gamename/maps - directory
gamename/maps/* - bridge to actual backing store
Initially the implementation could simply implement the bare minimum required to be a FUSE filesystem - provide read / write access to bridged files and refusing modifications of the fixed scaffolding.
As the implementation matures and we gain some practical experience we could optimize the I/O by using file descriptor offloading. FUSE could open the actual file and hand off the file descriptor to the kernel, thereby providing native performance to the non-synthetic sections.
There are some open questions I did not have time to get answers for:
- how to handle refreshes when the user is browsing, say the maps folder and the new revision removes that presentation. We would certainly have to handle some sort of corner cases where the snap is no longer presenting something but we have a folder open to the old view.
In some sense the new user-space filesystem could participate in refresh-app-awareness. Contributing information about business of a particular location. Definite answers would require more advanced prototype where that could be determined.