mirror of
https://github.com/ruuda/rcl.git
synced 2025-10-07 15:40:49 +00:00

I want to publish a new version of the Zed plugin, and it points to the Tree-sitter grammar by commit. This is what got the whole "rcl patch" thing started! So now, upon export of the Zed extension, we'll pin it to the HEAD of the adjacent tree-sitter-rcl repository.
169 lines
4.7 KiB
Python
Executable file
169 lines
4.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
# RCL -- A reasonable configuration language.
|
|
# Copyright 2024 Ruud van Asseldonk
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# A copy of the License has been included in the root of the repository.
|
|
|
|
"""
|
|
Publish files tracked in the RCL (mono)repository into separate repositories.
|
|
|
|
Some tools -- in particular around Tree-sitter -- are repository-oriented and
|
|
expect some code that we rather track in subdirectories, to live in their own
|
|
repository. This script updates those external repositories to match the source
|
|
of truth in this repository.
|
|
|
|
USAGE
|
|
|
|
tools/update_repos.py [tree-sitter-rcl] [zed-rcl]
|
|
|
|
REPOSITORIES
|
|
|
|
We expect the following directories to exist relative to the repository root:
|
|
|
|
../tree-sitter-rcl
|
|
../zed-rcl
|
|
|
|
RATIONALE
|
|
|
|
Why export to an external repository rather than including those external
|
|
repositories as a Git submodule here?
|
|
|
|
* Git submodules currently do not work very nicely with Nix flakes, which
|
|
would make it harder to use the current Nix-based CI.
|
|
* Some consumers of Tree-sitter grammars prefer to have the generated files
|
|
be part of the repository, but in this repository we prefer to be minimal
|
|
and don't have large assets that are effectively opaque like binaries. In
|
|
an external repository, we can have both.
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import sys
|
|
import textwrap
|
|
import tomllib
|
|
|
|
from os import path
|
|
from subprocess import check_output, check_call
|
|
from typing import List
|
|
|
|
|
|
def get_rcl_version() -> str:
|
|
# TODO: Would be nice to load Cargo.rcl instead, with the RCL module.
|
|
with open("Cargo.toml", "rb") as f:
|
|
version: str = tomllib.load(f)["package"]["version"]
|
|
return version
|
|
|
|
|
|
def ignores_tree_sitter_rcl(dirname: str, _entries: List[str]) -> List[str]:
|
|
if dirname == "grammar/tree-sitter-rcl":
|
|
return [".gitignore", "Cargo.rcl"]
|
|
else:
|
|
return []
|
|
|
|
|
|
def ignores_zed(dirname: str, _entries: List[str]) -> List[str]:
|
|
if dirname == "grammar/zed":
|
|
return [".gitignore", "extension.rcl", "grammars"]
|
|
else:
|
|
return []
|
|
|
|
|
|
def git_head(repo_dir: str) -> str:
|
|
return check_output(
|
|
["git", "-C", repo_dir, "rev-parse", "HEAD"], encoding="ascii"
|
|
).strip()
|
|
|
|
|
|
def git_commit(repo_dir: str, message: str) -> None:
|
|
print(f"Creating commit in {repo_dir} ...")
|
|
git = ["git", "-C", repo_dir]
|
|
check_output([*git, "add", "."])
|
|
check_call([*git, "commit", "--message", message.strip()])
|
|
|
|
|
|
def get_message(src_dir: str) -> str:
|
|
rcl_version = get_rcl_version()
|
|
git_describe = check_output(["git", "describe", "--dirty"]).decode("utf-8").strip()
|
|
commit_hash = check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip()
|
|
return textwrap.dedent(
|
|
f"""
|
|
Update to RCL {rcl_version}
|
|
|
|
This is a generated export based on files in the {src_dir}
|
|
directory of the main RCL repository. It is generated by
|
|
tools/update_repos.py.
|
|
|
|
Upstream-Describe: {git_describe}
|
|
Upstream-Commit: {commit_hash}
|
|
"""
|
|
)
|
|
|
|
|
|
def update_zed_rcl() -> None:
|
|
assert path.isdir("../zed-rcl/.git")
|
|
|
|
src_dir = "grammar/zed"
|
|
dst_dir = "../zed-rcl"
|
|
|
|
# Before we export, update `extension.toml` to point to the correct Git commit.
|
|
ts_commit = git_head("../tree-sitter-rcl")
|
|
check_call(
|
|
[
|
|
"rcl",
|
|
"patch",
|
|
"--in-place",
|
|
"grammar/zed/extension.rcl",
|
|
"grammars.rcl.commit",
|
|
json.dumps(ts_commit),
|
|
]
|
|
)
|
|
check_call(["rcl", "build"])
|
|
|
|
# TODO: It would be nice to skip the index and just generate the right
|
|
# Git tree. This is possible with `git fast-import`, which is also what
|
|
# MkDocs uses under the hood. But let's not go there right now.
|
|
shutil.copytree(
|
|
src=src_dir,
|
|
dst=dst_dir,
|
|
ignore=ignores_zed,
|
|
dirs_exist_ok=True,
|
|
)
|
|
git_commit(dst_dir, get_message(src_dir))
|
|
|
|
|
|
def update_tree_sitter_rcl() -> None:
|
|
assert path.isdir("../tree-sitter-rcl/.git")
|
|
|
|
src_dir = "grammar/tree-sitter-rcl"
|
|
dst_dir = "../tree-sitter-rcl"
|
|
|
|
# Rebuild the Tree-sitter grammar to ensure that we don't copy anything
|
|
# stale.
|
|
check_output(["tree-sitter", "generate", "--build"], cwd=src_dir)
|
|
|
|
shutil.copytree(
|
|
src=src_dir,
|
|
dst=dst_dir,
|
|
ignore=ignores_tree_sitter_rcl,
|
|
dirs_exist_ok=True,
|
|
)
|
|
git_commit(dst_dir, get_message(src_dir))
|
|
|
|
|
|
def main() -> None:
|
|
repos = sys.argv[1:]
|
|
if repos == []:
|
|
repos = ["tree-sitter-rcl", "zed-rcl"]
|
|
|
|
if "tree-sitter-rcl" in repos:
|
|
update_tree_sitter_rcl()
|
|
|
|
if "zed-rcl" in repos:
|
|
update_zed_rcl()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|