Skip to content

mgord9518/shappimage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shImg (shappimage)

A proof-of-concept implementation of AppImage created in shell script

How different is it from standard AppImage?

The ultimate goal is to have it be almost identical in normal use, but it isn't quite there yet. It's currently missing the ability to extract without requiring FUSE on the system, along with requiring fusermount3, which only exists on FUSE3 systems. Assuming you're on a modern system with FUSE3 though, it should work just like normal AppImages (assuming your file manager allows launching scripts as applications instead of just opening them in an editor)

The shImg runtime has a longer initialization time compared to standard the standard runtime. I've tried to optimize it a bit, but it still takes about 0.08s on my (fairly bad) hardware (mind you, Python 3 takes 0.1s on my system just to initalize and make a print statement, so it probably won't hurt performance that much for most things).

Another difference is the default compression being LZ4 (LZ4_HC) instead of LZIB, I decided this because LZ4 compression is practically free while still getting a decent (40%-60%) compression ratio. ZSTD is also supported as an option for both mid and high compression at the cost of longer launch time, but it should still be signifirantly faster than both ZLIB and XZ. Larger apps quickly reveal the benefit of using decompression optimized for modern hardware. Using LZ4, I generally get apps 30%-50% larger than ZLIB, but the return is a near-native launch speed.

How does it work?

Overall it's pretty simple, the script checks if the user has squashfuse/dwarfs binaries on their system (prefers this), if not it will extract a portable binary to $XDG_RUNTIME_DIR. It then uses the binary to mount the attached filesystem image at the specified offset, runs AppRun then unmounts and cleans up once finished. See File structure for more info

Packaging an application

Eventually I would like to make a proper tool for building shImgs, but for the time being, manually building is simple enough.

  1. Assemble an AppDir
  2. Compress the AppDir into a SquashFS image mksquashfs AppDir AppDir.sqfs -b1M -comp lz4 -Xhc
    • LZ4 should be used for applications where launch speed is preferred, ZSTD should be used in applications where maximum compression is preferred.
  3. Download or build the shImg runtime
  4. Concatenate the runtime and filesystem image cat runtime-[COMPRESSION]-[ARCHITECTURES] AppDir.sqfs > app.shImg

At this point, the shImg should be a working application given that it's marked executable or launched directly through the interpreter (eg: sh ./app.shImg) but the desktop integration zip should also be applied as it'll make it easier to integrate into the target system (once a final structure is decided on and software is made to supoort it)

AppDir

An AppDir is composed of all the files your application requires to run. It should be arranged in FHS, although any file layout works so long as your application is configured to load from relative locations.

  • Applications MUST not use absolute paths for loading built-in resources
  • Applications should make as few assumptions about the base system as reasonably possible. Static linking is preferable for maximum compatibility with systems like Alpine and NixOS.
  • AppDirs in shImg may be extended to support multiple system architectures in one image. To do so, you may either detect and run the appropriate binary using your AppRun, or provide an AppRun.[ARCH] eg: AppRun.aarch64, which the shImg runtime will prefer if the user is running said CPU.

File structure

The shell script (with the help of some attached fuse binaries) do the same job as the standard AppImage type 2 runtime, simply trying to find the image offset as fast as possible, mount it and run the contained application inside the SquashFS bundle. The (possibly multiarch) payload is appended, which contains the app itself.

Finally, a zip archive is slapped on the end to serve as desktop integration information. Zip was chosen over other formats for its ability to be placed at an arbitrary offset and still be accessed, this allows desktop integration software to simply open the AppImage as if it were a normal zip file, no need to worry about what's going on up front.

╔═══════════════════════════════╗ ─╮
║          shell script         ║  │
╟─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╢  │ ╭─────────╮
║  squashfuse binaries for all  ║  ├─┤ runtime │
║    supported architectures    ║  │ ╰─────────╯
╟───────────────────────────────╢ ─┴╮
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║     SquashFS/DwarFS payload   ║   │ ╭───────────────────╮
║                               ║   ├─┤ meat and potatoes │
║     (LZ4_HC, ZSTD or GZIP)    ║   │ ╰───────────────────╯
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
║                               ║   │
╟───────────────────────────────╢ ─┬╯╭───────────────╮
║    desktop integration zip    ║  ├─┤ cherry on top │
╚═══════════════════════════════╝ ─╯ ╰───────────────╯

Destop integration format

This is my current draft for desktop integration information in shImg. It is simply a zip file appended to the end of the shImg. Uncompressed entries are intended to be extracted via the shell script runtime, but this requirement may be dropped if I find an easy enough way to extract them without needing infozip on the host machine.

Inside the destop integration zip, the directory tree is as follows:

.APPIMAGE_RESOURCES/
├─ destop_entry
├─ metainfo     [OPTIONAL]
├─ update_info  [OPTIONAL] [MUST BE UNCOMPRESSED]
├─ signature    [OPTIONAL] [MUST BE UNCOMPRESSED]
└─ icon
   ├─ default.{png,svg}
   ├─ 16.png    [OPTIONAL]
   ├─ 24.png    [OPTIONAL]
   ├─ 32.png    [OPTIONAL]
   ├─ 48.png    [OPTIONAL]
   ├─ 64.png    [OPTIONAL]
   ├─ 96.png    [OPTIONAL]
   ├─ 128.png   [OPTIONAL]
   ├─ 256.png
   └─ 512.png   [OPTIONAL]

desktop_entry contains the app's .desktop file. metainfo contains AppStream metainfo, typically located at usr/share/metainfo/*.appdata.xml. update_info contains AppImage update information, along with a special header and footer to make it easy to find in shell script. signature is not yet impletmented, but will be a GPG sig used for signing the shImg.

The only supported icon (default.png, default.svg) image formats are PNG and SVG, and there should only be one "default" file. Thumbnailing images MUST be PNG. 256.png is the only required image for thumbnailing, but more sizes may also be added if desired.

DwarFS notice

  • DwarFS is licensed under GPL3, the DwarFS shImg version may only be used with GPL3 software.
  • This section of the runtime has much less testing than the SquashFS version and may come with more issues. It should currently only be used for testing

About

An AppImage implementation made in shell script

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages