#!/usr/bin/env nu # Read-only download of every file in the interim's storage, for # `appview import-files` to file under the ids they already have: # # dump-interim-files.nu -> / ... + /manifest.json # appview import-files extraction.json # # It only reads: one GraphQL query for the list, then a GET per file. The admin # secret comes from the environment and is never written anywhere. Like the # snapshot dump, running it against live data is the owner's step; the committed # script is the reviewable artifact. # # Usage: # $env.HASURA_URL = "https://.hasura..nhost.run/v1/graphql" # $env.NHOST_STORAGE_URL = "https://.storage..nhost.run/v1" # $env.HASURA_ADMIN_SECRET = "" # never commit this # nu scripts/dump-interim-files.nu files # # A file already in at the size storage reports is not fetched again, so a # run that was cut short is simply run again. `import-files` checks each size # against the manifest, and refuses a file that came across short. # # One file at a time with a pause between (DUMP_PAUSE_MS, default 150): storage # shares one small project with everything else the interim runs on. def main [dir: path] { let hasura = ($env | get -o HASURA_URL | default "") let storage = ($env | get -o NHOST_STORAGE_URL | default "" | str trim --right --char "/") let secret = ($env | get -o HASURA_ADMIN_SECRET | default "") if ($hasura | is-empty) or ($storage | is-empty) or ($secret | is-empty) { print -e "set HASURA_URL, NHOST_STORAGE_URL and HASURA_ADMIN_SECRET (read-only; the secret is never committed)" exit 2 } let headers = {x-hasura-admin-secret: $secret} let query = "query { files(where: {isUploaded: {_eq: true}}) { id name mimeType size } }" let resp = (http post --content-type application/json --headers $headers $hasura ({query: $query} | to json)) if ($resp | get -o errors | is-not-empty) { print -e $"hasura error: ($resp.errors | to json)" exit 1 } let files = $resp.data.files mkdir $dir $files | to json | save --force ($dir | path join "manifest.json") let pause = ($env | get -o DUMP_PAUSE_MS | default "150" | into int | into duration --unit ms) mut fetched = 0 mut kept = 0 for file in $files { let target = ($dir | path join $file.id) if ($target | path exists) and ((ls $target | get 0.size | into int) == $file.size) { $kept += 1 continue } http get --raw --headers $headers $"($storage)/files/($file.id)" | save --force --raw $target $fetched += 1 if ($fetched mod 100) == 0 { print -e $" ($fetched) fetched" } sleep $pause } print -e $"($files | length) files in storage: ($fetched) fetched, ($kept) here already" }