From 694de2ac42ff85b313ab1d38fc502d9b86acb9d0 Mon Sep 17 00:00:00 2001 From: Peder Bergebakken Sundt Date: Sun, 1 Mar 2026 19:59:07 +0100 Subject: [PATCH 1/2] pulsar: 1.130.1 -> 1.131.1 Changelog: https://github.com/pulsar-edit/pulsar/blob/v1.131.1/CHANGELOG.md Blog: https://blog.pulsar-edit.dev/posts/20251202-savetheclocktower-pulsar-on-electron-30/ Release checklist: https://github.com/pulsar-edit/pulsar/issues/1431 --- doc/release-notes/rl-2605.section.md | 2 ++ pkgs/by-name/pu/pulsar/package.nix | 44 ++++++++++++++++------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/doc/release-notes/rl-2605.section.md b/doc/release-notes/rl-2605.section.md index adc8cb486bba..f00bfc74cb6a 100644 --- a/doc/release-notes/rl-2605.section.md +++ b/doc/release-notes/rl-2605.section.md @@ -89,6 +89,8 @@ - `forgejo` has been updated to major version 14. For more information, see the [release blog post](https://forgejo.org/2026-01-release-v14-0/) and [full release notes](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/release-notes-published/14.0.0.md) +- `pulsar` has finally migrated from electron v12 to v30, backup `~/.pulsar` before upgrading. See [Pulsar on Electron 30: what it means for you](https://blog.pulsar-edit.dev/posts/20251202-savetheclocktower-pulsar-on-electron-30/). + - `bartender` has been updated to major version 6. This removes support for MacOS Sonoma (and adds support for Tahoe). For more information, see [the release notes](https://www.macbartender.com/Bartender6/release_notes/) or [the Bartender 6 support page](https://www.macbartender.com/Bartender6/support/). - `lima` has been updated from `1.x` to `2.x`. This major update includes several breaking changes, such as `/tmp/lima` no longer being mounted by default. diff --git a/pkgs/by-name/pu/pulsar/package.nix b/pkgs/by-name/pu/pulsar/package.nix index 0e3e7149afe9..502315589fa8 100644 --- a/pkgs/by-name/pu/pulsar/package.nix +++ b/pkgs/by-name/pu/pulsar/package.nix @@ -44,14 +44,14 @@ let pname = "pulsar"; - version = "1.130.1"; + version = "1.131.1"; sourcesPath = { x86_64-linux.tarname = "Linux.${pname}-${version}.tar.gz"; - x86_64-linux.hash = "sha256-/s2sjGGDVOJ8cpIlgku+vt7DQI58IvM7jzMo61Vnq+E="; + x86_64-linux.hash = "sha256-Is+KAnPuHUrj87KFTjB/v/LMDflq4LbX3VP8Cv7/CNQ="; aarch64-linux.tarname = "ARM.Linux.${pname}-${version}-arm64.tar.gz"; - aarch64-linux.hash = "sha256-Psvx3oefvUtV5+gIt7xpB+k63c0073WejCFwVacV2+E="; + aarch64-linux.hash = "sha256-P2ZBV9Al6xw347yUs3BOWnwJGWegRh52oygLFgjoBcw="; } .${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); @@ -102,6 +102,16 @@ stdenv.mkDerivation { inherit hash; }; + # strip leading `.` from $0. + # for .pulsar.sh-wrapped to correctly set ATOM_BASE_NAME + # (`--argv0` shenanigans in makeWrapper does not work) + postPatch = '' + substituteInPlace resources/pulsar.sh \ + --replace-fail \ + 'ATOM_BASE_NAME=''${ATOM_BASE_NAME%.*}' \ + 'ATOM_BASE_NAME=''${ATOM_BASE_NAME%.*}; ATOM_BASE_NAME=''${ATOM_BASE_NAME#.}' + ''; + nativeBuildInputs = [ wrapGAppsHook3 copyDesktopItems @@ -181,12 +191,17 @@ stdenv.mkDerivation { unlink $dugite/git/libexec/git-core/git-lfs ln -s ${git-lfs}/bin/git-lfs $dugite/git/libexec/git-core/git-lfs '' - + lib.optionalString (stdenv.hostPlatform.system == "x86_64-linux") '' - # We have to patch a prebuilt binary in the asar archive + + lib.optionalString stdenv.hostPlatform.isLinux '' + # We have to patch prebuilt binaries in the asar archive # But asar complains because the node_gyp unpacked dependency uses a prebuilt Python3 itself + ( + shopt -s globstar - rm $opt/resources/app.asar.unpacked/node_modules/tree-sitter-bash/build/node_gyp_bins/python3 - ln -s ${python3.interpreter} $opt/resources/app.asar.unpacked/node_modules/tree-sitter-bash/build/node_gyp_bins/python3 + for python3_binary in $opt/resources/app.asar.unpacked/node_modules/**/build/node_gyp_bins/python3; do + rm -v "$python3_binary" + ln -sv ${python3.interpreter} "$python3_binary" + done + ) '' + '' # Patch the bundled node executables @@ -208,7 +223,7 @@ stdenv.mkDerivation { --suffix "PATH" : "${lib.makeBinPath [ coreutils ]}" \ --set "PULSAR_PATH" "$opt" ln -s $opt/resources/pulsar.sh $out/bin/pulsar - ln -s $opt/resources/app/ppm/bin/apm $out/bin/ppm + ln -s $opt/resources/app/ppm/bin/ppm $out/bin/ppm # Copy the icons mkdir -p $out/share/icons/hicolor/scalable/apps $out/share/icons/hicolor/1024x1024/apps @@ -255,15 +270,8 @@ stdenv.mkDerivation { bryango pbsds ]; - knownVulnerabilities = [ - # electron 12.2.3, efforts are in place to bump it - "CVE-2023-5217" - "CVE-2022-21718" - "CVE-2022-29247" - "CVE-2022-29257" - "CVE-2022-36077" - "CVE-2023-29198" - "CVE-2023-39956" - ]; + # https://www.electronjs.org/docs/latest/tutorial/electron-timelines + # a bump is expected (pulsar v1.131.0 bumped electron 12.2.3 -> 30.0.9 in february 2026) + knownVulnerabilities = [ "Electron version 30 is EOL" ]; }; } From e2a32f0cdd581159bd962a3a25df9d14defc6c96 Mon Sep 17 00:00:00 2001 From: Peder Bergebakken Sundt Date: Sun, 1 Mar 2026 20:58:26 +0100 Subject: [PATCH 2/2] pulsar: use finalAttrs, simplify update script --- pkgs/by-name/pu/pulsar/package.nix | 53 +++++++++------ pkgs/by-name/pu/pulsar/update.mjs | 106 ----------------------------- 2 files changed, 33 insertions(+), 126 deletions(-) delete mode 100755 pkgs/by-name/pu/pulsar/update.mjs diff --git a/pkgs/by-name/pu/pulsar/package.nix b/pkgs/by-name/pu/pulsar/package.nix index 502315589fa8..e2fcacc10542 100644 --- a/pkgs/by-name/pu/pulsar/package.nix +++ b/pkgs/by-name/pu/pulsar/package.nix @@ -1,6 +1,10 @@ { lib, stdenv, + writeShellScript, + nix-update, + curl, + jq, git, git-lfs, fetchurl, @@ -43,17 +47,6 @@ }: let - pname = "pulsar"; - version = "1.131.1"; - - sourcesPath = - { - x86_64-linux.tarname = "Linux.${pname}-${version}.tar.gz"; - x86_64-linux.hash = "sha256-Is+KAnPuHUrj87KFTjB/v/LMDflq4LbX3VP8Cv7/CNQ="; - aarch64-linux.tarname = "ARM.Linux.${pname}-${version}-arm64.tar.gz"; - aarch64-linux.hash = "sha256-P2ZBV9Al6xw347yUs3BOWnwJGWegRh52oygLFgjoBcw="; - } - .${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); newLibpath = lib.makeLibraryPath [ alsa-lib @@ -91,16 +84,27 @@ let hunspellCopyCommands = lib.concatMapStringsSep "\n" ( lang: "cp -r ${lang}/* ${hunspellTargetDirs};" ) hunspellDirs; + in -stdenv.mkDerivation { - inherit pname version; + +stdenv.mkDerivation (finalAttrs: { + pname = "pulsar"; + version = "1.131.1"; src = - with sourcesPath; - fetchurl { - url = "https://github.com/pulsar-edit/pulsar/releases/download/v${version}/${tarname}"; - inherit hash; + finalAttrs.passthru.srcs.${stdenv.hostPlatform.system} + or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); + + passthru.srcs = { + x86_64-linux = fetchurl { + url = "https://github.com/pulsar-edit/pulsar/releases/download/v${finalAttrs.version}/Linux.pulsar-${finalAttrs.version}.tar.gz"; + hash = "sha256-Is+KAnPuHUrj87KFTjB/v/LMDflq4LbX3VP8Cv7/CNQ="; }; + aarch64-linux = fetchurl { + url = "https://github.com/pulsar-edit/pulsar/releases/download/v${finalAttrs.version}/ARM.Linux.pulsar-${finalAttrs.version}-arm64.tar.gz"; + hash = "sha256-P2ZBV9Al6xw347yUs3BOWnwJGWegRh52oygLFgjoBcw="; + }; + }; # strip leading `.` from $0. # for .pulsar.sh-wrapped to correctly set ATOM_BASE_NAME @@ -253,7 +257,16 @@ stdenv.mkDerivation { }) ]; - passthru.updateScript = ./update.mjs; + passthru.updateScript = writeShellScript "update-pulsar" '' + set -euo pipefail + PATH="${lib.getBin curl}:$PATH" + PATH="${lib.getBin jq}:$PATH" + PATH="${lib.getBin coreutils}:$PATH" + PATH="${lib.getBin nix-update}:$PATH" + version="$(curl https://api.github.com/repos/pulsar-edit/pulsar/releases/latest | jq ".tag_name" -r | tr -d 'v')" + nix-update pkgsCross.gnu64.pulsar --version "$version" + nix-update pkgsCross.aarch64-multiplatform.pulsar --version skip + ''; meta = { description = "Community-led Hyper-Hackable Text Editor"; @@ -262,7 +275,7 @@ stdenv.mkDerivation { Designed to be deeply customizable, but still approachable using the default configuration. ''; homepage = "https://github.com/pulsar-edit/pulsar"; - changelog = "https://github.com/pulsar-edit/pulsar/blob/v${version}/CHANGELOG.md"; + changelog = "https://github.com/pulsar-edit/pulsar/blob/v${finalAttrs.version}/CHANGELOG.md"; sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; license = lib.licenses.mit; platforms = lib.platforms.linux; @@ -274,4 +287,4 @@ stdenv.mkDerivation { # a bump is expected (pulsar v1.131.0 bumped electron 12.2.3 -> 30.0.9 in february 2026) knownVulnerabilities = [ "Electron version 30 is EOL" ]; }; -} +}) diff --git a/pkgs/by-name/pu/pulsar/update.mjs b/pkgs/by-name/pu/pulsar/update.mjs deleted file mode 100755 index 215092faab02..000000000000 --- a/pkgs/by-name/pu/pulsar/update.mjs +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env nix-shell -/* -#!nix-shell -i node -p nodejs -*/ - -import { promises as fs } from 'node:fs'; - -const constants = { - githubUrl: "https://api.github.com/repos/pulsar-edit/pulsar/releases", - sha256FileURL: (newVersion) => `https://github.com/pulsar-edit/pulsar/releases/download/v${newVersion}/SHA256SUMS.txt`, - x86_64FileName: (newVersion) => `Linux.pulsar-${newVersion}.tar.gz`, - aarch64FileName: (newVersion) => `ARM.Linux.pulsar-${newVersion}-arm64.tar.gz`, - targetFile: new URL("package.nix", import.meta.url).pathname, -}; - -async function utf16ToUtf8(blob) { - // Sometime, upstream saves the SHA256SUMS.txt file in UTF-16, which absolutely breaks node's string handling - // So we need to convert this blob to UTF-8 - - // We need to skip the first 2 bytes, which are the BOM - const arrayBuffer = await blob.slice(2).arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - const utf8String = buffer.toString('utf16le'); - return utf8String; -} - -async function getLatestVersion() { - const requestResult = await fetch(constants.githubUrl); - if (!requestResult.ok) { - console.error("Failed to fetch releases"); - console.error(requestResult); - process.exit(1); - }; - let jsonResult = await requestResult.json(); - - jsonResult = jsonResult.filter((release) => !release.prerelease && !release.draft); - if (jsonResult.length == 0) { - console.error("No releases found"); - process.exit(1); - } - - return jsonResult[0].tag_name.replace(/^v/, ''); -} - -async function getSha256Sum(hashFileContent, targetFile) { - // The upstream file has a fomat like this: - // 0000000000000000000000000000000000000000000000000000000000000000 targetFile - - let sha256 = hashFileContent. - split('\n'). - map(line => line.replace("\r", "")). // Side-effect of the UTF-16 conversion, if the file was created from Windows - filter((line) => line.endsWith(targetFile))[0]. - split(' ')[0]; - - return "sha256-" + Buffer.from(sha256, 'hex').toString('base64'); -} - -async function getSha256Sums(newVersion) { - // Upstream provides a file with the hashes of the files, but it's not in the SRI format, and it refers to the compressed tarball - // So let's just use nix-prefetch-url to get the hashes of the decompressed tarball, and `nix hash to-sri` to convert them to SRI format - const hashFileUrl = constants.sha256FileURL(newVersion); - const hashFileContent = await fetch(hashFileUrl).then((response) => response.blob()); - const headerbuffer = await hashFileContent.slice(0, 2).arrayBuffer() - const header = Buffer.from(headerbuffer).toString('hex'); - - // We must detect if it's UTF-16 or UTF-8. If it's UTF-16, we must convert it to UTF-8, otherwise just use it as-is - const hashFileContentString = header == 'fffe' ? - await utf16ToUtf8(hashFileContent) : - await hashFileContent.text(); - - let x86_64; - let aarch64; - console.log("Getting new hashes"); - let promises = [ - getSha256Sum(hashFileContentString, constants.x86_64FileName(newVersion)).then((hash) => { x86_64 = hash; }), - getSha256Sum(hashFileContentString, constants.aarch64FileName(newVersion)).then((hash) => { aarch64 = hash; }), - ]; - await Promise.all(promises); - return { x86_64, aarch64 }; -} - -async function updateFile(newVersion, sha256Sums, currentFile) { - // There is some assumptions in how the file is formatted, but nothing egregious - - let newFile = currentFile.replace(/version = "(.*)";/, `version = "${newVersion}";`); - newFile = newFile.replace(/x86_64-linux\.hash = "(.*)";/, `x86_64-linux.hash = "${sha256Sums.x86_64}";`); - newFile = newFile.replace(/aarch64-linux\.hash = "(.*)";/, `aarch64-linux.hash = "${sha256Sums.aarch64}";`); - - await fs.writeFile(constants.targetFile, newFile); -}; - -let currentFile = await fs.readFile(constants.targetFile, 'utf8'); -let currentVersion = currentFile.match(/version = "(.*)";/)[1]; -const newVersion = await getLatestVersion(); -if (currentVersion === newVersion) { - console.error("Already up to date"); - process.exit(0); -} -console.log("New version: " + newVersion); -const sha256Sums = await getSha256Sums(newVersion); -console.log(sha256Sums) -if (!sha256Sums.x86_64 || !sha256Sums.aarch64) { - console.error("Failed to find sha256 sums for the 2 files"); - process.exit(1); -} -updateFile(newVersion, sha256Sums, currentFile);