1"""Brings the icons and their name map over from a clone of
2wolfsouldev/jerrys-pixel-icons.
3
4    nix shell nixpkgs#librsvg -c python3 third-party/jerrys-pixel-icons/update.py <clone>
5
6Each upstream icon is an SVG holding one PNG; the PNG is taken out as it
7is. The few drawn as paths are rendered at the same size. The theme's map
8(names, extensions, folders) is written as packages/tree/src/icons_theme.rs.
9"""
10import base64, glob, json, os, re, subprocess, sys
11
12src = sys.argv[1]
13out = os.path.dirname(os.path.abspath(__file__))
14root = os.path.join(out, "..", "..")
15commit = subprocess.run(["git", "-C", src, "log", "-1", "--format=%h %s"], capture_output=True, text=True, check=True).stdout.strip()
16
17have = set()
18for path in sorted(glob.glob(src + "/icons/*/*.svg")):
19    kind = "file" if "/files/" in path else "folder"
20    name = f"{kind}-{os.path.basename(path)[:-4]}"
21    held = re.search(r'href="data:image/png;base64,([^"]+)"', open(path).read())
22    dest = os.path.join(out, name + ".png")
23    if held:
24        open(dest, "wb").write(base64.b64decode(held.group(1)))
25    else:
26        subprocess.run(["rsvg-convert", "-w", "256", "-h", "256", path, "-o", dest], check=True)
27    have.add(name)

The theme is JSON with comments and trailing commas.

30text = open(src + "/themes/icon-theme.json").read()
31text = re.sub(r"^\s*//.*$", "", text, flags=re.M)
32theme = json.loads(re.sub(r",(\s*[}\]])", r"\1", text))
35def icon(defined):
36    path = theme["iconDefinitions"][defined]["iconPath"]
37    return f"{'file' if '/files/' in path else 'folder'}-{os.path.basename(path)[:-4]}"
38
39
40def table(name, entries, doc):
41    rows = sorted((key, icon(value)) for key, value in entries.items() if "*" not in key and value in theme["iconDefinitions"])
42    for _, value in rows:
43        assert value in have, value
44    body = "".join(f'    ("{key}", "{value}"),\n' for key, value in rows)
45    return f"/// {doc}\npub const {name}: &[(&str, &str)] = &[\n{body}];\n"
46
47
48rust = f"""//! Which of Jerry's pixel icons a name gets: the icon theme's own map
49//! (`themes/icon-theme.json` of wolfsouldev/jerrys-pixel-icons, at
50//! {commit}), read into tables. Generated by
51//! third-party/jerrys-pixel-icons/update.py; do not edit by hand. Entries
52//! with a wildcard are left out. Each icon is a file of that name, `.png`,
53//! in third-party/jerrys-pixel-icons.
54
55{table("EXTENSIONS", theme["fileExtensions"], "A file, by what follows its last dot.")}
56{table("NAMES", theme["fileNames"], "A file, by its whole name.")}
57{table("FOLDERS", theme["folderNames"], "A folder, by its name. Its open icon is the same name with `-open`.")}
58/// A file with no icon of its own, and a folder with none.
59pub const FILE: &str = "{icon(theme["file"])}";
60pub const FOLDER: &str = "{icon(theme["folder"])}";
61"""
62open(os.path.join(root, "packages/tree/src/icons_theme.rs"), "w").write(rust)
63subprocess.run(["cp", src + "/LICENSE", os.path.join(out, "LICENSE")], check=True)
64print(len(have), "icons, from", commit)