Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package tree-sitter for openSUSE:Factory checked in at 2026-08-21 16:50:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tree-sitter (Old) and /work/SRC/openSUSE:Factory/.tree-sitter.new.1258 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tree-sitter" Fri Aug 21 16:50:19 2026 rev:28 rq:1372547 version:0.26.8 Changes: -------- --- /work/SRC/openSUSE:Factory/tree-sitter/tree-sitter.changes 2026-05-17 18:56:31.111553224 +0200 +++ /work/SRC/openSUSE:Factory/.tree-sitter.new.1258/tree-sitter.changes 2026-08-21 16:51:07.638284082 +0200 @@ -1,0 +2,50 @@ +Thu Aug 20 13:53:41 UTC 2026 - Martin Pluskal <[email protected]> + +- Do not emit treesitter_grammar_src() rpm symbols for relative + require() paths (., .., ./, ../). Local relative requires are + still followed to find nested external grammar deps. Fixes + installcheck on grammars that share a sibling common/ + directory (nothing provides treesitter_grammar_src(../common) + for tree-sitter-php-devel). + +------------------------------------------------------------------- +Thu Aug 20 08:46:22 UTC 2026 - Martin Pluskal <[email protected]> + +- Add an opt-in Python binding macro to the grammar framework. + Review follow-up: generate a Python loader instead of compiling + the upstream C binding, so the parser is not built a second time: + * %treesitter_python_install installs upstream's pure-Python + bindings/python package files as-is and replaces the compiled + _binding extension with a generated _binding.py that loads the + grammar library from %{_libdir}/tree-sitter via ctypes and + hands its TSLanguage pointer to python-tree-sitter as the + "tree_sitter.Language" PyCapsule the Language() constructor + expects - no duplicate parser, no compiler, no wheel + * New source tree-sitter-python-shim.py.in: the template the + generated _binding.py comes from, shipped in %{_rpmconfigdir} + so it is versioned and testable instead of inlined in a macro + * %treesitter_python_build is a deprecated no-op; consumers no + longer need the python devel/pip/wheel/setuptools/installer + BuildRequires + * The python subpackage pins the grammar package exactly + (Requires: %{name} = %{version}-%{release}); library and + binding come from the same source package and move in lockstep + * %treesitter_python_install also takes an explicit multi-language + form, MODNAME GRAMMAR..., for upstream modules that expose + several grammars from one python package: each grammar yields a + language_<grammar>() function loading its own library, matching + the upstream binding of tree-sitter-typescript + (language_typescript and language_tsx, no plain language) + * Consuming specs still carry the (now much smaller) singlespec + template literally: the python-rpm-macros generator re-reads + the raw spec text for the %package template, so an %include + fragment cannot provide it (the BuildRequires alone could move + to a fragment - the OBS scheduler does resolve %include - but + splitting one small block across two files is not worth it) + * Documented python subpackage dep is Suggests: + python-tree-sitter >= 0.22, not Requires -- python-tree-sitter + is not in Rings:1-MinimalX, so a hard Requires fails Staging + installcheck for ring1 grammars (matching tree-sitter-bash) + * No change for grammar packages that do not opt in + +------------------------------------------------------------------- New: ---- tree-sitter-python-shim.py.in ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tree-sitter.spec ++++++ --- /var/tmp/diff_new_pack.7s3l1c/_old 2026-08-21 16:51:10.296379544 +0200 +++ /var/tmp/diff_new_pack.7s3l1c/_new 2026-08-21 16:51:10.299379652 +0200 @@ -36,6 +36,7 @@ Source24: compile-macros.sh Source25: treesitter_grammar.attr Source26: treesitter_grammar.req +Source27: tree-sitter-python-shim.py.in BuildRequires: cargo-packaging BuildRequires: clang BuildRequires: fdupes @@ -110,6 +111,7 @@ install -Dm644 %{SOURCE25} %{buildroot}%{_fileattrsdir}/$(basename %{SOURCE25}) install -Dm755 %{SOURCE26} %{buildroot}%{_rpmconfigdir}/$(basename %{SOURCE26}) +install -Dm644 %{SOURCE27} %{buildroot}%{_rpmconfigdir}/$(basename %{SOURCE27}) #remove .a/.la files find %{buildroot} -type f \( -name "*.la" -o -name "*.a" \) -delete -print @@ -147,6 +149,7 @@ %{_rpmconfigdir}/%{name}-target.py %{_rpmmacrodir}/macros.treesitter %{_rpmconfigdir}/treesitter_grammar.req +%{_rpmconfigdir}/tree-sitter-python-shim.py.in %{_fileattrsdir}/treesitter_grammar.attr %dir %{_emacs_sitelispdir} %dir %{_emacs_sitestartdir} ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.7s3l1c/_old 2026-08-21 16:51:10.417383890 +0200 +++ /var/tmp/diff_new_pack.7s3l1c/_new 2026-08-21 16:51:10.424384141 +0200 @@ -1,6 +1,6 @@ -mtime: 1778866530 -commit: eb3df7e9d39c71d2c3d1614445eb1122df9567e6663bc2d64646f4566de80bb0 +mtime: 1787235978 +commit: 7b58a6ff7fe22f73f8388cd38d57f1aca71ab17a57f15f00a18d0e8f7add5a8d url: https://src.opensuse.org/tree-sitter/tree-sitter -revision: eb3df7e9d39c71d2c3d1614445eb1122df9567e6663bc2d64646f4566de80bb0 +revision: 7b58a6ff7fe22f73f8388cd38d57f1aca71ab17a57f15f00a18d0e8f7add5a8d projectscmsync: https://src.opensuse.org/tree-sitter/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-08-20 16:26:18.000000000 +0200 @@ -0,0 +1,5 @@ +*.obscpio +*.osc +_build.* +.pbuild +tree-sitter-*-build/ ++++++ macros.in ++++++ --- /var/tmp/diff_new_pack.7s3l1c/_old 2026-08-21 16:51:10.915401776 +0200 +++ /var/tmp/diff_new_pack.7s3l1c/_new 2026-08-21 16:51:10.918401883 +0200 @@ -19,6 +19,123 @@ %files -n %{__treesitter_devel_package_name} \ %{treesitter_devel_files} + +# --[[ +# Optional Python binding subpackage for grammars whose upstream ships +# bindings/python (the tree-sitter org grammars do). Ships the +# tree_sitter_<grammar> module for every python flavor (singlespec), for +# consumers like graphify that use the grammar from Python via +# python3-tree-sitter. +# +# No second copy of the parser is compiled: upstream's pure-Python +# package files (__init__.py, __init__.pyi, py.typed, queries) are +# installed as-is and the compiled _binding C extension is replaced by a +# generated _binding.py (from %%{_treesitter_python_shim_template}) that +# ctypes-loads the grammar library this same source package installs +# into %%{_treesitter_grammardir} and hands its TSLanguage pointer to +# python-tree-sitter as the "tree_sitter.Language" PyCapsule that the +# Language() constructor expects. No compiler, no wheel, no abi concerns. +# +# Usage -- the spec MUST carry the BuildRequires AND the singlespec +# subpackage template literally. Neither can come from a macro in this +# file: the OBS scheduler extracts BuildRequires without +# macros.treesitter installed, and the python-rpm-macros generator +# re-reads the raw spec text for the %%package template to clone per +# flavor. +# +# %%define python_subpackage_only 1 +# BuildRequires: fdupes +# BuildRequires: python-rpm-macros +# BuildRequires: %%{python_module base} +# # only for the functional test in %%check: +# BuildRequires: %%{python_module tree-sitter} +# +# %%treesitter_grammars %%{_name} +# %%python_subpackages +# +# %%package -n python-%%{name} +# Summary: Python binding for the %%{name} grammar +# Requires: %%{name} = %%{version}-%%{release} +# Suggests: python-tree-sitter >= 0.22 +# %%description -n python-%%{name} +# ... +# +# %%files %%{python_files %%{name}} +# %%license LICENSE +# %%{python_sitearch}/tree_sitter_* +# +# %%install +# %%treesitter_install +# %%treesitter_python_install +# +# The Requires on the grammar package is exact on purpose: the grammar +# library is unversioned and both halves come from the same source +# package, so library and binding always move in lockstep. +# +# python-tree-sitter is Suggests, not Requires: it is a separate +# package not in Rings:1-MinimalX, and several grammars live in +# ring1. A hard Requires fails Staging installcheck (nothing +# provides python*-tree-sitter). tree-sitter-bash already uses +# Suggests for the same reason. +# --]] + +# Template the generated _binding.py comes from; shipped by tree-sitter +# next to the other rpm helpers so it is versioned and testable on its own +# instead of being inlined (and %%-escaped) in a macro body. +%_treesitter_python_shim_template %{_rpmconfigdir}/tree-sitter-python-shim.py.in + +# Deprecated no-op: nothing is compiled for the python binding any more. +# Kept so in-flight grammar branches that still call it in %%build keep +# building; remove once those branches are refreshed. +%treesitter_python_build %{nil} + +# %%treesitter_python_install [grammarname] +# %%treesitter_python_install MODNAME GRAMMAR1 GRAMMAR2 ... +# Installs upstream's bindings/python/tree_sitter_<name> package for every +# python flavor, dropping binding.c and generating _binding.py from +# %%{_treesitter_python_shim_template}. +# +# Bare or single-argument form: the module tree_sitter_<grammarname> +# (default: the single grammar declared via %%treesitter_grammars) gets a +# plain language() function, matching upstream's single-language bindings. +# +# Multi-language form, for upstream modules that expose several grammars +# from one python package (no plain language()): pass the module name and +# then every grammar; each grammar Gi yields a language_<Gi>() function +# loading libtree-sitter-<Gi>.so. tree-sitter-typescript is the known case: +# %%treesitter_python_install typescript typescript tsx +# generates language_typescript() and language_tsx() in +# tree_sitter_typescript, matching its upstream binding exactly. +# CAUTION: in the multi form the module name does NOT count as a grammar -- +# when the module also exposes its namesake grammar, repeat it (as above). +# "%%treesitter_python_install typescript tsx" would generate ONLY +# language_tsx() and the module's own __init__ import would fail. +%treesitter_python_install() \ +tspy_args="%{?*}" \ +if test -z "${tspy_args}"; then \ + tspy_args="%{treesitter_grammar_names}" \ + if test $(echo ${tspy_args} | wc -w) -ne 1; then echo "error: package declares multiple grammars (${tspy_args}); call %%treesitter_python_install MODNAME GRAMMAR... explicitly (see macros.treesitter)" >&2; exit 1; fi \ +fi \ +set -- ${tspy_args} \ +tspy_grammar="$1" \ +tspy_mod="tree_sitter_$(echo "$1" | tr '-' '_')" \ +if ! test -d "bindings/python/${tspy_mod}"; then echo "error: bindings/python/${tspy_mod} not found -- upstream ships no python binding for $1" >&2; exit 1; fi \ +sed -e "s|@GRAMMAR@|${tspy_grammar}|g" %{_treesitter_python_shim_template} > _tspy_binding.py \ +# NB: no backslash-escaped quotes below -- rpm macro expansion strips the \ +# backslashes and collapses the shell quoting. Python string literals are \ +# single-quoted and docstrings triple-single-quoted so none are needed. \ +if test "$#" -eq 1; then \ + tspy_und=$(echo "${tspy_grammar}" | tr '-' '_') \ + { echo '' ; echo '' ; echo 'def language():' ; echo " '''Return the language capsule for tree_sitter.Language().'''" ; echo " return _language('%{_treesitter_grammardir}/%{_treesitter_grammar_base_libname}-${tspy_grammar}.so', 'tree_sitter_${tspy_und}')" ; } >> _tspy_binding.py \ +else \ + shift \ + for tspy_g in "$@"; do \ + tspy_g_und=$(echo "${tspy_g}" | tr '-' '_') \ + { echo '' ; echo '' ; echo "def language_${tspy_g_und}():" ; echo " '''Return the ${tspy_g} language capsule for tree_sitter.Language().'''" ; echo " return _language('%{_treesitter_grammardir}/%{_treesitter_grammar_base_libname}-${tspy_g}.so', 'tree_sitter_${tspy_g_und}')" ; } >> _tspy_binding.py \ + done \ +fi \ +%{python_expand install -d %{buildroot}%{$python_sitearch}/${tspy_mod} ; cp -pr bindings/python/${tspy_mod}/. %{buildroot}%{$python_sitearch}/${tspy_mod}/ ; rm -f %{buildroot}%{$python_sitearch}/${tspy_mod}/binding.c ; if test -d queries && ! test -d %{buildroot}%{$python_sitearch}/${tspy_mod}/queries; then install -d %{buildroot}%{$python_sitearch}/${tspy_mod}/queries ; install -m 0644 queries/*.scm %{buildroot}%{$python_sitearch}/${tspy_mod}/queries/ ; fi ; install -m 0644 _tspy_binding.py %{buildroot}%{$python_sitearch}/${tspy_mod}/_binding.py ; %fdupes %{buildroot}%{$python_sitearch}} + ### LUA-MACROS ### ++++++ tree-sitter-python-shim.py.in ++++++ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2026 SUSE LLC # # Header template for the pure-Python tree-sitter grammar binding generated # by %treesitter_python_install (see macros.treesitter). The grammar name # token in the docstring is substituted at package build time; the # per-language "def language...()" lines are appended below this header by # the macro, one per grammar library the module exposes. # # This file is generated into MIT-licensed grammar subpackages, so it is # MIT itself. # # Instead of compiling upstream's binding.c (which would link a second copy # of the parser), load the grammar library packaged by this same source # package and hand its TSLanguage pointer to python-tree-sitter as the # PyCapsule named "tree_sitter.Language" that Language() expects. """Binding for the @GRAMMAR@ tree-sitter grammar (openSUSE, ctypes-based).""" import ctypes # Module-level cache: the TSLanguage pointers handed out below point into # these mappings. The module stays referenced in sys.modules for the life # of the interpreter, so no library is ever dlclose()d while capsules # pointing into it exist. _libs = {} # ctypes defaults restype to c_int, which truncates pointers on 64-bit. # The explicit restypes below are load-bearing; do not remove them. _PyCapsule_New = ctypes.pythonapi.PyCapsule_New _PyCapsule_New.restype = ctypes.py_object _PyCapsule_New.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p) _CAPSULE_NAME = b"tree_sitter.Language" def _language(path, symbol): lib = _libs.get(path) if lib is None: lib = _libs[path] = ctypes.CDLL(path) fn = getattr(lib, symbol) fn.restype = ctypes.c_void_p fn.argtypes = () return _PyCapsule_New(fn(), _CAPSULE_NAME, None) ++++++ treesitter_grammar.req ++++++ --- /var/tmp/diff_new_pack.7s3l1c/_old 2026-08-21 16:51:11.030405906 +0200 +++ /var/tmp/diff_new_pack.7s3l1c/_new 2026-08-21 16:51:11.039406229 +0200 @@ -79,9 +79,8 @@ requiredLvl2.group(1).removeprefix("'").removesuffix("'") requiredLvl2_grp_cleaned = \ requiredLvl2_grp_cleaned.removeprefix("\"").removesuffix("\"") - if not requiredLvl2_grp_cleaned.split('/')[0] == "..": - # Don't emit dependencies which are local - pass + # Follow local relative requires to find nested + # external deps; emission is filtered below. dummyRequire(requiredLvl2_grp_cleaned, maxDepth - 1) except FileNotFoundError: pass @@ -89,8 +88,14 @@ if maxDepth == 5: # In case we immediately fail to open the first grammar source file return - # We only want to resolve dependencies outside of the package - print(f"{treeSitterGrammarSymbolToken}({Path(requiredFile_fd).parent})") + # We only want to resolve dependencies outside of the package. + # Never emit a relative-path rpm symbol (., .., ./..., ../...): + # those are local fragments, not grammar names. A token such as + # ../common produced treesitter_grammar_src(../common). + token = str(Path(requiredFile_fd).parent) + if token in (".", "..") or token.startswith("../") or token.startswith("./"): + return + print(f"{treeSitterGrammarSymbolToken}({token})") for line in fileinput.input(): line = line.rstrip('\n')
