diff --git a/flake.nix b/flake.nix index 24eca11..dc5dac8 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,7 @@ lib = import ./lib-overlay.nix; rust = import ./rust-overlay.nix; firefox = import ./firefox-overlay.nix; + thunderbird = import ./thunderbird-overlay.nix; git-cinnabar = import ./git-cinnabar-overlay.nix; }; }; diff --git a/overlays.nix b/overlays.nix index c94f781..27f024b 100644 --- a/overlays.nix +++ b/overlays.nix @@ -2,5 +2,6 @@ ./lib-overlay.nix ./rust-overlay.nix ./firefox-overlay.nix + ./thunderbird-overlay.nix ./git-cinnabar-overlay.nix ] diff --git a/thunderbird-overlay.nix b/thunderbird-overlay.nix new file mode 100644 index 0000000..fdcb3b1 --- /dev/null +++ b/thunderbird-overlay.nix @@ -0,0 +1,233 @@ +# This file provide the latest binary versions of Thunderbird published by Mozilla. +# It is a slightly modified version of firefox-overlay.nix +self: super: + +let + # This URL needs to be updated about every 2 years when the subkey is rotated. + pgpKey = super.fetchurl { + url = "https://download.cdn.mozilla.net/pub/thunderbird/releases/115.0/KEY"; + sha256 = "2c67dd09f369a7c1d3a9e139455e5c8d40be8cc04441a790a103019900fd194d"; + }; + + # This file is currently maintained manually, if this Nix expression attempt + # to download the wrong version, this is likely to be the problem. + # + # Open a pull request against https://github.com/mozilla-releng/ship-it/ to + # update the version, as done in + # https://github.com/mozilla-releng/ship-it/pull/182 + thunderbird_versions = with builtins; + fromJSON (readFile (fetchurl "https://product-details.mozilla.org/1.0/thunderbird_versions.json")); + + arch = if self.stdenv.system == "i686-linux" + then "linux-i686" + else "linux-x86_64"; + + yearOf = with super.lib; yyyymmddhhmmss: + head (splitString "-" yyyymmddhhmmss); + monthOf = with super.lib; yyyymmddhhmmss: + head (tail (splitString "-" yyyymmddhhmmss)); + + # Given SHA512SUMS file contents and file name, extract matching sha512sum. + extractSha512Sum = sha512sums: file: + with builtins; + # Nix 1.x do not have `builtins.split`. + # Nix 2.0 have an bug in `builtins.match` (see https://github.com/NixOS/nix/issues/2147). + # So I made separate logic for Nix 1.x and Nix 2.0. + if builtins ? split then + substring 0 128 (head + (super.lib.filter + (s: isString s && substring 128 (stringLength s) s == " ${file}") + (split "\n" sha512sums))) + else + head (match ".*[\n]([0-9a-f]*) ${file}.*" sha512sums); + + # The timestamp argument is a yyyy-mm-dd-hh-mm-ss date, which corresponds to + # one specific version. This is used mostly for bisecting. + versionInfo = { name, version, release, system ? arch, timestamp ? null, info ? null, ... }: with builtins; + if (info != null) then info else + if release then + # For versions such as Beta & Release: + # https://download.cdn.mozilla.net/pub/thunderbird/releases/55.0b3/SHA256SUMS + let + dir = "https://download.cdn.mozilla.net/pub/thunderbird/releases/${version}"; + file = "${system}/en-US/thunderbird-${version}.tar.bz2"; + sha512Of = chksum: file: extractSha512Sum (readFile (fetchurl chksum)) file; + in rec { + chksum = "${dir}/SHA512SUMS"; + chksumSig = "${chksum}.asc"; + chksumSha256 = hashFile "sha256" (fetchurl "${dir}/SHA512SUMS"); + chksumSigSha256 = hashFile "sha256" (fetchurl "${chksum}.asc"); + inherit file; + url = "${dir}/${file}"; + sha512 = sha512Of chksum file; + sig = null; + sigSha512 = null; + } + else + # For Daily versions: + # https://download.cdn.mozilla.net/pub/thunderbird/nightly/latest-comm-central/thunderbird-56.0a1.en-US.linux-x86_64.checksums + let + dir = + if timestamp == null then + let + buildhubJSON = with builtins; + fromJSON (readFile (fetchurl "https://download.cdn.mozilla.net/pub/thunderbird/nightly/latest-comm-central/thunderbird-${version}.en-US.${system}.buildhub.json")); + in builtins.replaceStrings [ "/${file}" ] [ "" ] buildhubJSON.download.url + else "https://download.cdn.mozilla.net/pub/thunderbird/nightly/${yearOf timestamp}/${monthOf timestamp}/${timestamp}-mozilla-central" ; + file = "thunderbird-${version}.en-US.${system}.tar.bz2"; + sha512Of = chksum: file: head (match ".*[\n]([0-9a-f]*) sha512 [0-9]* ${file}[\n].*" (readFile (fetchurl chksum))); + in rec { + chksum = "${dir}/thunderbird-${version}.en-US.${system}.checksums"; + chksumSig = null; + # file content: + # sha512 62733881 thunderbird-56.0a1.en-US.linux-x86_64.tar.bz2 + # sha256 62733881 thunderbird-56.0a1.en-US.linux-x86_64.tar.bz2 + url = "${dir}/${file}"; + sha512 = sha512Of chksum file; + sig = "${dir}/${file}.asc"; + sigSha512 = sha512Of chksum "${file}.asc"; + }; + + # From the version info, check the authenticity of the check sum file, such + # that we guarantee that we have + verifyFileAuthenticity = { file, sha512, chksum, chksumSig }: + assert extractSha512Sum (builtins.readFile chksum) file == sha512; + super.runCommand "check-thunderbird-signature" { + buildInputs = [ self.gnupg ]; + FILE = chksum; + ASC = chksumSig; + } '' + set -eu + gpg --dearmor < ${pgpKey} > keyring.gpg + gpgv --keyring=./keyring.gpg $ASC $FILE + mkdir $out + ''; + + # From the version info, create a fetchurl derivation which will get the + # sources from the remote. + fetchVersion = info: + if info.chksumSig != null then + super.fetchurl { + inherit (info) url sha512; + + # This is a fixed derivation, but we still add as a dependency the + # verification of the checksum. Thus, this fetch script can only be + # executed once the verifyAuthenticity script finished successfully. + postFetch = '' + : # Authenticity Check (${verifyFileAuthenticity { + inherit (info) file sha512; + chksum = builtins.fetchurl { url = info.chksum; sha256 = info.chksumSha256; }; + chksumSig = builtins.fetchurl { url = info.chksumSig; sha256 = info.chksumSigSha256; }; + }}) + ''; + } + else + super.fetchurl { + inherit (info) url sha512; + + # This would download the tarball, and then verify that the content + # match the signature file. Fortunately, any failure of this code would + # prevent the output from being reused. + postFetch = + let asc = super.fetchurl { url = info.sig; sha512 = info.sigSha512; }; in '' + : # Authenticity Check + set -eu + export PATH="$PATH:${self.gnupg}/bin/" + gpg --dearmor < ${pgpKey} > keyring.gpg + gpgv --keyring=./keyring.gpg ${asc} $out + ''; + }; + + thunderbirdVersion = version: + let + info = versionInfo version; + pkg = ((self.thunderbird-bin-unwrapped.override { + generated = { + version = version.version; + sources = { inherit (info) url sha512; }; + }; + # channel = version.channel; + }).overrideAttrs (old: { + # Add a dependency on the signature check. + src = fetchVersion info; + + # inject hacked up patchelf to not break binaries + nativeBuildInputs = old.nativeBuildInputs or [] ++ [ + (self.callPackage ./pkgs/patchelf {}) + ]; + })); + in super.wrapThunderbird pkg { + pname = "${pkg.binaryName}-bin"; + desktopName = version.name; + wmClass = version.wmClass; + }; + + thunderbirdVariants = { + thunderbird-daily-bin = { + name = "Thunderbird Daily"; + channel = "nightly"; + wmClass = "thunderbird-daily"; + version = thunderbird_versions.LATEST_THUNDERBIRD_NIGHTLY_VERSION; + release = false; + }; + thunderbird-beta-bin = { + name = "Thunderbird Beta"; + channel = "beta"; + wmClass = "thunderbird-beta"; + version = thunderbird_versions.LATEST_THUNDERBIRD_DEVEL_VERSION; + release = true; + }; + thunderbird-bin = { + name = "Thunderbird"; + channel = "release"; + wmClass = "thunderbird"; + version = thunderbird_versions.LATEST_THUNDERBIRD_VERSION; + release = true; + }; + }; +in + +{ + lib = super.lib // { + thunderbirdOverlay = { + inherit pgpKey thunderbirdVersion versionInfo thunderbird_versions thunderbirdVariants; + }; + }; + + # Set of packages which are automagically updated. Do not rely on these for + # reproducible builds. + latest = (super.latest or {}) // (builtins.mapAttrs (n: v: thunderbirdVersion v) thunderbirdVariants); + + # Set of packages which used to build developer environment + devEnv = (super.shell or {}) // { + gecko = super.callPackage ./pkgs/gecko { + inherit (self.python38Packages) setuptools; + pythonFull = self.python38Full; + nodejs = + if builtins.compareVersions self.nodejs.name "nodejs-8.11.3" < 0 + then self.nodejs-8_x else self.nodejs; + + rust-cbindgen = + if !(self ? "rust-cbindgen") then self.rust-cbindgen-latest + else if builtins.compareVersions self.rust-cbindgen.version self.rust-cbindgen-latest.version < 0 + then self.rust-cbindgen-latest else self.rust-cbindgen; + + # Due to std::ascii::AsciiExt changes in 1.23, Gecko does not compile, so + # use the latest Rust version before 1.23. + # rust = (super.rustChannelOf { channel = "stable"; date = "2017-11-22"; }).rust; + # rust = (super.rustChannelOf { channel = "stable"; date = "2020-03-12"; }).rust; + inherit (self.latest.rustChannels.stable) rust; + }; + }; + + # Use rust-cbindgen imported from Nixpkgs (September 2018) unless the current + # version of Nixpkgs already packages a version of rust-cbindgen. + rust-cbindgen-latest = super.callPackage ./pkgs/cbindgen { + rustPlatform = super.makeRustPlatform { + cargo = self.latest.rustChannels.stable.rust; + rustc = self.latest.rustChannels.stable.rust; + }; + }; + + jsdoc = super.callPackage ./pkgs/jsdoc {}; +}