Files
larksuite-cli/scripts/fetch_meta.py
shanglei 2098c3c412 perf(registry): drop embedded meta_data.json and the larkmeta build tag
The startup baseline now comes solely from the generated static Go registry
(metastatic.Registry), wired into the stub-declared Registry via a package-level
var plus an init() struct-header copy. No build tag, no committed generated
file, and zero startup allocation is preserved.

- gen.go emits a tag-free `var registryData` + `func init()` instead of a
  //go:build larkmeta top-level `var Registry`; stub.go declares Registry
  unconditionally so the package always compiles
- fetch_meta.py regenerates the static registry after fetching, so every build
  and CI step that fetches also produces it (no separate gen step, no CI change)
- remove the //go:embed meta_data.json baseline and the JSON parse fallback;
  meta_data.json is now only the build-time input to the generator
- EmbeddedSpec/EmbeddedServiceNames read the static baseline; drop the schema
  key-order machinery so envelope field order is alphabetical (JSON Schema
  property order is not semantic; parameterOrder for positional args is intact)
- drop -tags larkmeta from Makefile, .goreleaser.yml, and build-pkg-pr-new.sh

Command tree is byte-identical (8092 lines). registry/schema/cmd unit tests,
the zero-alloc bench, and the e2e dry-run suite all pass.
2026-06-09 18:36:58 +08:00

114 lines
3.7 KiB
Python

#!/usr/bin/env python3
# Copyright (c) 2026 Lark Technologies Pte. Ltd.
# SPDX-License-Identifier: MIT
"""Fetch meta_data.json from remote API for build-time embedding.
Usage:
python3 scripts/fetch_meta.py # fetch from feishu (default)
python3 scripts/fetch_meta.py --brand lark # fetch from larksuite
"""
import argparse
import json
import os
import subprocess
import sys
import urllib.request
import urllib.error
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.join(SCRIPT_DIR, "..")
OUT_PATH = os.path.join(ROOT, "internal", "registry", "meta_data.json")
API_HOSTS = {
"feishu": "https://open.feishu.cn/api/tools/open/api_definition",
"lark": "https://open.larksuite.com/api/tools/open/api_definition",
}
TIMEOUT = 10 # seconds
def get_version():
"""Get version from git tags, matching Makefile logic."""
try:
return subprocess.check_output(
["git", "describe", "--tags", "--always", "--dirty"],
stderr=subprocess.DEVNULL,
text=True,
cwd=ROOT,
).strip()
except Exception:
return "dev"
def fetch_remote(brand):
"""Fetch MergedRegistry from remote API."""
base = API_HOSTS.get(brand, API_HOSTS["feishu"])
version = get_version()
url = f"{base}?protocol=meta&client_version={urllib.request.quote(version)}"
print(f"fetch-meta: GET {url}", file=sys.stderr)
req = urllib.request.Request(url)
resp = urllib.request.urlopen(req, timeout=TIMEOUT)
body = resp.read()
envelope = json.loads(body)
if envelope.get("msg") != "succeeded":
raise RuntimeError(f"unexpected response msg: {envelope.get('msg')!r}")
data = envelope.get("data", {})
if not data.get("services"):
raise RuntimeError("remote returned empty services")
return data
def run_gen():
"""Regenerate the static Go registry (metastatic/meta_data_gen.go) from
meta_data.json. Run after every fetch so any caller that fetches also
produces the sole build-time source of the embedded command tree — no build
tag, no JSON embedded in the binary. Output is gitignored."""
print("fetch-meta: generating static Go registry (metastatic/meta_data_gen.go)", file=sys.stderr)
subprocess.run(
["go", "run", "internal/registry/metastatic/gen.go"],
cwd=ROOT,
check=True,
)
def main():
parser = argparse.ArgumentParser(description="Fetch meta_data.json for build-time embedding")
parser.add_argument("--brand", default="feishu", choices=["feishu", "lark"],
help="API brand (default: feishu)")
parser.add_argument("--force", action="store_true",
help="force refresh from remote even if local file exists")
args = parser.parse_args()
have_valid = False
if os.path.isfile(OUT_PATH) and not args.force:
try:
with open(OUT_PATH, "r", encoding="utf-8") as fp:
local = json.load(fp)
have_valid = bool(local.get("services"))
except (OSError, json.JSONDecodeError):
have_valid = False
if have_valid:
print(f"fetch-meta: {OUT_PATH} already exists, skipping fetch (use --force to re-fetch)", file=sys.stderr)
else:
data = fetch_remote(args.brand)
count = len(data.get("services", []))
print(f"fetch-meta: OK, {count} services from remote API", file=sys.stderr)
with open(OUT_PATH, "w") as fp:
json.dump(data, fp, ensure_ascii=False, indent=2)
fp.write("\n")
# Always (re)generate the static Go registry so every fetch also produces
# the embedded command tree — the build-time replacement for the old
# embedded meta_data.json.
run_gen()
if __name__ == "__main__":
main()