appleFonts.base: Let's try using an IPSW

This commit is contained in:
Artemis Tosini 2023-12-20 23:20:02 +00:00
parent 0fa9c60778
commit 7e34876a71
Signed by: artemist
GPG key ID: EE5227935FE3FF18
5 changed files with 148 additions and 49 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
{ lib, fetchurl, stdenvNoCC, unzip }: { lib, fetchurl, stdenvNoCC, unzip, ipsw, _7zz }:
let let
root = lib.importJSON ./assets.json; root = lib.importJSON ./assets.json;
@ -23,9 +23,11 @@ let
done done
''; '';
passthru.font = true;
meta = with lib; { meta = with lib; {
license = licenses.unfree; license = licenses.unfree;
platforms = platforms.all; platforms = platforms.all;
maintainer = with maintainers; [ artemist ];
description = "${family} fonts as downloadable from macOS"; description = "${family} fonts as downloadable from macOS";
}; };
}; };
@ -33,4 +35,27 @@ let
in { in {
extra = lib.mapAttrs' mkExtraFont root.extra; extra = lib.mapAttrs' mkExtraFont root.extra;
allExtra = (mkExtraFont "All Extra" root.all_extra).value; allExtra = (mkExtraFont "All Extra" root.all_extra).value;
base = let data = root.base;
in stdenvNoCC.mkDerivation {
pname = "macos-fonts-base";
version = with data; "${version}-${build}";
src = fetchurl { inherit (data) url hash; };
installPhase = ''
${ipsw}/bin/ipsw extract $src --dmg fs
${_7zz}/bin/7zz e -i'!4.apfs' ${data.build}*/*.dmg
mkdir -p $out/share/fonts/apple
# This gives us some erros, ignore that
# Skipping overwrite because Apple has duplicate fonts for some reason
${_7zz}/bin/7zz e -i'!System/Library/Fonts' \
-i'!System/Library/PrivateFrameworks/FontServices.framework/Versions/A/Resources/Fonts/ApplicationSupport' \
4.apfs -aos -o$out/share/fonts/apple
'';
dontUnpack = true;
};
} }

View file

@ -5,54 +5,97 @@ import base64
import json import json
import plistlib import plistlib
import requests import requests
import re
from typing import Dict, Any, List from typing import Dict, Any, List
assets = plistlib.loads(
requests.get(
"https://mesu.apple.com/assets/com_apple_MobileAsset_Font7/com_apple_MobileAsset_Font7.xml"
).content
)["Assets"]
families: Dict[str, Any] = dict() def update_macos_extra():
all_assets: List[Dict[str, str]] = [] assets = plistlib.loads(
for asset in assets: requests.get(
# Period used for extra PUA font "https://mesu.apple.com/assets/com_apple_MobileAsset_Font7/com_apple_MobileAsset_Font7.xml"
names = set( ).content
[ )["Assets"]
info["FontFamilyName"]
for info in asset["FontInfo4"]
if not info["FontFamilyName"].startswith(".")
]
)
name = names.pop()
# There seems to be some support for things other than SHA-1 but I haven't seen it families: Dict[str, Any] = dict()
hsh = "sha1-" + base64.b64encode(asset["_Measurement"]).decode("utf-8") all_assets: List[Dict[str, str]] = []
url = asset["__BaseURL"] + asset["__RelativePath"] for asset in assets:
asset_obj = { # Period used for extra PUA font
"url": url, names = set(
"hash": hsh, [
info["FontFamilyName"]
for info in asset["FontInfo4"]
if not info["FontFamilyName"].startswith(".")
]
)
name = names.pop()
# There seems to be some support for things other than SHA-1 but I haven't seen it
hsh = "sha1-" + base64.b64encode(asset["_Measurement"]).decode("utf-8")
url = asset["__BaseURL"] + asset["__RelativePath"]
asset_obj = {
"url": url,
"hash": hsh,
}
all_assets.append(asset_obj)
version = asset["_CompatibilityVersion"]
if len(names) > 1:
print("Multiple family names found in asset:", ", ".join(names))
if name in families:
other_version = families[name]["version"]
if version == other_version:
families[name]["assets"].append(asset_obj)
continue
elif int(version) < int(other_version):
print(f"Duplicate asset found for family {name}, skipping")
continue
families[name] = {
"assets": [asset_obj],
"version": version,
}
return {"extra": families, "all_extra": {"assets": all_assets, "version": "mixed"}}
def update_macos_ipsw():
ipsws = plistlib.loads(
requests.get(
"https://mesu.apple.com/assets/macos/com_apple_macOSIPSW/com_apple_macOSIPSW.xml"
).content
)["MobileDeviceSoftwareVersionsByVersion"]["1"]["MobileDeviceSoftwareVersions"]
# Apple seems to be naming everything Mac now, use the newest one
# As of writing everything is UniversalMac but do this anyway
pattern = re.compile(r"Mac(\d+),(\d+)")
max_ident = (0, 0)
for ident in ipsws.keys():
if match := pattern.fullmatch(ident):
major, minor = match.groups()
major, minor = int(major), int(minor)
if major > max_ident[0] or major == max_ident[0] and minor > max_ident[1]:
max_ident = major, minor
ident = f"Mac{max_ident[0]},{max_ident[1]}"
# Unknown has an extra level we don't want, ignore it
build = max(ipsws[ident].keys(), key=lambda item: "" if item == "Unknown" else item)
ipsw = ipsws[ident][build]["Restore"]
version = ipsw["ProductVersion"]
print(f"Using ipsw from macOS {version} (build {build})")
return {
"base": {
"url": ipsw["FirmwareURL"],
"hash": "sha1-"
+ base64.b64encode(
base64.b16decode(ipsw["FirmwareSHA1"], casefold=True)
).decode("utf-8"),
"version": version,
"build": build,
}
} }
all_assets.append(asset_obj)
version = asset["_CompatibilityVersion"]
if len(names) > 1:
print("Multiple family names found in asset:", ", ".join(names))
if name in families:
other_version = families[name]["version"]
if version == other_version:
families[name]["assets"].append(asset_obj)
continue
elif int(version) < int(other_version):
print(f"Duplicate asset found for family {name}, skipping")
continue
families[name] = {
"assets": [asset_obj],
"version": version,
}
with open("assets.json", "w") as f: with open("assets.json", "w") as f:
json.dump( json.dump(update_macos_ipsw() | update_macos_extra(), f)
{"extra": families, "all_extra": {"assets": all_assets, "version": "mixed"}}, f
)

View file

@ -1,5 +1,28 @@
{ {
"nodes": { "nodes": {
"artemist": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"utils": [
"flake-utils"
]
},
"locked": {
"lastModified": 1702966889,
"narHash": "sha256-+vRUp3CoGyEya2JhhjxxM7JuVynsET7cbloYOlpZDOo=",
"ref": "refs/heads/canon",
"rev": "195c2e4d1c70f6e9b36f134097beddeedd2dd8d0",
"revCount": 18,
"type": "git",
"url": "https://git.mildlyfunctional.gay/artemist/packages.git"
},
"original": {
"type": "git",
"url": "https://git.mildlyfunctional.gay/artemist/packages.git"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@ -35,6 +58,7 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"artemist": "artemist",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }

View file

@ -3,9 +3,14 @@
inputs = { inputs = {
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:nixos/nixpkgs"; nixpkgs.url = "github:nixos/nixpkgs";
artemist = {
url = "git+https://git.mildlyfunctional.gay/artemist/packages.git";
inputs.utils.follows = "flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = { self, nixpkgs, flake-utils, }: outputs = { self, nixpkgs, flake-utils, artemist }:
with nixpkgs.lib; with nixpkgs.lib;
{ {
overlays.default = (final: prev: overlays.default = (final: prev:
@ -118,7 +123,7 @@
meta = { meta = {
inherit license; inherit license;
platforms = platforms.all; platforms = platforms.all;
maintainers = with maintainers; [ artemist ]; maintainers = [ maintainers.artemist ];
description = "${name} font by ${author}"; description = "${name} font by ${author}";
}; };
}; };
@ -127,13 +132,15 @@
name = replaceStrings [ " " ] [ "-" ] (toLower font.name); name = replaceStrings [ " " ] [ "-" ] (toLower font.name);
value = buildLocalFont font; value = buildLocalFont font;
}) localFonts); }) localFonts);
appleFonts = final.callPackage ./apple { }; appleFonts = final.callPackage ./apple {
ipsw = if final ? ipsw then final.ipsw else artemist.packages.${final.stdenv.system}.ipsw;
};
}); });
} // flake-utils.lib.eachDefaultSystem (system: } // flake-utils.lib.eachDefaultSystem (system:
let let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ self.overlays.default ]; overlays = [ self.overlays.default artemist.overlays.default ];
config.allowUnfree = true; config.allowUnfree = true;
}; };
in { in {