blog.grace.moe

Source for the blog blog.grace.moe
git clone https://git.grace.moe/blog.grace.moe
Log | Files | Refs

make.py (4129B)


      1 #!/usr/bin/env -S uv run
      2 from make3 import EchoAll, file_hash, make_main, once, shell
      3 import asyncio
      4 import json
      5 import os
      6 
      7 
      8 async def main():
      9     STORAGENAME = "blog-grace-moe"
     10     STORAGEPASSWORD = (
     11         await shell("secret-tool lookup owner blog-grace-moe.b-cdn.net")
     12     ).utf8stdout
     13 
     14     PULLZONEID = "3580820"
     15     APIPASSWORD = (await shell("secret-tool lookup owner grace@bunny.net")).utf8stdout
     16     LOCALPATH = "public"
     17 
     18     STORAGEURL = f"https://sg.storage.bunnycdn.com/{STORAGENAME}"
     19     STORAGECMD = f"curl -H 'AccessKey: {STORAGEPASSWORD}' -s"
     20     PURGEURL = f"https://api.bunny.net/pullzone/{PULLZONEID}/purgeCache"
     21     APICMD = f"curl -H 'AccessKey: {APIPASSWORD}' -s"
     22 
     23     @once()
     24     async def rebuild():
     25         await shell(
     26             """
     27             rm -rf public
     28             rm -rf layouts/*.raw.shtml
     29             for layout in layouts/*.shtml; do
     30                 tail -n+2 $layout > $layout.raw
     31             done
     32             rename .shtml.raw .raw.shtml layouts/*.shtml.raw
     33             zine release
     34             """,
     35             echo=EchoAll,
     36         )
     37 
     38     bunny_sem = asyncio.Semaphore(80)
     39 
     40     @once()
     41     async def contents(path: str):
     42         async with bunny_sem:
     43             print("+++ download", path)
     44             path_json = await shell(f"{STORAGECMD} '{STORAGEURL}/{path}/'")
     45             print("--- download", path)
     46             return json.loads(path_json.utf8stdout)
     47 
     48     @once()
     49     async def cleanfile(path: str):
     50         if not os.path.isfile(f"{LOCALPATH}/{path}"):
     51             async with bunny_sem:
     52                 print("+++ cleanfile", path)
     53                 await shell(f"{STORAGECMD} -XDELETE '{STORAGEURL}/{path}'")
     54                 print("--- cleanfile", path)
     55 
     56     @once()
     57     async def cleandir(path: str):
     58         if not os.path.isdir(f"{LOCALPATH}/{path}"):
     59             async with bunny_sem:
     60                 print("+++ cleandir", path)
     61                 await shell(f"{STORAGECMD} -XDELETE '{STORAGEURL}/{path}/'")
     62                 print("--- cleandir", path)
     63 
     64     @once()
     65     async def clean(path: str):
     66         path_contents = await contents(path)
     67         await asyncio.gather(
     68             *(
     69                 (
     70                     (cleandir(path + "/" + ent["ObjectName"]))
     71                     if ent["IsDirectory"]
     72                     else (cleanfile(path + "/" + ent["ObjectName"]))
     73                 )
     74                 for ent in path_contents
     75                 if isinstance(ent, dict)
     76             )
     77         )
     78         # print("- clean", path)
     79 
     80     @once()
     81     async def upload(path: str):
     82         path_contents = await contents(path[: path.rfind("/")])
     83 
     84         bunny_checksum = None
     85         if isinstance(path_contents, list):
     86             try:
     87                 bunny_checksum = next(
     88                     (
     89                         ent["Checksum"]
     90                         for ent in path_contents
     91                         if ent["ObjectName"] == path[path.rfind("/") + 1 :]
     92                     )
     93                 )
     94             except StopIteration:
     95                 pass
     96 
     97         our_checksum = (await file_hash(f"{LOCALPATH}/{path}")).upper()
     98 
     99         if bunny_checksum != our_checksum:
    100             async with bunny_sem:
    101                 print("+++ uploading", path)
    102                 await shell(
    103                     f"{STORAGECMD} -T'{LOCALPATH}/{path}' '{STORAGEURL}/{path}'"
    104                 )
    105                 print("--- uploading", path)
    106         # print("- upload", path)
    107 
    108     @once()
    109     async def purge():
    110         async with bunny_sem:
    111             print("+++ purge")
    112             await shell(f"{APICMD} -XPOST '{PURGEURL}'")
    113             print("--- purge")
    114 
    115     @once()
    116     async def all():
    117         await rebuild()
    118         UPLOAD = (await shell(f"cd '{LOCALPATH}' && find . -type f")).utf8stdout
    119         CLEAN = (await shell(f"cd '{LOCALPATH}' && find . -type d")).utf8stdout
    120         await asyncio.gather(
    121             *((upload(path)) for path in UPLOAD.strip().split("\n")),
    122             *((clean(path)) for path in CLEAN.strip().split("\n")),
    123         )
    124         await purge()
    125 
    126     _ = all
    127     return await make_main(locals())
    128 
    129 
    130 if __name__ == "__main__":
    131     exit(asyncio.run(main()))