1#!/usr/bin/env nix-shell
2#!nix-shell -i python -p nix 'python3.withPackages (pp: [ pp.requests ])'
3
4import json
5import os
6from pathlib import Path
7import sys
8import subprocess
9import requests
10
11USAGE = """Usage: {0} [ | plugin-name | plugin-file-path]
12
13eg.
14 {0}
15 {0} dprint-plugin-json
16 {0} /path/to/dprint-plugin-json.nix"""
17
18FILE_PATH = Path(os.path.realpath(__file__))
19SCRIPT_DIR = FILE_PATH.parent
20
21pname = ""
22if len(sys.argv) > 1:
23 if "-help" in "".join(sys.argv):
24 print(USAGE.format(FILE_PATH.name))
25 exit(0)
26 pname = sys.argv[1]
27else:
28 pname = os.environ.get("UPDATE_NIX_PNAME", "")
29
30
31# get sri hash for a url, no unpack
32def nix_prefetch_url(url, algo="sha256"):
33 hash = (
34 subprocess.check_output(["nix-prefetch-url", "--type", algo, url])
35 .decode("utf-8")
36 .rstrip()
37 )
38 sri = (
39 subprocess.check_output(
40 # split by space is enough for this command
41 "nix --extra-experimental-features nix-command "
42 f"hash convert --hash-algo {algo} --to sri {hash}".split(" ")
43 )
44 .decode("utf-8")
45 .rstrip()
46 )
47 return sri
48
49
50# json object to nix string
51def json_to_nix(jsondata):
52 # to quote strings, dumps twice does it
53 json_str = json.dumps(json.dumps(jsondata))
54 return (
55 subprocess.check_output(
56 "nix --extra-experimental-features nix-command eval "
57 f"--expr 'builtins.fromJSON ''{json_str}''' --impure | nixfmt",
58 shell=True,
59 )
60 .decode("utf-8")
61 .rstrip()
62 )
63
64
65# nix string to json object
66def nix_to_json(nixstr):
67 return json.loads(
68 subprocess.check_output(
69 f"nix --extra-experimental-features nix-command eval --json --expr '{nixstr}'",
70 shell=True,
71 )
72 .decode("utf-8")
73 .rstrip()
74 )
75
76
77# nixfmt a file
78def nixfmt(nixfile):
79 subprocess.run(["nixfmt", nixfile])
80
81
82def get_update_url(plugin_url):
83 """Get a single plugin's update url given the plugin's url"""
84
85 # remove -version.wasm at the end
86 url = "-".join(plugin_url.split("-")[:-1])
87 names = url.split("/")[3:]
88 # if single name then -> dprint/<name>
89 if len(names) == 1:
90 names.insert(0, "dprint")
91 return "https://plugins.dprint.dev/" + "/".join(names) + "/latest.json"
92
93
94def write_plugin_derivation(drv_attrs):
95 drv = f"{{ mkDprintPlugin }}: mkDprintPlugin {json_to_nix(drv_attrs)}"
96 filepath = SCRIPT_DIR / f"{drv_attrs["pname"]}.nix"
97 with open(filepath, "w+", encoding="utf8") as f:
98 f.write(drv)
99 nixfmt(filepath)
100
101
102def update_plugin_by_name(name):
103 """Update a single plugin by name"""
104
105 # allow passing in filename as well as pname
106 if name.endswith(".nix"):
107 name = Path(name[:-4]).name
108 try:
109 p = (SCRIPT_DIR / f"{name}.nix").read_text().replace("\n", "")
110 except OSError as e:
111 print(f"failed to update plugin {name}: error: {e}")
112 exit(1)
113
114 start_idx = p.find("mkDprintPlugin {") + len("mkDprintPlugin {")
115 p = nix_to_json("{" + p[start_idx:].strip())
116
117 data = requests.get(p["updateUrl"]).json()
118 p["url"] = data["url"]
119 p["version"] = data["version"]
120 p["hash"] = nix_prefetch_url(data["url"])
121
122 write_plugin_derivation(p)
123
124
125def update_plugins():
126 """Update all the plugins"""
127
128 data = requests.get("https://plugins.dprint.dev/info.json").json()["latest"]
129
130 for e in data:
131 update_url = get_update_url(e["url"])
132 pname = e["name"]
133 if "/" in e["name"]:
134 pname = pname.replace("/", "-")
135 drv_attrs = {
136 "url": e["url"],
137 "hash": nix_prefetch_url(e["url"]),
138 "updateUrl": update_url,
139 "pname": pname,
140 "version": e["version"],
141 "description": e["description"],
142 "initConfig": {
143 "configKey": e["configKey"],
144 "configExcludes": e["configExcludes"],
145 "fileExtensions": e["fileExtensions"],
146 },
147 }
148 write_plugin_derivation(drv_attrs)
149
150
151if pname != "":
152 update_plugin_by_name(pname)
153else:
154 update_plugins()