diff --git a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.hashes.json b/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.hashes.json deleted file mode 100644 index e9ad1c327f4f..000000000000 --- a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.hashes.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob_10jwvS-FGJCMY.ttf": "sha256-B8XBpYycOYBjrhjlnyiz42YukIoOjGTd3NN3EY00NiQ=", - "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf": "sha256-Zfwh9q2GrL5Dwp+J/8Ddd2IXCaUXpQ7dE3CqgCMMyPs=", - "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-Z0jwvS-FGJCMY.ttf": "sha256-/O5b2DzM8g97NAdJgIC/RsQ7E5P7USKq7TXyDuUE3WQ=", - "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob911TwvS-FGJCMY.ttf": "sha256-vrjB8GlhzWAe6jG/Srpy8R431VivNtWbCa5Uh4ATnmU=", - "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob9M1TwvS-FGJCMY.ttf": "sha256-EbnZt8h4Lcl0yJoOKmXlF1nfcP5hZv7n4cEQ10yBkcg=" -} diff --git a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.json b/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.json deleted file mode 100644 index c729634b9e1e..000000000000 --- a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "kind": "webfonts#webfontList", - "items": [ - { - "family": "Noto Emoji", - "variants": [ - "300", - "regular", - "500", - "600", - "700" - ], - "subsets": [ - "emoji" - ], - "version": "v47", - "lastModified": "2023-09-27", - "files": { - "300": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob_10jwvS-FGJCMY.ttf", - "regular": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf", - "500": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-Z0jwvS-FGJCMY.ttf", - "600": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob911TwvS-FGJCMY.ttf", - "700": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob9M1TwvS-FGJCMY.ttf" - }, - "category": "sans-serif", - "kind": "webfonts#webfont", - "menu": "http://fonts.gstatic.com/s/notoemoji/v47/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0gwuQeU.ttf" - } - ] -} diff --git a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.py b/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.py deleted file mode 100755 index 9f1eadd95bca..000000000000 --- a/pkgs/by-name/no/noto-fonts-monochrome-emoji/noto-emoji.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env nix-shell -#! nix-shell -i "python3 -I" -p python3 - -from contextlib import contextmanager -from pathlib import Path -from typing import Iterable, Optional -from urllib import request - -import hashlib, json - - -def getMetadata(apiKey: str, family: str = "Noto Emoji"): - '''Fetch the Google Fonts metadata for a given family. - - An API key can be obtained by anyone with a Google account (🚮) from - `https://developers.google.com/fonts/docs/developer_api#APIKey` - ''' - from urllib.parse import urlencode - - with request.urlopen( - "https://www.googleapis.com/webfonts/v1/webfonts?" + - urlencode({ 'key': apiKey, 'family': family }) - ) as req: - return json.load(req) - -def getUrls(metadata) -> Iterable[str]: - '''Fetch all files' URLs from Google Fonts' metadata. - - The metadata must obey the API v1 schema, and can be obtained from: - https://www.googleapis.com/webfonts/v1/webfonts?key=${GOOGLE_FONTS_TOKEN}&family=${FAMILY} - ''' - return ( url for i in metadata['items'] for _, url in i['files'].items() ) - - -def hashUrl(url: str, *, hash: str = 'sha256'): - '''Compute the hash of the data from HTTP GETing a given `url`. - - The `hash` must be an algorithm name `hashlib.new` accepts. - ''' - with request.urlopen(url) as req: - return hashlib.new(hash, req.read()) - - -def sriEncode(h) -> str: - '''Encode a hash in the SRI format. - - Takes a `hashlib` object, and produces a string that - nixpkgs' `fetchurl` accepts as `hash` parameter. - ''' - from base64 import b64encode - return f"{h.name}-{b64encode(h.digest()).decode()}" - -def validateSRI(sri: Optional[str]) -> Optional[str]: - '''Decode an SRI hash, return `None` if invalid. - - This is not a full SRI hash parser, hash options aren't supported. - ''' - from base64 import b64decode - - if sri is None: - return None - - try: - hashName, b64 = sri.split('-', 1) - - h = hashlib.new(hashName) - digest = b64decode(b64, validate=True) - assert len(digest) == h.digest_size - - except: - return None - else: - return sri - - -def hashUrls( - urls: Iterable[str], - knownHashes: dict[str, str] = {}, -) -> dict[str, str]: - '''Generate a `dict` mapping URLs to SRI-encoded hashes. - - The `knownHashes` optional parameter can be used to avoid - re-downloading files whose URL have not changed. - ''' - return { - url: validateSRI(knownHashes.get(url)) or sriEncode(hashUrl(url)) - for url in urls - } - - -@contextmanager -def atomicFileUpdate(target: Path): - '''Atomically replace the contents of a file. - - Yields an open file to write into; upon exiting the context, - the file is closed and (atomically) replaces the `target`. - - Guarantees that the `target` was either successfully overwritten - with new content and no exception was raised, or the temporary - file was cleaned up. - ''' - from tempfile import mkstemp - fd, _p = mkstemp( - dir = target.parent, - prefix = target.name, - ) - tmpPath = Path(_p) - - try: - with open(fd, 'w') as f: - yield f - - tmpPath.replace(target) - - except Exception: - tmpPath.unlink(missing_ok = True) - raise - - -if __name__ == "__main__": - from os import environ - from urllib.error import HTTPError - - environVar = 'GOOGLE_FONTS_TOKEN' - currentDir = Path(__file__).parent - metadataPath = currentDir / 'noto-emoji.json' - - try: - apiToken = environ[environVar] - metadata = getMetadata(apiToken) - - except (KeyError, HTTPError) as exn: - # No API key in the environment, or the query was rejected. - match exn: - case KeyError if exn.args[0] == environVar: - print(f"No '{environVar}' in the environment, " - "skipping metadata update") - - case HTTPError if exn.getcode() == 403: - print("Got HTTP 403 (Forbidden)") - if apiToken != '': - print("Your Google API key appears to be valid " - "but does not grant access to the fonts API.") - print("Aborting!") - raise SystemExit(1) - - case HTTPError if exn.getcode() == 400: - # Printing the supposed token should be fine, as this is - # what the API returns on invalid tokens. - print(f"Got HTTP 400 (Bad Request), is this really an API token: '{apiToken}' ?") - case _: - # Unknown error, let's bubble it up - raise - - # In that case just use the existing metadata - with metadataPath.open() as metadataFile: - metadata = json.load(metadataFile) - - lastModified = metadata["items"][0]["lastModified"]; - print(f"Using metadata from file, last modified {lastModified}") - - else: - # If metadata was successfully fetched, validate and persist it - lastModified = metadata["items"][0]["lastModified"]; - print(f"Fetched current metadata, last modified {lastModified}") - with atomicFileUpdate(metadataPath) as metadataFile: - json.dump(metadata, metadataFile, indent = 2) - metadataFile.write("\n") # Pacify nixpkgs' dumb editor config check - - hashPath = currentDir / 'noto-emoji.hashes.json' - try: - with hashPath.open() as hashFile: - hashes = json.load(hashFile) - except FileNotFoundError: - hashes = {} - - with atomicFileUpdate(hashPath) as hashFile: - json.dump( - hashUrls(getUrls(metadata), knownHashes = hashes), - hashFile, - indent = 2, - ) - hashFile.write("\n") # Pacify nixpkgs' dumb editor config check diff --git a/pkgs/by-name/no/noto-fonts-monochrome-emoji/package.nix b/pkgs/by-name/no/noto-fonts-monochrome-emoji/package.nix index 08f78b613efc..1cf7b6c5fcdb 100644 --- a/pkgs/by-name/no/noto-fonts-monochrome-emoji/package.nix +++ b/pkgs/by-name/no/noto-fonts-monochrome-emoji/package.nix @@ -1,46 +1,32 @@ { lib , stdenvNoCC -, fetchurl +, fetchFromGitHub +, rename }: -# Metadata fetched from -# https://www.googleapis.com/webfonts/v1/webfonts?key=${GOOGLE_FONTS_TOKEN}&family=Noto+Emoji -let - metadata = with builtins; head (fromJSON (readFile ./noto-emoji.json)).items; - urlHashes = with builtins; fromJSON (readFile ./noto-emoji.hashes.json); -in stdenvNoCC.mkDerivation { pname = "noto-fonts-monochrome-emoji"; - version = "${lib.removePrefix "v" metadata.version}.${metadata.lastModified}"; - preferLocalBuild = true; + version = "3.000"; - dontUnpack = true; - srcs = - let - weightNames = { - "300" = "Light"; - regular = "Regular"; - "500" = "Medium"; - "600" = "SemiBold"; - "700" = "Bold"; - }; - in - lib.mapAttrsToList - (variant: url: fetchurl { - name = "NotoEmoji-${weightNames.${variant}}.ttf"; - hash = urlHashes.${url}; - inherit url; - }) - metadata.files; + src = fetchFromGitHub { + owner = "google"; + repo = "fonts"; + rev = "a73b9ab0a5df191bcfed817159a903911ea7958a"; + hash = "sha256-qVFU4uZius8oFPJCIL9ek2YdS3jru5mmTHp2L9RIXfg="; + sparseCheckout = [ "ofl/notoemoji" ]; + }; installPhase = '' runHook preInstall - for src in $srcs; do - install -D $src $out/share/fonts/noto/$(stripHash $src) - done + + install -m444 -Dt $out/share/fonts/noto ofl/notoemoji/*.ttf + ${rename}/bin/rename 's/\[.*\]//' $out/share/fonts/noto/* + runHook postInstall ''; + passthru.updateScript = ./update.sh; + meta = { description = "Monochrome emoji font"; homepage = "https://fonts.google.com/noto/specimen/Noto+Emoji"; diff --git a/pkgs/by-name/no/noto-fonts-monochrome-emoji/update.sh b/pkgs/by-name/no/noto-fonts-monochrome-emoji/update.sh new file mode 100755 index 000000000000..4141e68044f5 --- /dev/null +++ b/pkgs/by-name/no/noto-fonts-monochrome-emoji/update.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash -p common-updater-scripts git nix-prefetch + +tmpdir=$(mktemp -d) + +git -C "$tmpdir" init --initial-branch main +git -C "$tmpdir" config core.sparseCheckout true +git -C "$tmpdir" remote add origin https://github.com/google/fonts.git +echo "ofl/notoemoji/*" > "$tmpdir/.git/info/sparse-checkout" +git -C "$tmpdir" fetch origin main +git -C "$tmpdir" checkout main + +newrev=$(git -C "$tmpdir" rev-list -1 HEAD "ofl/notoemoji/*.ttf") +newver=$(grep 'archive:' "$tmpdir/ofl/notoemoji/upstream.yaml" | grep -oP '(?<=v)[0-9]+\.[0-9]+') +newhash=$(nix-prefetch "{ stdenv, fetchurl }: stdenv.mkDerivation rec { + name = \"noto-fonts-cjk-serif\"; + src = fetchFromGitHub { + owner = \"google\"; + repo = \"fonts\"; + rev = \"$newrev\"; + sparseCheckout = [ \"ofl/notoemoji\" ]; + }; +}") + +update-source-version noto-fonts-monochrome-emoji "$newver" "$newhash" --rev="$newrev"