mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-01-18 13:36:36 +01:00
pack: Add support for AppImage pack format.
* guix/scripts/pack.scm (self-contained-appimage): New procedure. (%formats, show-formats): Add it. (guix-pack): Honor it. * doc/guix.texi: Document AppImage pack. * tests/pack.scm ("appimage", "appimage + localstatedir"): New tests. Co-authored-by: Noé Lopez <noelopez@free.fr> Change-Id: I33ebfec623cff1cfcd6f029d2d3054c23ab1949a Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
parent
b143ec8eda
commit
ccf72d5074
3 changed files with 198 additions and 6 deletions
|
@ -6955,6 +6955,16 @@ directly be used as a file system container image with the
|
||||||
environment}, using commands like @command{singularity shell} or
|
environment}, using commands like @command{singularity shell} or
|
||||||
@command{singularity exec}.
|
@command{singularity exec}.
|
||||||
|
|
||||||
|
@cindex AppImage, create an AppImage file with @command{guix pack}
|
||||||
|
Another format internally based on SquashFS is
|
||||||
|
@uref{https://appimage.org/, AppImage}. An AppImage file can be created
|
||||||
|
and executed without any special privileges:
|
||||||
|
|
||||||
|
@example
|
||||||
|
file=$(guix pack -f appimage --entry-point=bin/guile guile)
|
||||||
|
$file --help
|
||||||
|
@end example
|
||||||
|
|
||||||
Several command-line options allow you to customize your pack:
|
Several command-line options allow you to customize your pack:
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
|
@ -7071,6 +7081,48 @@ to install Guix-produced @samp{.rpm} packages on a system where
|
||||||
installation or other, non-rpm packs.
|
installation or other, non-rpm packs.
|
||||||
@end quotation
|
@end quotation
|
||||||
|
|
||||||
|
@item appimage
|
||||||
|
@cindex AppImage, create an AppImage file with @command{guix pack}
|
||||||
|
This produces an @uref{https://appimage.org/, AppImage file} with the
|
||||||
|
@samp{.AppImage} extension. AppImage is a SquashFS volume prefixed with
|
||||||
|
a runtime that mounts the SquashFS file system and executes the binary
|
||||||
|
provided with @option{--entry-point}. This results in a self-contained
|
||||||
|
archive that bundles the software and all its requirements into a single
|
||||||
|
file. When the file is made executable it runs the packaged software.
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix pack -f appimage --entry-point=bin/vlc vlc
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The runtime used by AppImages invokes the @command{fusermount3} command
|
||||||
|
to mount the image quickly. If that command is unavailable, the
|
||||||
|
AppImage fails to run, but it can still be started by passing the
|
||||||
|
@option{--appimage-extract-and-run} flag.
|
||||||
|
|
||||||
|
@quotation Warning
|
||||||
|
When building an AppImage, always @emph{pass} the @option{--relocatable}
|
||||||
|
option (or @option{-R}, or @option{-RR}) to make sure the image can be
|
||||||
|
used on systems where Guix is not installed. A warning is printed when
|
||||||
|
this option is not used.
|
||||||
|
@end quotation
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix pack -f appimage --entry-point=bin/hello --relocatable hello
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@quotation Note
|
||||||
|
The resulting AppImage does not conform to the complete standard as it
|
||||||
|
currently does not contain a @file{.DirIcon} file. This does not impact
|
||||||
|
functionality of the AppImage itself, but possibly that of software used
|
||||||
|
to manage AppImages.
|
||||||
|
@end quotation
|
||||||
|
|
||||||
|
@quotation Note
|
||||||
|
As the generated AppImage packages the complete dependency graph, it
|
||||||
|
will be larger than comparable AppImage files found online, which depend
|
||||||
|
on host system libraries.
|
||||||
|
@end quotation
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@cindex relocatable binaries
|
@cindex relocatable binaries
|
||||||
|
@ -7160,10 +7212,10 @@ execution engines listed above by setting the
|
||||||
|
|
||||||
@cindex entry point, for Docker and Singularity images
|
@cindex entry point, for Docker and Singularity images
|
||||||
@item --entry-point=@var{command}
|
@item --entry-point=@var{command}
|
||||||
Use @var{command} as the @dfn{entry point} of the resulting pack, if the pack
|
Use @var{command} as the @dfn{entry point} of the resulting pack, if the
|
||||||
format supports it---currently @code{docker} and @code{squashfs} (Singularity)
|
pack format supports it---currently @code{docker}, @code{appimage}, and
|
||||||
support it. @var{command} must be relative to the profile contained in the
|
@code{squashfs} (Singularity) support it. @var{command} must be
|
||||||
pack.
|
relative to the profile contained in the pack.
|
||||||
|
|
||||||
The entry point specifies the command that tools like @code{docker run} or
|
The entry point specifies the command that tools like @code{docker run} or
|
||||||
@code{singularity run} automatically start by default. For example, you can
|
@code{singularity run} automatically start by default. For example, you can
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
|
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
|
||||||
;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk>
|
;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk>
|
||||||
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
||||||
|
;;; Copyright © 2024 Sebastian Dümcke <code@sam-d.com>
|
||||||
|
;;; Copyright © 2024 Noé Lopez <noelopez@free.fr>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -56,6 +58,7 @@ (define-module (guix scripts pack)
|
||||||
#:use-module ((gnu packages compression) #:hide (zip))
|
#:use-module ((gnu packages compression) #:hide (zip))
|
||||||
#:use-module (gnu packages guile)
|
#:use-module (gnu packages guile)
|
||||||
#:use-module (gnu packages base)
|
#:use-module (gnu packages base)
|
||||||
|
#:autoload (gnu packages appimage) (appimage-type2-runtime)
|
||||||
#:autoload (gnu packages gnupg) (guile-gcrypt)
|
#:autoload (gnu packages gnupg) (guile-gcrypt)
|
||||||
#:autoload (gnu packages guile) (guile2.0-json guile-json)
|
#:autoload (gnu packages guile) (guile2.0-json guile-json)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
@ -64,6 +67,7 @@ (define-module (guix scripts pack)
|
||||||
#:use-module (srfi srfi-35)
|
#:use-module (srfi srfi-35)
|
||||||
#:use-module (srfi srfi-37)
|
#:use-module (srfi srfi-37)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
|
#:use-module (ice-9 optargs)
|
||||||
#:export (symlink-spec-option-parser
|
#:export (symlink-spec-option-parser
|
||||||
|
|
||||||
self-contained-tarball
|
self-contained-tarball
|
||||||
|
@ -71,6 +75,7 @@ (define-module (guix scripts pack)
|
||||||
rpm-archive
|
rpm-archive
|
||||||
docker-image
|
docker-image
|
||||||
squashfs-image
|
squashfs-image
|
||||||
|
self-contained-appimage
|
||||||
|
|
||||||
%formats
|
%formats
|
||||||
guix-pack))
|
guix-pack))
|
||||||
|
@ -974,8 +979,100 @@ (define signature
|
||||||
(gexp->derivation (string-append name ".rpm") build
|
(gexp->derivation (string-append name ".rpm") build
|
||||||
#:target target
|
#:target target
|
||||||
#:references-graphs `(("profile" ,profile))))
|
#:references-graphs `(("profile" ,profile))))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; AppImage format
|
||||||
|
;;;
|
||||||
|
(define* (self-contained-appimage name profile
|
||||||
|
#:key target
|
||||||
|
(profile-name "guix-profile")
|
||||||
|
entry-point
|
||||||
|
(compressor (lookup-compressor "zstd"))
|
||||||
|
localstatedir?
|
||||||
|
(symlinks '())
|
||||||
|
(archiver tar)
|
||||||
|
(extra-options '()))
|
||||||
|
"Return a self-contained AppImage containing a store initialized with the
|
||||||
|
closure of PROFILE, a derivation. The AppImage contains /gnu/store unless
|
||||||
|
RELOCATABLE option is used; if LOCALSTATEDIR? is true, it also contains
|
||||||
|
/var/guix, including /var/guix/db with a properly initialized store database.
|
||||||
|
|
||||||
|
SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
|
||||||
|
added to the pack."
|
||||||
|
(unless entry-point
|
||||||
|
(leave (G_ "entry-point must be provided in the '~a' format~%")
|
||||||
|
'appimage))
|
||||||
|
(let-keywords extra-options #f ((relocatable? #f))
|
||||||
|
(unless relocatable?
|
||||||
|
(warning (G_ "AppImages should be built with the --relocatable flag~%"))))
|
||||||
|
|
||||||
|
(define runtime-package appimage-type2-runtime)
|
||||||
|
(define runtime-path "bin/runtime-fuse3")
|
||||||
|
(define %valid-compressors '("gzip" "zstd"))
|
||||||
|
|
||||||
|
(let ((compressor-name (compressor-name compressor)))
|
||||||
|
(unless (member compressor-name %valid-compressors)
|
||||||
|
(leave (G_ "~a is not a valid squashfs archive compressor used in
|
||||||
|
generating the AppImage. Valid compressors are: ~a~%")
|
||||||
|
compressor-name
|
||||||
|
%valid-compressors)))
|
||||||
|
|
||||||
|
(define builder
|
||||||
|
(with-extensions (list guile-gcrypt)
|
||||||
|
(with-imported-modules (source-module-closure
|
||||||
|
'((guix build store-copy)
|
||||||
|
(guix build utils))
|
||||||
|
#:select? not-config?)
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils)
|
||||||
|
(guix build store-copy)
|
||||||
|
(rnrs io ports)
|
||||||
|
(srfi srfi-1)
|
||||||
|
(srfi srfi-26))
|
||||||
|
|
||||||
|
(define (concatenate-files result file1 file2)
|
||||||
|
"Creates a new file RESULT containing FILE1 followed by FILE2."
|
||||||
|
(call-with-output-file result
|
||||||
|
(lambda (output)
|
||||||
|
(call-with-input-file file1
|
||||||
|
(lambda (input)
|
||||||
|
(dump-port input output)))
|
||||||
|
(call-with-input-file file2
|
||||||
|
(lambda (input)
|
||||||
|
(dump-port input output))))))
|
||||||
|
|
||||||
|
(let* ((appdir "AppDir")
|
||||||
|
(squashfs "squashfs")
|
||||||
|
(profile-items (map store-info-item
|
||||||
|
(call-with-input-file "profile" read-reference-graph)))
|
||||||
|
(profile (find (lambda (item)
|
||||||
|
(string-suffix? "-profile" item))
|
||||||
|
profile-items)))
|
||||||
|
(mkdir-p appdir)
|
||||||
|
;; Copy all store items from the profile to the AppDir.
|
||||||
|
(populate-store '("profile") appdir)
|
||||||
|
;; Symlink the provided entry-point to AppDir/AppRun.
|
||||||
|
(symlink (string-append "." profile "/" #$entry-point)
|
||||||
|
(string-append appdir "/AppRun"))
|
||||||
|
;; Create .desktop file as required by the spec.
|
||||||
|
(make-desktop-entry-file
|
||||||
|
(string-append appdir "/" #$name ".desktop")
|
||||||
|
#:name #$name
|
||||||
|
#:exec #$entry-point)
|
||||||
|
;; Compress the AppDir.
|
||||||
|
(invoke #+(file-append squashfs-tools "/bin/mksquashfs") appdir
|
||||||
|
squashfs "-root-owned" "-noappend"
|
||||||
|
"-comp" #+(compressor-name compressor))
|
||||||
|
;; Append runtime and squashFS into file AppImage.
|
||||||
|
(concatenate-files #$output
|
||||||
|
#$(file-append runtime-package "/" runtime-path)
|
||||||
|
squashfs)
|
||||||
|
;; Add execution permission.
|
||||||
|
(chmod #$output #o555))))))
|
||||||
|
(gexp->derivation (string-append name ".AppImage") builder
|
||||||
|
#:target target
|
||||||
|
#:references-graphs `(("profile" ,profile))))
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Compiling C programs.
|
;;; Compiling C programs.
|
||||||
;;;
|
;;;
|
||||||
|
@ -1311,6 +1408,7 @@ (define %formats
|
||||||
(squashfs . ,squashfs-image)
|
(squashfs . ,squashfs-image)
|
||||||
(docker . ,docker-image)
|
(docker . ,docker-image)
|
||||||
(deb . ,debian-archive)
|
(deb . ,debian-archive)
|
||||||
|
(appimage . ,self-contained-appimage)
|
||||||
(rpm . ,rpm-archive)))
|
(rpm . ,rpm-archive)))
|
||||||
|
|
||||||
(define (show-formats)
|
(define (show-formats)
|
||||||
|
@ -1327,6 +1425,8 @@ (define (show-formats)
|
||||||
deb Debian archive installable via dpkg/apt"))
|
deb Debian archive installable via dpkg/apt"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
rpm RPM archive installable via rpm/yum"))
|
rpm RPM archive installable via rpm/yum"))
|
||||||
|
(display (G_ "
|
||||||
|
appimage AppImage self-contained and executable format"))
|
||||||
(newline))
|
(newline))
|
||||||
|
|
||||||
(define (required-option symbol)
|
(define (required-option symbol)
|
||||||
|
@ -1694,6 +1794,8 @@ (define (process-file-arg opts name)
|
||||||
(process-file-arg opts 'preun-file)
|
(process-file-arg opts 'preun-file)
|
||||||
#:postun-file
|
#:postun-file
|
||||||
(process-file-arg opts 'postun-file)))
|
(process-file-arg opts 'postun-file)))
|
||||||
|
('appimage
|
||||||
|
(list #:relocatable? relocatable?))
|
||||||
(_ '())))
|
(_ '())))
|
||||||
(target (assoc-ref opts 'target))
|
(target (assoc-ref opts 'target))
|
||||||
(bootstrap? (assoc-ref opts 'bootstrap?))
|
(bootstrap? (assoc-ref opts 'bootstrap?))
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
||||||
;;; Copyright © 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
;;; Copyright © 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||||
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
||||||
|
;;; Copyright © 2024 Noé Lopez <noelopez@free.fr>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -32,7 +33,8 @@ (define-module (test-pack)
|
||||||
#:use-module (guix utils)
|
#:use-module (guix utils)
|
||||||
#:use-module ((guix build utils) #:select (%store-directory))
|
#:use-module ((guix build utils) #:select (%store-directory))
|
||||||
#:use-module (gnu packages)
|
#:use-module (gnu packages)
|
||||||
#:use-module ((gnu packages base) #:select (libc-utf8-locales-for-target))
|
#:use-module ((gnu packages base) #:select (libc-utf8-locales-for-target
|
||||||
|
hello))
|
||||||
#:use-module (gnu packages bootstrap)
|
#:use-module (gnu packages bootstrap)
|
||||||
#:use-module ((gnu packages package-management) #:select (rpm))
|
#:use-module ((gnu packages package-management) #:select (rpm))
|
||||||
#:use-module ((gnu packages compression) #:select (squashfs-tools))
|
#:use-module ((gnu packages compression) #:select (squashfs-tools))
|
||||||
|
@ -340,6 +342,42 @@ (define bin
|
||||||
(mkdir #$output))))))))
|
(mkdir #$output))))))))
|
||||||
(built-derivations (list check))))
|
(built-derivations (list check))))
|
||||||
|
|
||||||
|
(unless store (test-skip 1))
|
||||||
|
(test-assertm "appimage"
|
||||||
|
(mlet* %store-monad
|
||||||
|
((guile (set-guile-for-build (default-guile)))
|
||||||
|
(profile -> (profile
|
||||||
|
(content (packages->manifest (list %bootstrap-guile hello)))
|
||||||
|
(hooks '())
|
||||||
|
(locales? #f)))
|
||||||
|
(image (self-contained-appimage "hello-appimage" profile
|
||||||
|
#:entry-point "bin/hello"
|
||||||
|
#:extra-options
|
||||||
|
(list #:relocatable? #t)))
|
||||||
|
(check (gexp->derivation
|
||||||
|
"check-appimage"
|
||||||
|
#~(invoke #$image))))
|
||||||
|
(built-derivations (list check))))
|
||||||
|
|
||||||
|
(unless store (test-skip 1))
|
||||||
|
(test-assertm "appimage + localstatedir"
|
||||||
|
(mlet* %store-monad
|
||||||
|
((guile (set-guile-for-build (default-guile)))
|
||||||
|
(profile -> (profile
|
||||||
|
(content (packages->manifest (list %bootstrap-guile hello)))
|
||||||
|
(hooks '())
|
||||||
|
(locales? #f)))
|
||||||
|
(image (self-contained-appimage "hello-appimage" profile
|
||||||
|
#:entry-point "bin/hello"
|
||||||
|
#:localstatedir? #t
|
||||||
|
#:extra-options
|
||||||
|
(list #:relocatable? #t)))
|
||||||
|
(check (gexp->derivation
|
||||||
|
"check-appimage"
|
||||||
|
#~(begin
|
||||||
|
(invoke #$image)))))
|
||||||
|
(built-derivations (list check))))
|
||||||
|
|
||||||
(unless store (test-skip 1))
|
(unless store (test-skip 1))
|
||||||
(test-assertm "deb archive with symlinks and control files"
|
(test-assertm "deb archive with symlinks and control files"
|
||||||
(mlet* %store-monad
|
(mlet* %store-monad
|
||||||
|
|
Loading…
Reference in a new issue