forked from ralismark/nix-appimage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flake.nix
161 lines (145 loc) · 5.83 KB
/
flake.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
{
description = "AppImage bundler";
inputs = {
nixpkgs.url = "nixpkgs/nixos-22.05";
flake-utils.url = "github:numtide/flake-utils";
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
appimage-runtime = {
url = "github:AppImageCrafters/appimage-runtime";
flake = false;
};
squashfuse = {
url = "github:vasi/squashfuse";
flake = false;
};
};
outputs = { self, nixpkgs, flake-utils, ... }@inputs:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = (import nixpkgs {
inherit system;
}).pkgsStatic;
# nixpkgs has an old version so we need to package our own
own-squashfuse = pkgs.stdenv.mkDerivation {
name = "squashfuse";
src = inputs.squashfuse;
nativeBuildInputs = with pkgs; [ autoreconfHook libtool pkg-config ];
buildInputs = with pkgs; [ lz4 xz zlib lzo zstd fuse ];
};
in
rec {
packages.apprun = pkgs.runCommandCC "AppRun" { } ''
$CC ${./apprun.c} -Werror -o $out
'';
packages.runtime =
let
git-commit = "0000000";
in
pkgs.runCommandCC "runtime"
{
nativeBuildInputs = with pkgs; [ pkg-config ];
buildInputs = with pkgs; [
fuse
own-squashfuse
zstd
zlib
lzma
lz4
lzo
];
} ''
NIX_CFLAGS_COMPILE="$(pkg-config --cflags fuse) $NIX_CFLAGS_COMPILE"
# extra includes to make things work
mkdir -p include/squashfuse
echo "#include_next <squashfuse/squashfuse.h>" > include/squashfuse/squashfuse.h
cp ${inputs.squashfuse}/fuseprivate.h -t include/squashfuse
$CC ${inputs.appimage-runtime}/src/main.c -o $out \
-I./include -D_FILE_OFFSET_BITS=64 -DGIT_COMMIT='"${git-commit}"' \
-lfuse -lsquashfuse_ll -lzstd -lz -llzma -llz4 -llzo2 \
-T ${inputs.appimage-runtime}/src/data_sections.ld
# Add AppImage Type 2 Magic Bytes to runtime
printf %b '\x41\x49\x02' > magic_bytes
dd if=magic_bytes of=$out bs=1 count=3 seek=8 conv=notrunc status=none
'';
# Produce an (probably non-conforming) AppImage.
#
# The AppImage type 2 format is simply the runtime binary concatenated
# with a squashfs. When running the AppImage, the squashfs binary is
# extracted/mounted at an arbitrary place and the AppRun binary within
# run.
#
# The `exclude` argument, if supplied, enables excluding files from the
# final squashfs image. Globs are supported. See `mksquashfs(1)` for for
# details.
mkappimage = { drv, entrypoint, name, exclude ? [] }:
let
arch = builtins.head (builtins.split "-" system);
closure = pkgs.writeReferencesToFile drv;
extras = [
"AppRun f 555 0 0 cat ${packages.apprun}"
"entrypoint s 555 0 0 ${entrypoint}"
"mountroot d 777 0 0" # TODO permissions?
];
extra-args = pkgs.lib.concatMapStrings (x: " -p \"${x}\"") extras;
exclude-args = pkgs.lib.optionalString (exclude != []) " -wildcards -e ${pkgs.lib.escapeShellArgs exclude}";
in
pkgs.runCommand "${name}-${arch}.AppImage"
{
nativeBuildInputs = with pkgs; [ squashfsTools ];
} ''
mksquashfs $(cat ${closure}) $out \
-no-strip \
-offset $(stat -L -c%s ${packages.runtime}) \
-comp zstd \
-all-root \
-noappend \
-b 1M \
${extra-args} \
${exclude-args}
dd if=${packages.runtime} of=$out conv=notrunc
chmod 755 $out
'';
bundlers.default =
let
basename = p: pkgs.lib.lists.last (builtins.split "/" p);
mainProgram = drv:
if drv?meta && drv.meta?mainProgram then drv.meta.mainProgram
else (builtins.parseDrvName (builtins.unsafeDiscardStringContext drv.name)).name;
program = drv:
let
# Use same auto-detect that <https://github.com/NixOS/bundlers>
# uses. This isn't 100% accurate and might pick the wrong name
# (e.g. nixpkgs#mesa-demos), so we do an additional check to
# make sure the target exists
main =
if drv?meta && drv.meta?mainProgram then drv.meta.mainProgram
else (builtins.parseDrvName (builtins.unsafeDiscardStringContext drv.name)).name;
mainPath = "${drv}/bin/${main}";
# builtins.pathExists mainPath doesn't work consistently (e.g.
# for symlinks), but this does
mainPathExists = builtins.hasAttr main (builtins.readDir "${drv}/bin");
in
assert pkgs.lib.assertMsg mainPathExists "main program ${mainPath} does not exist";
mainPath;
handler = {
app = drv: mkappimage {
drv = drv.program;
entrypoint = drv.program;
name = basename drv.program;
};
derivation = drv: mkappimage {
drv = drv;
entrypoint = program drv;
name = drv.name;
};
};
known-types = builtins.concatStringsSep ", " (builtins.attrNames handler);
in
drv:
assert pkgs.lib.assertMsg (handler ? ${drv.type}) "don't know how to make app image for type '${drv.type}'; only know ${known-types}";
handler.${drv.type} drv;
});
}