lol
1{ lib
2, stdenv
3, chromium
4, nodejs
5, python3
6, fetchYarnDeps
7, fetchNpmDeps
8, fixup-yarn-lock
9, npmHooks
10, yarn
11, substituteAll
12, libnotify
13, unzip
14, pkgs
15, pkgsBuildHost
16, pipewire
17, libsecret
18, libpulseaudio
19, speechd
20, info
21}:
22
23let
24 fetchdep = dep: let
25 opts = removeAttrs dep ["fetcher"];
26 in pkgs.${dep.fetcher} opts;
27
28 fetchedDeps = lib.mapAttrs (name: fetchdep) info.deps;
29
30in (chromium.override { upstream-info = info.chromium; }).mkDerivation (base: {
31 packageName = "electron";
32 inherit (info) version;
33 buildTargets = [ "electron:electron_dist_zip" ];
34
35 nativeBuildInputs = base.nativeBuildInputs ++ [ nodejs yarn fixup-yarn-lock unzip npmHooks.npmConfigHook ];
36 buildInputs = base.buildInputs ++ [ libnotify ];
37
38 electronOfflineCache = fetchYarnDeps {
39 yarnLock = fetchedDeps."src/electron" + "/yarn.lock";
40 sha256 = info.electron_yarn_hash;
41 };
42 npmDeps = fetchNpmDeps rec {
43 src = fetchedDeps."src";
44 # Assume that the fetcher always unpack the source,
45 # based on update.py
46 sourceRoot = "${src.name}/third_party/node";
47 hash = info.chromium_npm_hash;
48 };
49
50 src = null;
51
52 patches = base.patches ++ lib.optional (lib.versionAtLeast info.version "29" && lib.versionOlder info.version "30")
53 (substituteAll {
54 # disable a component that requires CIPD blobs
55 name = "disable-screen-ai.patch";
56 src = ./disable-screen-ai.patch;
57 inherit (info) version;
58 })
59 ;
60
61 unpackPhase = ''
62 runHook preUnpack
63 '' + (
64 lib.concatStrings (lib.mapAttrsToList (path: dep: ''
65 mkdir -p ${builtins.dirOf path}
66 cp -r ${dep}/. ${path}
67 chmod u+w -R ${path}
68 '') fetchedDeps)
69 ) + ''
70 sourceRoot=src
71 runHook postUnpack
72 '';
73
74 npmRoot = "third_party/node";
75
76 postPatch = ''
77 mkdir -p third_party/jdk/current/bin
78
79 echo 'build_with_chromium = true' >> build/config/gclient_args.gni
80 echo 'checkout_google_benchmark = false' >> build/config/gclient_args.gni
81 echo 'checkout_android = false' >> build/config/gclient_args.gni
82 echo 'checkout_android_prebuilts_build_tools = false' >> build/config/gclient_args.gni
83 echo 'checkout_android_native_support = false' >> build/config/gclient_args.gni
84 echo 'checkout_ios_webkit = false' >> build/config/gclient_args.gni
85 echo 'checkout_nacl = false' >> build/config/gclient_args.gni
86 echo 'checkout_openxr = false' >> build/config/gclient_args.gni
87 echo 'checkout_rts_model = false' >> build/config/gclient_args.gni
88 echo 'checkout_src_internal = false' >> build/config/gclient_args.gni
89 echo 'cros_boards = ""' >> build/config/gclient_args.gni
90 echo 'cros_boards_with_qemu_images = ""' >> build/config/gclient_args.gni
91 echo 'generate_location_tags = true' >> build/config/gclient_args.gni
92
93 echo 'LASTCHANGE=${info.deps."src".rev}-refs/heads/master@{#0}' > build/util/LASTCHANGE
94 echo "$SOURCE_DATE_EPOCH" > build/util/LASTCHANGE.committime
95
96 cat << EOF > gpu/config/gpu_lists_version.h
97 /* Generated by lastchange.py, do not edit.*/
98 #ifndef GPU_CONFIG_GPU_LISTS_VERSION_H_
99 #define GPU_CONFIG_GPU_LISTS_VERSION_H_
100 #define GPU_LISTS_VERSION "${info.deps."src".rev}"
101 #endif // GPU_CONFIG_GPU_LISTS_VERSION_H_
102 EOF
103
104 cat << EOF > skia/ext/skia_commit_hash.h
105 /* Generated by lastchange.py, do not edit.*/
106 #ifndef SKIA_EXT_SKIA_COMMIT_HASH_H_
107 #define SKIA_EXT_SKIA_COMMIT_HASH_H_
108 #define SKIA_COMMIT_HASH "${info.deps."src/third_party/skia".rev}-"
109 #endif // SKIA_EXT_SKIA_COMMIT_HASH_H_
110 EOF
111
112 echo -n '${info.deps."src/third_party/dawn".rev}' > gpu/webgpu/DAWN_VERSION
113
114 (
115 cd electron
116 export HOME=$TMPDIR/fake_home
117 yarn config --offline set yarn-offline-mirror $electronOfflineCache
118 fixup-yarn-lock yarn.lock
119 yarn install --offline --frozen-lockfile --ignore-scripts --no-progress --non-interactive
120 )
121
122 (
123 cd ..
124 PATH=$PATH:${lib.makeBinPath (with pkgsBuildHost; [ jq git ])}
125 config=src/electron/patches/config.json
126 for entry in $(cat $config | jq -c ".[]")
127 do
128 patch_dir=$(echo $entry | jq -r ".patch_dir")
129 repo=$(echo $entry | jq -r ".repo")
130 for patch in $(cat $patch_dir/.patches)
131 do
132 echo applying in $repo: $patch
133 git apply -p1 --directory=$repo --exclude='src/third_party/blink/web_tests/*' --exclude='src/content/test/data/*' $patch_dir/$patch
134 done
135 done
136 )
137 '' + base.postPatch;
138
139 preConfigure = ''
140 (
141 cd third_party/node
142 grep patch update_npm_deps | sh
143 )
144 '' + (base.preConfigure or "");
145
146 gnFlags = rec {
147 # build/args/release.gn
148 is_component_build = false;
149 is_official_build = true;
150 rtc_use_h264 = proprietary_codecs;
151 is_component_ffmpeg = true;
152
153 # build/args/all.gn
154 is_electron_build = true;
155 root_extra_deps = [ "//electron" ];
156 node_module_version = info.modules;
157 v8_promise_internal_field_count = 1;
158 v8_embedder_string = "-electron.0";
159 v8_enable_snapshot_native_code_counters = false;
160 v8_enable_javascript_promise_hooks = true;
161 enable_cdm_host_verification = false;
162 proprietary_codecs = true;
163 ffmpeg_branding = "Chrome";
164 enable_printing = true;
165 angle_enable_vulkan_validation_layers = false;
166 dawn_enable_vulkan_validation_layers = false;
167 enable_pseudolocales = false;
168 allow_runtime_configurable_key_storage = true;
169 enable_cet_shadow_stack = false;
170 is_cfi = false;
171 use_qt = false;
172 use_perfetto_client_library = false;
173 v8_builtins_profiling_log_file = "";
174 enable_dangling_raw_ptr_checks = false;
175 } // lib.optionalAttrs (lib.versionAtLeast info.version "28") {
176 dawn_use_built_dxc = false;
177 v8_enable_private_mapping_fork_optimization = true;
178 } // lib.optionalAttrs (lib.versionAtLeast info.version "29") {
179 v8_expose_public_symbols = true;
180 } // {
181
182 # other
183 enable_widevine = false;
184 override_electron_version = info.version;
185 };
186
187 installPhase = ''
188 runHook preInstall
189
190 mkdir -p $libExecPath
191 unzip -d $libExecPath out/Release/dist.zip
192
193 runHook postInstall
194 '';
195
196 postFixup =
197 let
198 libPath = lib.makeLibraryPath [
199 libnotify
200 pipewire
201 stdenv.cc.cc.lib
202 libsecret
203 libpulseaudio
204 speechd
205 ];
206 in
207 base.postFixup + ''
208 patchelf \
209 --add-rpath "${libPath}" \
210 $out/libexec/electron/electron
211 '';
212
213 requiredSystemFeatures = [ "big-parallel" ];
214
215 passthru = {
216 inherit info fetchedDeps;
217 headers = stdenv.mkDerivation rec {
218 name = "node-v${info.node}-headers.tar.gz";
219 nativeBuildInputs = [ python3 ];
220 src = fetchedDeps."src/third_party/electron_node";
221 buildPhase = ''
222 runHook preBuild
223 make tar-headers
224 runHook postBuild
225 '';
226 installPhase = ''
227 runHook preInstall
228 mv ${name} $out
229 runHook postInstall
230 '';
231 };
232 };
233
234 meta = with lib; {
235 description = "Cross platform desktop application shell";
236 homepage = "https://github.com/electron/electron";
237 platforms = lib.platforms.linux;
238 license = licenses.mit;
239 maintainers = with maintainers; [ yayayayaka ];
240 mainProgram = "electron";
241 hydraPlatforms = lib.optionals (!(hasInfix "alpha" info.version) && !(hasInfix "beta" info.version)) ["aarch64-linux" "x86_64-linux"];
242 timeout = 172800; # 48 hours (increased from the Hydra default of 10h)
243 };
244})